summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-09-05 13:14:37 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-09-05 13:14:37 +0000
commitfd3b2704efc2b206784615c1a23eb25501842259 (patch)
tree61ba3a8af2a0ae2ac9ec362bbf18b038f5dc0448 /src
parentInitial commit. (diff)
downloadflac-fd3b2704efc2b206784615c1a23eb25501842259.tar.xz
flac-fd3b2704efc2b206784615c1a23eb25501842259.zip
Adding upstream version 1.4.3+ds.upstream/1.4.3+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--src/CMakeLists.txt36
-rw-r--r--src/Makefile.am40
-rw-r--r--src/Makefile.in694
-rw-r--r--src/flac/CMakeLists.txt25
-rw-r--r--src/flac/Makefile.am69
-rw-r--r--src/flac/Makefile.in782
-rw-r--r--src/flac/analyze.c252
-rw-r--r--src/flac/analyze.h32
-rw-r--r--src/flac/decode.c1674
-rw-r--r--src/flac/decode.h73
-rw-r--r--src/flac/encode.c2852
-rw-r--r--src/flac/encode.h116
-rw-r--r--src/flac/foreign_metadata.c952
-rw-r--r--src/flac/foreign_metadata.h83
-rw-r--r--src/flac/iffscan.c129
-rw-r--r--src/flac/local_string_utils.c109
-rw-r--r--src/flac/local_string_utils.h28
-rw-r--r--src/flac/main.c2442
-rw-r--r--src/flac/utils.c439
-rw-r--r--src/flac/utils.h77
-rw-r--r--src/flac/version.rc38
-rw-r--r--src/flac/vorbiscomment.c254
-rw-r--r--src/flac/vorbiscomment.h27
-rw-r--r--src/libFLAC++/CMakeLists.txt41
-rw-r--r--src/libFLAC++/Makefile.am68
-rw-r--r--src/libFLAC++/Makefile.in831
-rw-r--r--src/libFLAC++/flac++.pc.in11
-rw-r--r--src/libFLAC++/libFLAC++.m4114
-rw-r--r--src/libFLAC++/metadata.cpp1745
-rw-r--r--src/libFLAC++/stream_decoder.cpp394
-rw-r--r--src/libFLAC++/stream_encoder.cpp519
-rw-r--r--src/libFLAC++/version.rc40
-rw-r--r--src/libFLAC/CMakeLists.txt126
-rw-r--r--src/libFLAC/Makefile.am123
-rw-r--r--src/libFLAC/Makefile.in1157
-rw-r--r--src/libFLAC/bitmath.c73
-rw-r--r--src/libFLAC/bitreader.c1052
-rw-r--r--src/libFLAC/bitwriter.c955
-rw-r--r--src/libFLAC/cpu.c255
-rw-r--r--src/libFLAC/crc.c436
-rw-r--r--src/libFLAC/deduplication/bitreader_read_rice_signed_block.c143
-rw-r--r--src/libFLAC/deduplication/lpc_compute_autocorrelation_intrin.c14
-rw-r--r--src/libFLAC/deduplication/lpc_compute_autocorrelation_intrin_neon.c70
-rw-r--r--src/libFLAC/deduplication/lpc_compute_autocorrelation_intrin_sse2.c81
-rw-r--r--src/libFLAC/fixed.c667
-rw-r--r--src/libFLAC/fixed_intrin_avx2.c343
-rw-r--r--src/libFLAC/fixed_intrin_sse2.c194
-rw-r--r--src/libFLAC/fixed_intrin_sse42.c223
-rw-r--r--src/libFLAC/fixed_intrin_ssse3.c179
-rw-r--r--src/libFLAC/flac.pc.in12
-rw-r--r--src/libFLAC/float.c302
-rw-r--r--src/libFLAC/format.c608
-rw-r--r--src/libFLAC/include/Makefile.am32
-rw-r--r--src/libFLAC/include/Makefile.in689
-rw-r--r--src/libFLAC/include/private/Makefile.am53
-rw-r--r--src/libFLAC/include/private/Makefile.in599
-rw-r--r--src/libFLAC/include/private/all.h50
-rw-r--r--src/libFLAC/include/private/bitmath.h210
-rw-r--r--src/libFLAC/include/private/bitreader.h101
-rw-r--r--src/libFLAC/include/private/bitwriter.h104
-rw-r--r--src/libFLAC/include/private/cpu.h198
-rw-r--r--src/libFLAC/include/private/crc.h60
-rw-r--r--src/libFLAC/include/private/fixed.h117
-rw-r--r--src/libFLAC/include/private/float.h95
-rw-r--r--src/libFLAC/include/private/format.h47
-rw-r--r--src/libFLAC/include/private/lpc.h238
-rw-r--r--src/libFLAC/include/private/macros.h74
-rw-r--r--src/libFLAC/include/private/md5.h50
-rw-r--r--src/libFLAC/include/private/memory.h58
-rw-r--r--src/libFLAC/include/private/metadata.h46
-rw-r--r--src/libFLAC/include/private/ogg_decoder_aspect.h80
-rw-r--r--src/libFLAC/include/private/ogg_encoder_aspect.h63
-rw-r--r--src/libFLAC/include/private/ogg_helper.h44
-rw-r--r--src/libFLAC/include/private/ogg_mapping.h64
-rw-r--r--src/libFLAC/include/private/stream_encoder.h67
-rw-r--r--src/libFLAC/include/private/stream_encoder_framing.h46
-rw-r--r--src/libFLAC/include/private/window.h74
-rw-r--r--src/libFLAC/include/protected/Makefile.am35
-rw-r--r--src/libFLAC/include/protected/Makefile.in581
-rw-r--r--src/libFLAC/include/protected/all.h39
-rw-r--r--src/libFLAC/include/protected/stream_decoder.h60
-rw-r--r--src/libFLAC/include/protected/stream_encoder.h124
-rw-r--r--src/libFLAC/libFLAC.m4114
-rw-r--r--src/libFLAC/lpc.c1629
-rw-r--r--src/libFLAC/lpc_intrin_avx2.c1122
-rw-r--r--src/libFLAC/lpc_intrin_fma.c73
-rw-r--r--src/libFLAC/lpc_intrin_neon.c1273
-rw-r--r--src/libFLAC/lpc_intrin_sse2.c966
-rw-r--r--src/libFLAC/lpc_intrin_sse41.c950
-rw-r--r--src/libFLAC/md5.c517
-rw-r--r--src/libFLAC/memory.c219
-rw-r--r--src/libFLAC/metadata_iterators.c3554
-rw-r--r--src/libFLAC/metadata_object.c2018
-rw-r--r--src/libFLAC/ogg_decoder_aspect.c251
-rw-r--r--src/libFLAC/ogg_encoder_aspect.c228
-rw-r--r--src/libFLAC/ogg_helper.c210
-rw-r--r--src/libFLAC/ogg_mapping.c48
-rw-r--r--src/libFLAC/stream_decoder.c3731
-rw-r--r--src/libFLAC/stream_encoder.c4738
-rw-r--r--src/libFLAC/stream_encoder_framing.c594
-rw-r--r--src/libFLAC/stream_encoder_intrin_avx2.c146
-rw-r--r--src/libFLAC/stream_encoder_intrin_sse2.c159
-rw-r--r--src/libFLAC/stream_encoder_intrin_ssse3.c148
-rw-r--r--src/libFLAC/version.rc40
-rw-r--r--src/libFLAC/window.c308
-rw-r--r--src/metaflac/CMakeLists.txt18
-rw-r--r--src/metaflac/Makefile.am65
-rw-r--r--src/metaflac/Makefile.in789
-rw-r--r--src/metaflac/main.c75
-rw-r--r--src/metaflac/operations.c823
-rw-r--r--src/metaflac/operations.h27
-rw-r--r--src/metaflac/operations_shorthand.h26
-rw-r--r--src/metaflac/operations_shorthand_cuesheet.c226
-rw-r--r--src/metaflac/operations_shorthand_picture.c184
-rw-r--r--src/metaflac/operations_shorthand_seektable.c220
-rw-r--r--src/metaflac/operations_shorthand_streaminfo.c127
-rw-r--r--src/metaflac/operations_shorthand_vorbiscomment.c430
-rw-r--r--src/metaflac/options.c1146
-rw-r--r--src/metaflac/options.h221
-rw-r--r--src/metaflac/usage.c349
-rw-r--r--src/metaflac/usage.h26
-rw-r--r--src/metaflac/utils.c282
-rw-r--r--src/metaflac/utils.h47
-rw-r--r--src/metaflac/version.rc38
-rw-r--r--src/share/Makefile.am73
-rw-r--r--src/share/Makefile.in905
-rw-r--r--src/share/README5
-rw-r--r--src/share/getopt/CMakeLists.txt13
-rw-r--r--src/share/getopt/getopt.c1053
-rw-r--r--src/share/getopt/getopt1.c189
-rw-r--r--src/share/grabbag/CMakeLists.txt14
-rw-r--r--src/share/grabbag/alloc.c48
-rw-r--r--src/share/grabbag/cuesheet.c681
-rw-r--r--src/share/grabbag/file.c207
-rw-r--r--src/share/grabbag/picture.c515
-rw-r--r--src/share/grabbag/replaygain.c669
-rw-r--r--src/share/grabbag/seektable.c105
-rw-r--r--src/share/grabbag/snprintf.c101
-rw-r--r--src/share/replaygain_analysis/CMakeLists.txt2
-rw-r--r--src/share/replaygain_analysis/replaygain_analysis.c575
-rw-r--r--src/share/replaygain_synthesis/CMakeLists.txt2
-rw-r--r--src/share/replaygain_synthesis/replaygain_synthesis.c429
-rw-r--r--src/share/utf8/CMakeLists.txt8
-rw-r--r--src/share/utf8/charmaps.h57
-rw-r--r--src/share/utf8/charset.c534
-rw-r--r--src/share/utf8/charset.h72
-rw-r--r--src/share/utf8/charset_test.c263
-rw-r--r--src/share/utf8/iconvert.c257
-rw-r--r--src/share/utf8/iconvert.h49
-rw-r--r--src/share/utf8/makemap.c81
-rw-r--r--src/share/utf8/utf8.c202
-rw-r--r--src/share/win_utf8_io/win_utf8_io.c398
-rw-r--r--src/test_grabbag/CMakeLists.txt2
-rw-r--r--src/test_grabbag/Makefile.am22
-rw-r--r--src/test_grabbag/Makefile.in679
-rw-r--r--src/test_grabbag/cuesheet/CMakeLists.txt5
-rw-r--r--src/test_grabbag/cuesheet/Makefile.am37
-rw-r--r--src/test_grabbag/cuesheet/Makefile.in669
-rw-r--r--src/test_grabbag/cuesheet/main.c147
-rw-r--r--src/test_grabbag/picture/CMakeLists.txt5
-rw-r--r--src/test_grabbag/picture/Makefile.am37
-rw-r--r--src/test_grabbag/picture/Makefile.in669
-rw-r--r--src/test_grabbag/picture/main.c222
-rw-r--r--src/test_libFLAC++/CMakeLists.txt10
-rw-r--r--src/test_libFLAC++/Makefile.am50
-rw-r--r--src/test_libFLAC++/Makefile.in720
-rw-r--r--src/test_libFLAC++/decoders.cpp1179
-rw-r--r--src/test_libFLAC++/decoders.h25
-rw-r--r--src/test_libFLAC++/encoders.cpp576
-rw-r--r--src/test_libFLAC++/encoders.h25
-rw-r--r--src/test_libFLAC++/main.cpp42
-rw-r--r--src/test_libFLAC++/metadata.cpp41
-rw-r--r--src/test_libFLAC++/metadata.h25
-rw-r--r--src/test_libFLAC++/metadata_manip.cpp2241
-rw-r--r--src/test_libFLAC++/metadata_object.cpp2099
-rw-r--r--src/test_libFLAC/CMakeLists.txt25
-rw-r--r--src/test_libFLAC/Makefile.am63
-rw-r--r--src/test_libFLAC/Makefile.in736
-rw-r--r--src/test_libFLAC/bitreader.c355
-rw-r--r--src/test_libFLAC/bitreader.h27
-rw-r--r--src/test_libFLAC/bitwriter.c688
-rw-r--r--src/test_libFLAC/bitwriter.h27
-rw-r--r--src/test_libFLAC/crc.c274
-rw-r--r--src/test_libFLAC/crc.h26
-rw-r--r--src/test_libFLAC/decoders.c1054
-rw-r--r--src/test_libFLAC/decoders.h27
-rw-r--r--src/test_libFLAC/encoders.c530
-rw-r--r--src/test_libFLAC/encoders.h27
-rw-r--r--src/test_libFLAC/endswap.c111
-rw-r--r--src/test_libFLAC/endswap.h26
-rw-r--r--src/test_libFLAC/format.c260
-rw-r--r--src/test_libFLAC/format.h27
-rw-r--r--src/test_libFLAC/main.c64
-rw-r--r--src/test_libFLAC/md5.c221
-rw-r--r--src/test_libFLAC/md5.h26
-rw-r--r--src/test_libFLAC/metadata.c41
-rw-r--r--src/test_libFLAC/metadata.h29
-rw-r--r--src/test_libFLAC/metadata_manip.c2146
-rw-r--r--src/test_libFLAC/metadata_object.c2291
-rw-r--r--src/test_libs_common/CMakeLists.txt4
-rw-r--r--src/test_libs_common/Makefile.am29
-rw-r--r--src/test_libs_common/Makefile.in666
-rw-r--r--src/test_libs_common/README2
-rw-r--r--src/test_libs_common/file_utils_flac.c155
-rw-r--r--src/test_libs_common/metadata_utils.c636
-rw-r--r--src/test_seeking/CMakeLists.txt5
-rw-r--r--src/test_seeking/Makefile.am39
-rw-r--r--src/test_seeking/Makefile.in666
-rw-r--r--src/test_seeking/main.c473
-rw-r--r--src/test_streams/CMakeLists.txt2
-rw-r--r--src/test_streams/Makefile.am29
-rw-r--r--src/test_streams/Makefile.in661
-rw-r--r--src/test_streams/main.c1398
-rw-r--r--src/utils/Makefile.am19
-rw-r--r--src/utils/Makefile.in676
-rw-r--r--src/utils/flacdiff/CMakeLists.txt5
-rw-r--r--src/utils/flacdiff/Makefile.am21
-rw-r--r--src/utils/flacdiff/Makefile.in501
-rw-r--r--src/utils/flacdiff/main.cpp230
-rw-r--r--src/utils/flactimer/CMakeLists.txt2
-rw-r--r--src/utils/flactimer/Makefile.am21
-rw-r--r--src/utils/flactimer/Makefile.in501
-rw-r--r--src/utils/flactimer/main.cpp175
223 files changed, 87303 insertions, 0 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000..262feea
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 3.11)
+
+option(ENABLE_64_BIT_WORDS "Set FLAC__BYTES_PER_WORD to 8, for 64-bit machines. For 32-bit machines, turning this off might give a tiny speed improvement" ON)
+option(BUILD_UTILS "Build utils" OFF)
+
+add_subdirectory("libFLAC")
+if(BUILD_CXXLIBS)
+ add_subdirectory("libFLAC++")
+endif()
+add_subdirectory("share/replaygain_analysis")
+add_subdirectory("share/replaygain_synthesis")
+add_subdirectory("share/getopt")
+add_subdirectory("share/utf8")
+add_subdirectory("share/grabbag")
+
+if(BUILD_PROGRAMS)
+ add_subdirectory("flac")
+ add_subdirectory("metaflac")
+endif()
+if(BUILD_UTILS)
+ add_subdirectory(utils/flacdiff)
+ if(WIN32)
+ add_subdirectory(utils/flactimer)
+ endif()
+endif()
+
+if(BUILD_TESTING)
+ add_subdirectory("test_libs_common")
+ add_subdirectory("test_libFLAC")
+ if(BUILD_CXXLIBS)
+ add_subdirectory("test_libFLAC++")
+ endif()
+ add_subdirectory("test_grabbag")
+ add_subdirectory("test_seeking")
+ add_subdirectory("test_streams")
+endif()
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..e9d60a9
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,40 @@
+# FLAC - Free Lossless Audio Codec
+# Copyright (C) 2001-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This file is part the FLAC project. FLAC is comprised of several
+# components distributed under different 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 = libFLAC++ test_libFLAC++
+endif
+
+if FLaC__WITH_PROGRAMS
+PROGRAMS_DIRS = flac metaflac
+endif
+
+SUBDIRS = \
+ libFLAC \
+ share \
+ $(PROGRAMS_DIRS) \
+ test_grabbag \
+ test_libs_common \
+ test_libFLAC \
+ test_seeking \
+ test_streams \
+ utils \
+ $(CPPLIBS_DIRS)
+
+EXTRA_DIST = \
+ CMakeLists.txt
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..808cc51
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,694 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in 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.
+
+@SET_MAKE@
+
+# FLAC - Free Lossless Audio Codec
+# Copyright (C) 2001-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This file is part the FLAC project. FLAC is comprised of several
+# components distributed under different 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.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/add_cflags.m4 \
+ $(top_srcdir)/m4/add_cxxflags.m4 \
+ $(top_srcdir)/m4/ax_add_fortify_source.m4 \
+ $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_enable_debug.m4 \
+ $(top_srcdir)/m4/bswap.m4 $(top_srcdir)/m4/clang.m4 \
+ $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gcc_version.m4 \
+ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/ogg.m4 \
+ $(top_srcdir)/m4/really_gcc.m4 \
+ $(top_srcdir)/m4/stack_protect.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+DIST_SUBDIRS = libFLAC share flac metaflac test_grabbag \
+ test_libs_common test_libFLAC test_seeking test_streams utils \
+ libFLAC++ test_libFLAC++
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_64_BIT_WORDS = @ENABLE_64_BIT_WORDS@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLAC__HAS_OGG = @FLAC__HAS_OGG@
+FLAC__TEST_LEVEL = @FLAC__TEST_LEVEL@
+FLAC__TEST_WITH_VALGRIND = @FLAC__TEST_WITH_VALGRIND@
+GCC_MAJOR_VERSION = @GCC_MAJOR_VERSION@
+GCC_MINOR_VERSION = @GCC_MINOR_VERSION@
+GCC_VERSION = @GCC_VERSION@
+GIT_COMMIT_VERSION_HASH = @GIT_COMMIT_VERSION_HASH@
+GIT_FOUND = @GIT_FOUND@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_FUZZING_ENGINE = @LIB_FUZZING_ENGINE@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OBJ_FORMAT = @OBJ_FORMAT@
+OGG_CFLAGS = @OGG_CFLAGS@
+OGG_LIBS = @OGG_LIBS@
+OGG_PACKAGE = @OGG_PACKAGE@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@FLaC__WITH_CPPLIBS_TRUE@CPPLIBS_DIRS = libFLAC++ test_libFLAC++
+@FLaC__WITH_PROGRAMS_TRUE@PROGRAMS_DIRS = flac metaflac
+SUBDIRS = \
+ libFLAC \
+ share \
+ $(PROGRAMS_DIRS) \
+ test_grabbag \
+ test_libs_common \
+ test_libFLAC \
+ test_seeking \
+ test_streams \
+ utils \
+ $(CPPLIBS_DIRS)
+
+EXTRA_DIST = \
+ CMakeLists.txt
+
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-generic clean-libtool cscopelist-am ctags \
+ ctags-am distclean distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/flac/CMakeLists.txt b/src/flac/CMakeLists.txt
new file mode 100644
index 0000000..da7ce8d
--- /dev/null
+++ b/src/flac/CMakeLists.txt
@@ -0,0 +1,25 @@
+check_include_file("sys/ioctl.h" HAVE_SYS_IOCTL_H)
+check_include_file("termios.h" HAVE_TERMIOS_H)
+
+add_executable(flacapp
+ analyze.c
+ decode.c
+ encode.c
+ foreign_metadata.c
+ main.c
+ local_string_utils.c
+ utils.c
+ vorbiscomment.c
+ version.rc
+ $<$<BOOL:${WIN32}>:../../include/share/win_utf8_io.h>
+ $<$<BOOL:${WIN32}>:../share/win_utf8_io/win_utf8_io.c>)
+set_property(TARGET flacapp PROPERTY RUNTIME_OUTPUT_NAME flac)
+set_property(TARGET flacapp PROPERTY PROJECT_LABEL "flac")
+target_link_libraries(flacapp
+ FLAC
+ getopt
+ replaygain_synthesis
+ utf8)
+
+install(TARGETS flacapp EXPORT targets
+ RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
diff --git a/src/flac/Makefile.am b/src/flac/Makefile.am
new file mode 100644
index 0000000..279a7cb
--- /dev/null
+++ b/src/flac/Makefile.am
@@ -0,0 +1,69 @@
+# flac - Command-line FLAC encoder/decoder
+# Copyright (C) 2000-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+if OS_IS_WINDOWS
+win_utf8_lib = $(top_builddir)/src/share/win_utf8_io/libwin_utf8_io.la
+if HAVE_WINDRES
+flac_DEPENDENCIES = version.o
+windows_resource_link = -Wl,version.o
+endif
+endif
+
+bin_PROGRAMS = flac
+
+AM_CFLAGS = @OGG_CFLAGS@
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+EXTRA_DIST = \
+ CMakeLists.txt \
+ iffscan.c \
+ version.rc
+
+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/utf8/libutf8.la \
+ $(top_builddir)/src/share/grabbag/libgrabbag.la \
+ $(top_builddir)/src/share/getopt/libgetopt.la \
+ $(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \
+ $(top_builddir)/src/share/replaygain_synthesis/libreplaygain_synthesis.la \
+ $(top_builddir)/src/libFLAC/libFLAC.la \
+ $(win_utf8_lib) \
+ @LTLIBICONV@ \
+ -lm
+
+flac_LDFLAGS = $(AM_LDFLAGS) $(windows_resource_link)
+
+CLEANFILES = flac.exe
+
+.rc.o:
+ $(RC) $(AM_CPPFLAGS) $< $@
diff --git a/src/flac/Makefile.in b/src/flac/Makefile.in
new file mode 100644
index 0000000..bc1d11e
--- /dev/null
+++ b/src/flac/Makefile.in
@@ -0,0 +1,782 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in 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.
+
+@SET_MAKE@
+
+# flac - Command-line FLAC encoder/decoder
+# Copyright (C) 2000-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@HAVE_WINDRES_FALSE@flac_DEPENDENCIES = \
+@HAVE_WINDRES_FALSE@ $(top_builddir)/src/share/utf8/libutf8.la \
+@HAVE_WINDRES_FALSE@ $(top_builddir)/src/share/grabbag/libgrabbag.la \
+@HAVE_WINDRES_FALSE@ $(top_builddir)/src/share/getopt/libgetopt.la \
+@HAVE_WINDRES_FALSE@ $(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \
+@HAVE_WINDRES_FALSE@ $(top_builddir)/src/share/replaygain_synthesis/libreplaygain_synthesis.la \
+@HAVE_WINDRES_FALSE@ $(top_builddir)/src/libFLAC/libFLAC.la \
+@HAVE_WINDRES_FALSE@ $(win_utf8_lib)
+@OS_IS_WINDOWS_FALSE@flac_DEPENDENCIES = $(top_builddir)/src/share/utf8/libutf8.la \
+@OS_IS_WINDOWS_FALSE@ $(top_builddir)/src/share/grabbag/libgrabbag.la \
+@OS_IS_WINDOWS_FALSE@ $(top_builddir)/src/share/getopt/libgetopt.la \
+@OS_IS_WINDOWS_FALSE@ $(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \
+@OS_IS_WINDOWS_FALSE@ $(top_builddir)/src/share/replaygain_synthesis/libreplaygain_synthesis.la \
+@OS_IS_WINDOWS_FALSE@ $(top_builddir)/src/libFLAC/libFLAC.la \
+@OS_IS_WINDOWS_FALSE@ $(win_utf8_lib)
+bin_PROGRAMS = flac$(EXEEXT)
+subdir = src/flac
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/add_cflags.m4 \
+ $(top_srcdir)/m4/add_cxxflags.m4 \
+ $(top_srcdir)/m4/ax_add_fortify_source.m4 \
+ $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_enable_debug.m4 \
+ $(top_srcdir)/m4/bswap.m4 $(top_srcdir)/m4/clang.m4 \
+ $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gcc_version.m4 \
+ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/ogg.m4 \
+ $(top_srcdir)/m4/really_gcc.m4 \
+ $(top_srcdir)/m4/stack_protect.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)"
+PROGRAMS = $(bin_PROGRAMS)
+am_flac_OBJECTS = analyze.$(OBJEXT) decode.$(OBJEXT) encode.$(OBJEXT) \
+ foreign_metadata.$(OBJEXT) main.$(OBJEXT) \
+ local_string_utils.$(OBJEXT) utils.$(OBJEXT) \
+ vorbiscomment.$(OBJEXT)
+flac_OBJECTS = $(am_flac_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+flac_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(flac_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/analyze.Po ./$(DEPDIR)/decode.Po \
+ ./$(DEPDIR)/encode.Po ./$(DEPDIR)/foreign_metadata.Po \
+ ./$(DEPDIR)/local_string_utils.Po ./$(DEPDIR)/main.Po \
+ ./$(DEPDIR)/utils.Po ./$(DEPDIR)/vorbiscomment.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(flac_SOURCES)
+DIST_SOURCES = $(flac_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_64_BIT_WORDS = @ENABLE_64_BIT_WORDS@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLAC__HAS_OGG = @FLAC__HAS_OGG@
+FLAC__TEST_LEVEL = @FLAC__TEST_LEVEL@
+FLAC__TEST_WITH_VALGRIND = @FLAC__TEST_WITH_VALGRIND@
+GCC_MAJOR_VERSION = @GCC_MAJOR_VERSION@
+GCC_MINOR_VERSION = @GCC_MINOR_VERSION@
+GCC_VERSION = @GCC_VERSION@
+GIT_COMMIT_VERSION_HASH = @GIT_COMMIT_VERSION_HASH@
+GIT_FOUND = @GIT_FOUND@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_FUZZING_ENGINE = @LIB_FUZZING_ENGINE@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OBJ_FORMAT = @OBJ_FORMAT@
+OGG_CFLAGS = @OGG_CFLAGS@
+OGG_LIBS = @OGG_LIBS@
+OGG_PACKAGE = @OGG_PACKAGE@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@OS_IS_WINDOWS_TRUE@win_utf8_lib = $(top_builddir)/src/share/win_utf8_io/libwin_utf8_io.la
+@HAVE_WINDRES_TRUE@@OS_IS_WINDOWS_TRUE@flac_DEPENDENCIES = version.o
+@HAVE_WINDRES_TRUE@@OS_IS_WINDOWS_TRUE@windows_resource_link = -Wl,version.o
+AM_CFLAGS = @OGG_CFLAGS@
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+EXTRA_DIST = \
+ CMakeLists.txt \
+ iffscan.c \
+ version.rc
+
+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/utf8/libutf8.la \
+ $(top_builddir)/src/share/grabbag/libgrabbag.la \
+ $(top_builddir)/src/share/getopt/libgetopt.la \
+ $(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \
+ $(top_builddir)/src/share/replaygain_synthesis/libreplaygain_synthesis.la \
+ $(top_builddir)/src/libFLAC/libFLAC.la \
+ $(win_utf8_lib) \
+ @LTLIBICONV@ \
+ -lm
+
+flac_LDFLAGS = $(AM_LDFLAGS) $(windows_resource_link)
+CLEANFILES = flac.exe
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj .rc
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/flac/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/flac/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ || test -f $$p1 \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+flac$(EXEEXT): $(flac_OBJECTS) $(flac_DEPENDENCIES) $(EXTRA_flac_DEPENDENCIES)
+ @rm -f flac$(EXEEXT)
+ $(AM_V_CCLD)$(flac_LINK) $(flac_OBJECTS) $(flac_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/analyze.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decode.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/encode.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/foreign_metadata.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/local_string_utils.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vorbiscomment.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/analyze.Po
+ -rm -f ./$(DEPDIR)/decode.Po
+ -rm -f ./$(DEPDIR)/encode.Po
+ -rm -f ./$(DEPDIR)/foreign_metadata.Po
+ -rm -f ./$(DEPDIR)/local_string_utils.Po
+ -rm -f ./$(DEPDIR)/main.Po
+ -rm -f ./$(DEPDIR)/utils.Po
+ -rm -f ./$(DEPDIR)/vorbiscomment.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/analyze.Po
+ -rm -f ./$(DEPDIR)/decode.Po
+ -rm -f ./$(DEPDIR)/encode.Po
+ -rm -f ./$(DEPDIR)/foreign_metadata.Po
+ -rm -f ./$(DEPDIR)/local_string_utils.Po
+ -rm -f ./$(DEPDIR)/main.Po
+ -rm -f ./$(DEPDIR)/utils.Po
+ -rm -f ./$(DEPDIR)/vorbiscomment.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-binPROGRAMS clean-generic clean-libtool cscopelist-am \
+ ctags ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-binPROGRAMS \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am uninstall-binPROGRAMS
+
+.PRECIOUS: Makefile
+
+
+.rc.o:
+ $(RC) $(AM_CPPFLAGS) $< $@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/flac/analyze.c b/src/flac/analyze.c
new file mode 100644
index 0000000..0a85565
--- /dev/null
+++ b/src/flac/analyze.c
@@ -0,0 +1,252 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "FLAC/all.h"
+#include "analyze.h"
+
+#include "share/compat.h"
+
+typedef struct {
+ FLAC__int32 residual;
+ uint32_t count;
+} pair_t;
+
+typedef struct {
+ pair_t buckets[FLAC__MAX_BLOCK_SIZE];
+ int peak_index;
+ uint32_t nbuckets;
+ uint32_t 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, uint32_t 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, uint32_t frame_number, FLAC__uint64 frame_offset, FLAC__uint64 frame_bytes, analysis_options aopts, FILE *fout)
+{
+ const uint32_t channels = frame->header.channels;
+ char outfilename[1024];
+ subframe_stats_t stats;
+ uint32_t i, channel, partitions;
+
+ /* do the human-readable part first */
+ fprintf(fout, "frame=%u\toffset=%" PRIu64 "\tbits=%" PRIu64 "\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]);
+ 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 uint32_t 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=%" PRId64 "\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]=%" PRId64 "\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++) {
+ uint32_t 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]=%" PRId64 "\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++) {
+ uint32_t 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;
+ uint32_t 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);
+ }
+
+ if(stats.nsamples > 0) {
+ /* write the subframe */
+ flac_snprintf(outfilename, sizeof (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 && all_.nsamples > 0) {
+ 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, uint32_t incr)
+{
+ uint32_t 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;
+ uint32_t 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 = flac_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);
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ unlink(filename);
+#endif
+ return true;
+}
diff --git a/src/flac/analyze.h b/src/flac/analyze.h
new file mode 100644
index 0000000..ce07b14
--- /dev/null
+++ b/src/flac/analyze.h
@@ -0,0 +1,32 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#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, uint32_t frame_number, FLAC__uint64 frame_offset, FLAC__uint64 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
index 0000000..90f7a6c
--- /dev/null
+++ b/src/flac/decode.c
@@ -0,0 +1,1674 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <math.h> /* for floor() */
+#include <stdio.h> /* for FILE etc. */
+#include <string.h> /* for strcmp(), strerror() */
+#include <time.h> /* for clock() */
+#include "FLAC/all.h"
+#include "share/grabbag.h"
+#include "share/replaygain_synthesis.h"
+#include "share/compat.h"
+#include "decode.h"
+
+typedef struct {
+#if FLAC__HAS_OGG
+ FLAC__bool is_ogg;
+ FLAC__bool use_first_serial_number;
+ long serial_number;
+#endif
+
+ FileFormat format;
+ FileSubFormat subformat;
+ FLAC__bool treat_warnings_as_errors;
+ FLAC__bool continue_through_decode_errors;
+ FLAC__bool channel_map_none;
+ FLAC__bool relaxed_foreign_metadata_handling;
+
+ 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;
+ uint32_t 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 error_callback_suppress_messages; /* turn on to prevent repeating messages from the error callback */
+ FLAC__bool warn_user_about_foreign_metadata; /* to prevent more than one warning message per file */
+
+ 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;
+ uint32_t bps;
+ uint32_t channels;
+ uint32_t 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 */
+ FLAC__off_t fm_offset1, fm_offset2, fm_offset3;
+
+ clock_t old_clock_t;
+} 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, FileFormat format, FileSubFormat subformat, FLAC__bool treat_warnings_as_errors, FLAC__bool continue_through_decode_errors, FLAC__bool channel_map_none, FLAC__bool relaxed_foreign_metadata_handling, 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, uint32_t 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_body(FILE *f, FLAC__bool is_waveformatextensible, uint32_t bps, uint32_t channels, uint32_t sample_rate, FLAC__uint32 channel_mask);
+static FLAC__bool write_aiff_form_comm_chunk(FILE *f, FLAC__uint64 samples, uint32_t bps, uint32_t channels, uint32_t sample_rate, FileFormat format, FileSubFormat subformat, FLAC__uint32 comm_length);
+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_little_endian_uint64(FILE *f, FLAC__uint64 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, uint32_t 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_file(const char *infilename, const char *outfilename, FLAC__bool analysis_mode, analysis_options aopts, decode_options_t options)
+{
+ DecoderSession decoder_session;
+
+ FLAC__ASSERT(
+ options.format == FORMAT_WAVE ||
+ options.format == FORMAT_WAVE64 ||
+ options.format == FORMAT_RF64 ||
+ options.format == FORMAT_AIFF ||
+ options.format == FORMAT_AIFF_C ||
+ options.format == FORMAT_RAW
+ );
+
+ if(options.format == FORMAT_RAW) {
+ decoder_session.is_big_endian = options.format_options.raw.is_big_endian;
+ decoder_session.is_unsigned_samples = options.format_options.raw.is_unsigned_samples;
+ }
+
+ if(!
+ DecoderSession_construct(
+ &decoder_session,
+#if FLAC__HAS_OGG
+ options.is_ogg,
+ options.use_first_serial_number,
+ options.serial_number,
+#else
+ /*is_ogg=*/false,
+ /*use_first_serial_number=*/false,
+ /*serial_number=*/0,
+#endif
+ options.format,
+ options.force_subformat,
+ options.treat_warnings_as_errors,
+ options.continue_through_decode_errors,
+ options.channel_map_none,
+ options.relaxed_foreign_metadata_handling,
+ options.replaygain_synthesis_spec,
+ analysis_mode,
+ aopts,
+ &options.skip_specification,
+ &options.until_specification,
+ options.has_cue_specification? &options.cue_specification : 0,
+ options.format == FORMAT_RAW? NULL : options.format_options.iff.foreign_metadata,
+ infilename,
+ outfilename
+ )
+ )
+ return 1;
+
+ stats_new_file();
+ 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, FileFormat format, FileSubFormat subformat, FLAC__bool treat_warnings_as_errors, FLAC__bool continue_through_decode_errors, FLAC__bool channel_map_none, FLAC__bool relaxed_foreign_metadata_handling, 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->format = format;
+ d->subformat = subformat;
+ 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->relaxed_foreign_metadata_handling = relaxed_foreign_metadata_handling;
+ 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->error_callback_suppress_messages = false;
+ if(relaxed_foreign_metadata_handling)
+ d->warn_user_about_foreign_metadata = false;
+ else
+ d->warn_user_about_foreign_metadata = true;
+
+ 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 = UINT32_MAX;
+ 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;
+
+ d->old_clock_t = 0;
+
+ 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 = flac_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) {
+#if defined _WIN32 && !defined __CYGWIN__
+ if(!error_occurred) {
+ FLAC__off_t written_size = ftello(d->fout);
+ if(written_size > 0) {
+ HANDLE fh = CreateFile_utf8(d->outfilename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if(fh != INVALID_HANDLE_VALUE) {
+ if(GetFileType(fh) == FILE_TYPE_DISK) {
+ LARGE_INTEGER size;
+ size.QuadPart = written_size;
+ if(SetFilePointerEx(fh, size, NULL, FILE_CURRENT)) /* correct the file size */
+ SetEndOfFile(fh);
+ }
+ CloseHandle(fh);
+ }
+ }
+ }
+#endif
+ fclose(d->fout);
+
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ /* Always delete output file when fuzzing */
+ if(error_occurred)
+#endif
+ flac_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->test_only && strcmp(infilename, "-") != 0) {
+ /* When testing, we can be a little more pedantic, as long
+ * as we can seek properly */
+ FLAC__byte buffer[3];
+ FILE * f;
+
+ if(0 == (f = flac_fopen(infilename, "rb"))) {
+ flac__utils_printf(stderr, 1, "ERROR: can't open input file %s: %s\n", infilename, strerror(errno));
+ return false;
+ }
+
+ if(fread(buffer, 1, 3, f) < 3) {
+ flac__utils_printf(stderr, 1, "%s: ERROR checking for ID3v2 tag\n", decoder_session->inbasefilename);
+ fclose(f);
+ return false;
+ }
+ if(memcmp(buffer, "ID3", 3) == 0){
+ flac__utils_printf(stderr, 1, "%s: WARNING, ID3v2 tag found. This is non-standard and strongly discouraged\n", decoder_session->inbasefilename);
+ if(decoder_session->treat_warnings_as_errors) {
+ fclose(f);
+ return false;
+ }
+ }
+ fclose(f);
+ }
+
+ 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 || !decoder_session->channel_map_none)
+ FLAC__stream_decoder_set_metadata_respond(decoder_session->decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+ if(!decoder_session->analysis_mode && !decoder_session->test_only && decoder_session->foreign_metadata == NULL) {
+ /* Warn user if foreign metadata is found */
+ uint32_t i;
+ for(i = 0; i < FLAC__FOREIGN_METADATA_NUMBER_OF_RECOGNIZED_APPLICATION_IDS; i++)
+ FLAC__stream_decoder_set_metadata_respond_application(decoder_session->decoder, (FLAC__byte *)FLAC__FOREIGN_METADATA_APPLICATION_ID[i]);
+ }
+
+#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->analysis_mode)
+ FLAC__stream_decoder_get_decode_position(d->decoder, &d->decode_position);
+
+ if(d->abort_flag)
+ return false;
+
+ /* set channel mapping */
+ /* 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->channel_map_none && d->channel_mask == 0) {
+ if(d->channels == 1) {
+ d->channel_mask = 0x0004;
+ }
+ else if(d->channels == 2) {
+ d->channel_mask = 0x0003;
+ }
+ else if(d->channels == 3) {
+ d->channel_mask = 0x0007;
+ }
+ else if(d->channels == 4) {
+ d->channel_mask = 0x0033;
+ }
+ else if(d->channels == 5) {
+ d->channel_mask = 0x0607;
+ }
+ else if(d->channels == 6) {
+ d->channel_mask = 0x060f;
+ }
+ else if(d->channels == 7) {
+ d->channel_mask = 0x070f;
+ }
+ else if(d->channels == 8) {
+ d->channel_mask = 0x063f;
+ }
+ }
+
+#if defined _WIN32 && !defined __CYGWIN__
+ if(!d->analysis_mode && !d->test_only && d->total_samples > 0 && d->fout != stdout) {
+ HANDLE fh = CreateFile_utf8(d->outfilename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if(fh != INVALID_HANDLE_VALUE) {
+ if (GetFileType(fh) == FILE_TYPE_DISK) {
+ LARGE_INTEGER size;
+ size.QuadPart = d->total_samples * d->channels * ((d->bps+7)/8);
+ if(d->format != FORMAT_RAW) {
+ size.QuadPart += 512;
+ if(d->foreign_metadata) {
+ size_t i;
+ for(i = d->format==FORMAT_RF64?2:1; i < d->foreign_metadata->num_blocks; i++) {
+ if(i != d->foreign_metadata->format_block && i != d->foreign_metadata->audio_block)
+ size.QuadPart += d->foreign_metadata->blocks[i].size;
+ }
+ }
+ }
+
+ if(SetFilePointerEx(fh, size, NULL, FILE_CURRENT)) /* tell filesystem the expected filesize to eliminate fragmentation */
+ SetEndOfFile(fh);
+ }
+ CloseHandle(fh);
+ }
+ }
+#endif
+
+ /* write the WAVE/AIFF headers if necessary */
+ if(!d->analysis_mode && !d->test_only && d->format != FORMAT_RAW) {
+ 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;
+ }
+
+ /* write padding bytes for alignment if necessary */
+ if(!d->analysis_mode && !d->test_only && d->format != FORMAT_RAW) {
+ const FLAC__uint64 data_size = d->total_samples * d->channels * ((d->bps+7)/8);
+ uint32_t padding;
+ if(d->format != FORMAT_WAVE64) {
+ padding = (uint32_t)(data_size & 1);
+ }
+ else {
+ /* 8-byte alignment for Wave64 */
+ padding = (8 - (uint32_t)(data_size & 7)) & 7;
+ }
+ for( ; padding > 0; --padding) {
+ if(flac__utils_fwrite("\000", 1, 1, d->fout) != 1) {
+ print_error_with_state(
+ d,
+ d->format == FORMAT_WAVE? "ERROR writing pad byte to WAVE data chunk" :
+ d->format == FORMAT_WAVE64? "ERROR writing pad bytes to WAVE64 data chunk" :
+ d->format == FORMAT_RF64? "ERROR writing pad byte to RF64 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) {
+ stats_print_name(1, d->inbasefilename);
+ flac__utils_printf(stderr, 1, "ERROR, MD5 signature mismatch\n");
+ ok = d->continue_through_decode_errors;
+ }
+ else if(d->got_stream_info && d->total_samples && (d->total_samples > d->samples_processed)){
+ stats_print_name(1, d->inbasefilename);
+ flac__utils_printf(stderr, 1, "ERROR, decoded number of samples is smaller than the total number of samples set in the STREAMINFO\n");
+ ok = d->continue_through_decode_errors;
+ }
+ else {
+ if(!d->got_stream_info) {
+ stats_print_name(1, d->inbasefilename);
+ flac__utils_printf(stderr, 1, "WARNING, cannot check MD5 signature since there was no STREAMINFO\n");
+ ok = !d->treat_warnings_as_errors;
+ }
+ else if(!d->has_md5sum) {
+ stats_print_name(1, d->inbasefilename);
+ flac__utils_printf(stderr, 1, "WARNING, cannot check MD5 signature since it was unset in the STREAMINFO\n");
+ ok = !d->treat_warnings_as_errors;
+ }
+ else if(!d->total_samples) {
+ stats_print_name(1, d->inbasefilename);
+ flac__utils_printf(stderr, 1, "WARNING, cannot check total number of samples since it was unset in the STREAMINFO\n");
+ ok = !d->treat_warnings_as_errors;
+ }
+ stats_print_name(2, d->inbasefilename);
+ flac__utils_printf(stderr, 2, "%s \n", d->test_only? "ok ":d->analysis_mode?"done ":"done");
+ }
+ DecoderSession_destroy(d, /*error_occurred=*/!ok);
+ if(!d->analysis_mode && !d->test_only && d->format != FORMAT_RAW) {
+ 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;
+ }
+ if(!flac__foreign_metadata_compare_with_iff(d->foreign_metadata, d->infilename, d->outfilename, d->fm_offset3, &error)) {
+ flac__utils_printf(stderr, 1, "ERROR verifying foreign metadata restore 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, uint32_t sample_rate, FLAC__uint64 skip, FLAC__uint64 total_samples_in_input)
+{
+ /* convert from mm:ss.sss to sample number if necessary */
+ if(!flac__utils_canonicalize_skip_until_specification(spec, sample_rate)) {
+ flac__utils_printf(stderr, 1, "%s: ERROR, value of --until is too large\n", inbasefilename);
+ return false;
+ }
+
+ /* 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 FileFormat format = decoder_session->format;
+ const FileSubFormat subformat = decoder_session->subformat;
+ const char *fmt_desc =
+ format==FORMAT_WAVE? "WAVE" :
+ format==FORMAT_WAVE64? "Wave64" :
+ format==FORMAT_RF64? "RF64" :
+ format==FORMAT_AIFF? "AIFF" :
+ "AIFC";
+ const FLAC__bool is_waveformatextensible =
+ subformat == SUBFORMAT_WAVE_EXTENSIBLE || (
+ (format == FORMAT_WAVE || format == FORMAT_WAVE64 || format == FORMAT_RF64) &&
+ subformat != SUBFORMAT_WAVE_PCM &&
+ (
+ (decoder_session->channel_mask != 0 && decoder_session->channel_mask != 0x0004 && decoder_session->channel_mask != 0x0003) ||
+ (decoder_session->bps != 8 && decoder_session->bps != 16) ||
+ decoder_session->channels > 2
+ ));
+ const FLAC__uint64 data_size = samples * decoder_session->channels * ((decoder_session->bps+7)/8);
+ const FLAC__uint64 aligned_data_size =
+ format == FORMAT_WAVE64?
+ (data_size+7) & (~(FLAC__uint64)7) :
+ (data_size+1) & (~(FLAC__uint64)1);
+
+ FLAC__uint64 iff_size;
+ uint32_t 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;
+
+ FLAC__ASSERT(
+ format == FORMAT_WAVE ||
+ format == FORMAT_WAVE64 ||
+ format == FORMAT_RF64 ||
+ format == FORMAT_AIFF ||
+ format == FORMAT_AIFF_C
+ );
+
+ 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; we always skip the first chunk, ds64 chunk, format chunk, and sound chunk since we write our own */
+ for(i = format==FORMAT_RF64?2:1; i < fm->num_blocks; i++) {
+ if(i != fm->format_block && i != fm->audio_block)
+ foreign_metadata_size += fm->blocks[i].size;
+ }
+ }
+
+ if(samples == 0)
+ iff_size = 0;
+ else if(format == FORMAT_WAVE || format == FORMAT_RF64)
+ /* 4 for WAVE form bytes */
+ /* +{36,0} for ds64 chunk */
+ /* +8+{40,16} for fmt chunk header and body */
+ /* +8 for data chunk header */
+ iff_size = 4 + (format==FORMAT_RF64?36:0) + 8+(is_waveformatextensible?40:16) + 8 + foreign_metadata_size + aligned_data_size;
+ else if(format == FORMAT_WAVE64)
+ /* 16+8 for RIFF GUID and size field */
+ /* +16 for WAVE GUID */
+ /* +16+8+{40,16} for fmt chunk header (GUID and size field) and body */
+ /* +16+8 for data chunk header (GUID and size field) */
+ iff_size = 16+8 + 16 + 16+8+(is_waveformatextensible?40:16) + 16+8 + foreign_metadata_size + aligned_data_size;
+ else if(format == FORMAT_AIFF)
+ iff_size = 46 + foreign_metadata_size + aligned_data_size;
+ else /* AIFF-C */
+ iff_size = 16 + foreign_metadata_size + aligned_data_size + (fm?fm->aifc_comm_length:0);
+
+ if(format != FORMAT_WAVE64 && format != FORMAT_RF64 && iff_size >= 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(format == FORMAT_WAVE || format == FORMAT_WAVE64 || format == FORMAT_RF64) {
+ /* RIFF header */
+ switch(format) {
+ case FORMAT_WAVE:
+ if(flac__utils_fwrite("RIFF", 1, 4, f) != 4)
+ return false;
+ if(!write_little_endian_uint32(f, (FLAC__uint32)iff_size)) /* filesize-8 */
+ return false;
+ if(flac__utils_fwrite("WAVE", 1, 4, f) != 4)
+ return false;
+ break;
+ case FORMAT_WAVE64:
+ /* RIFF GUID 66666972-912E-11CF-A5D6-28DB04C10000 */
+ if(flac__utils_fwrite("\x72\x69\x66\x66\x2E\x91\xCF\x11\xA5\xD6\x28\xDB\x04\xC1\x00\x00", 1, 16, f) != 16)
+ return false;
+ if(!write_little_endian_uint64(f, iff_size))
+ return false;
+ /* WAVE GUID 65766177-ACF3-11D3-8CD1-00C04F8EDB8A */
+ if(flac__utils_fwrite("\x77\x61\x76\x65\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 1, 16, f) != 16)
+ return false;
+ break;
+ case FORMAT_RF64:
+ if(flac__utils_fwrite("RF64", 1, 4, f) != 4)
+ return false;
+ if(!write_little_endian_uint32(f, 0xffffffff))
+ return false;
+ if(flac__utils_fwrite("WAVE", 1, 4, f) != 4)
+ return false;
+ break;
+ default:
+ return false;
+ }
+
+ /* ds64 chunk for RF64 */
+ if(format == FORMAT_RF64) {
+ if(flac__utils_fwrite("ds64", 1, 4, f) != 4)
+ return false;
+
+ if(!write_little_endian_uint32(f, 28)) /* chunk size */
+ return false;
+
+ if(!write_little_endian_uint64(f, iff_size))
+ return false;
+
+ if(!write_little_endian_uint64(f, data_size))
+ return false;
+
+ if(!write_little_endian_uint64(f, samples)) /*@@@@@@ correct? */
+ return false;
+
+ if(!write_little_endian_uint32(f, 0)) /* table size */
+ return false;
+ }
+
+ decoder_session->fm_offset1 = ftello(f);
+
+ if(fm) {
+ /* seek forward to {allocate} or {skip over already-written chunks} before "fmt " */
+ for(i = format==FORMAT_RF64?2: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(format != FORMAT_WAVE64) {
+ 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;
+ }
+ else { /* Wave64 */
+ /* fmt GUID 20746D66-ACF3-11D3-8CD1-00C04F8EDB8A */
+ if(flac__utils_fwrite("\x66\x6D\x74\x20\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 1, 16, f) != 16)
+ return false;
+ /* chunk size (+16+8 for GUID and size fields) */
+ if(!write_little_endian_uint64(f, 16+8+(is_waveformatextensible?40:16)))
+ return false;
+ }
+
+ if(!write_riff_wave_fmt_chunk_body(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(format != FORMAT_WAVE64) {
+ if(flac__utils_fwrite("data", 1, 4, f) != 4)
+ return false;
+ if(!write_little_endian_uint32(f, format==FORMAT_RF64? 0xffffffff : (FLAC__uint32)data_size))
+ return false;
+ }
+ else { /* Wave64 */
+ /* data GUID 61746164-ACF3-11D3-8CD1-00C04F8EDB8A */
+ if(flac__utils_fwrite("\x64\x61\x74\x61\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 1, 16, f) != 16)
+ return false;
+ /* +16+8 for GUID and size fields */
+ if(!write_little_endian_uint64(f, 16+8 + data_size))
+ return false;
+ }
+
+ decoder_session->fm_offset3 = ftello(f) + aligned_data_size;
+ }
+ else {
+ if(flac__utils_fwrite("FORM", 1, 4, f) != 4)
+ return false;
+
+ if(!write_big_endian_uint32(f, (FLAC__uint32)iff_size)) /* filesize-8 */
+ return false;
+
+ if(format == FORMAT_AIFF) {
+ if(flac__utils_fwrite("AIFF", 1, 4, f) != 4)
+ return false;
+ }
+ else
+ if(flac__utils_fwrite("AIFC", 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, format, subformat, fm?fm->aifc_comm_length:0))
+ 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)) /* data size */
+ return false;
+
+ if(!write_big_endian_uint32(f, 0/*offset_size*/))
+ return false;
+
+ if(!write_big_endian_uint32(f, 0/*block_size*/))
+ return false;
+
+ decoder_session->fm_offset3 = ftello(f) + aligned_data_size;
+ }
+
+ return true;
+}
+
+FLAC__bool write_riff_wave_fmt_chunk_body(FILE *f, FLAC__bool is_waveformatextensible, uint32_t bps, uint32_t channels, uint32_t sample_rate, FLAC__uint32 channel_mask)
+{
+ 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, uint32_t bps, uint32_t channels, uint32_t sample_rate, FileFormat format, FileSubFormat subformat, FLAC__uint32 comm_length)
+{
+ FLAC__uint32 i;
+ FLAC__ASSERT(samples <= 0xffffffff);
+
+ if(comm_length == 0) {
+ if(format == FORMAT_AIFF)
+ comm_length = 30;
+ else
+ comm_length = 36;
+ }
+
+ if(flac__utils_fwrite("COMM", 1, 4, f) != 4)
+ return false;
+
+ if(!write_big_endian_uint32(f, comm_length-12)) /* 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;
+
+ if(format == FORMAT_AIFF_C) {
+ if(subformat == SUBFORMAT_AIFF_C_NONE) {
+ if(flac__utils_fwrite("NONE", 1, 4, f) != 4)
+ return false;
+ }
+ else if(subformat == SUBFORMAT_AIFF_C_SOWT) {
+ if(flac__utils_fwrite("sowt", 1, 4, f) != 4)
+ return false;
+ }
+ for(i = 34; i < comm_length; i++) {
+ if(flac__utils_fwrite("\x00", 1, 1, f) != 1)
+ 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_little_endian_uint64(FILE *f, FLAC__uint64 val)
+{
+ FLAC__byte *b = (FLAC__byte*)(&val);
+ if(is_big_endian_host_) {
+ FLAC__byte tmp;
+ tmp = b[7]; b[7] = b[0]; b[0] = tmp;
+ tmp = b[6]; b[6] = b[1]; b[1] = tmp;
+ tmp = b[5]; b[5] = b[2]; b[2] = tmp;
+ tmp = b[4]; b[4] = b[3]; b[3] = tmp;
+ }
+ return flac__utils_fwrite(b, 1, 8, f) == 8;
+}
+
+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, uint32_t 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.
+ *
+ */
+{
+ uint32_t shift, exponent;
+
+ if(val == 0U) {
+ if(!write_big_endian_uint16(f, 0))
+ return false;
+ if(!write_big_endian_uint32(f, 0))
+ return false;
+ if(!write_big_endian_uint32(f, 0))
+ return false;
+ return true;
+ }
+
+ 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->format==FORMAT_WAVE? "WAVE" :
+ d->format==FORMAT_WAVE64? "Wave64" :
+ d->format==FORMAT_RF64? "RF64" :
+ "AIFF";
+ FILE *f = flac_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 uint32_t bps = frame->header.bits_per_sample, channels = frame->header.channels;
+ const uint32_t shift = (bps%8)? 8-(bps%8): 0;
+ FLAC__bool is_big_endian = (
+ (decoder_session->format == FORMAT_AIFF || (decoder_session->format == FORMAT_AIFF_C && decoder_session->subformat == SUBFORMAT_AIFF_C_NONE)) ? true : (
+ decoder_session->format == FORMAT_WAVE || decoder_session->format == FORMAT_WAVE64 || decoder_session->format == FORMAT_RF64 || (decoder_session->format == FORMAT_AIFF_C && decoder_session->subformat == SUBFORMAT_AIFF_C_SOWT) ? false :
+ decoder_session->is_big_endian
+ ));
+ FLAC__bool is_unsigned_samples = (
+ decoder_session->format == FORMAT_AIFF || decoder_session->format == FORMAT_AIFF_C ? false : (
+ decoder_session->format == FORMAT_WAVE || decoder_session->format == FORMAT_WAVE64 || decoder_session->format == FORMAT_RF64 ? bps<=8 :
+ decoder_session->is_unsigned_samples
+ ));
+ uint32_t wide_samples = frame->header.blocksize, wide_sample, sample, channel;
+ FLAC__uint64 frame_bytes = 0;
+
+ static union
+ { /* The arrays defined within this union are all the same size. */
+ FLAC__int8 s8buffer [FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS * sizeof(FLAC__int32)]; /* WATCHOUT: can be up to 2 megs */
+ FLAC__uint8 u8buffer [FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS * sizeof(FLAC__int32)];
+ FLAC__int16 s16buffer [FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS * sizeof(FLAC__int16)];
+ FLAC__uint16 u16buffer [FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS * sizeof(FLAC__int16)];
+ FLAC__int32 s32buffer [FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS];
+ FLAC__uint32 u32buffer [FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS];
+ } ubuf;
+
+ 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);
+ if(decoder_session->format == FORMAT_RAW && ((decoder_session->bps % 8) != 0 || decoder_session->bps < 4)) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: bits per sample is %u, must be 8/16/24/32 for raw format output\n", decoder_session->inbasefilename, decoder_session->bps);
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+ }
+ 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 < UINT32_MAX) {
+ 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
+ */
+ /* 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 || !decoder_session->got_stream_info) {
+ 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 || !decoder_session->got_stream_info) {
+ 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 = (uint32_t)(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 = (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 0 /* in case time.h with clock() isn't available for some reason */
+ if(!(decoder_session->frame_counter & 0x1ff))
+ print_stats(decoder_session);
+#else
+ if((clock() - decoder_session->old_clock_t) > (CLOCKS_PER_SEC/4)) {
+ print_stats(decoder_session);
+ decoder_session->old_clock_t = clock();
+ }
+#endif
+
+
+ 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++)
+ ((uint32_t **)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(
+ ubuf.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_ = ubuf.s16buffer + 1;
+ if(is_big_endian)
+ memcpy(ubuf.s16buffer, ((FLAC__byte*)(buffer[0]))+2, sizeof(FLAC__int32) * wide_samples - 2);
+ else
+ memcpy(ubuf.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_ = ubuf.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++) {
+ ubuf.u16buffer[sample++] = (FLAC__uint16)(buffer[0][wide_sample] + 0x8000);
+ ubuf.u16buffer[sample++] = (FLAC__uint16)(buffer[1][wide_sample] + 0x8000);
+ }
+ }
+ else if(channels == 1) {
+ for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+ ubuf.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++)
+ ubuf.u16buffer[sample] = (FLAC__uint16)(buffer[channel][wide_sample] + 0x8000);
+ }
+ }
+ else {
+ if(channels == 2) {
+ for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) {
+ ubuf.s16buffer[sample++] = (FLAC__int16)(buffer[0][wide_sample]);
+ ubuf.s16buffer[sample++] = (FLAC__int16)(buffer[1][wide_sample]);
+ }
+ }
+ else if(channels == 1) {
+ for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+ ubuf.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++)
+ ubuf.s16buffer[sample] = (FLAC__int16)(buffer[channel][wide_sample]);
+ }
+ }
+ if(is_big_endian != is_big_endian_host_) {
+ uint8_t tmp;
+ const uint32_t bytes = sample * 2;
+ uint32_t b;
+ for(b = 0; b < bytes; b += 2) {
+ tmp = ubuf.u8buffer[b];
+ ubuf.u8buffer[b] = ubuf.u8buffer[b+1];
+ ubuf.u8buffer[b+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++)
+ ubuf.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++)
+ ubuf.s32buffer[sample] = buffer[channel][wide_sample];
+ }
+ if(is_big_endian != is_big_endian_host_) {
+ uint8_t tmp;
+ const uint32_t bytes = sample * 4;
+ uint32_t b;
+ for(b = 0; b < bytes; b += 4) {
+ tmp = ubuf.u8buffer[b];
+ ubuf.u8buffer[b] = ubuf.u8buffer[b+3];
+ ubuf.u8buffer[b+3] = tmp;
+ tmp = ubuf.u8buffer[b+1];
+ ubuf.u8buffer[b+1] = ubuf.u8buffer[b+2];
+ ubuf.u8buffer[b+2] = tmp;
+ }
+ }
+ if(is_big_endian) {
+ uint32_t b, lbyte;
+ const uint32_t bytes = sample * 4;
+ for(lbyte = b = 0; b < bytes; ) {
+ b++;
+ ubuf.u8buffer[lbyte++] = ubuf.u8buffer[b++];
+ ubuf.u8buffer[lbyte++] = ubuf.u8buffer[b++];
+ ubuf.u8buffer[lbyte++] = ubuf.u8buffer[b++];
+ }
+ }
+ else {
+ uint32_t b, lbyte;
+ const uint32_t bytes = sample * 4;
+ for(lbyte = b = 0; b < bytes; ) {
+ ubuf.u8buffer[lbyte++] = ubuf.u8buffer[b++];
+ ubuf.u8buffer[lbyte++] = ubuf.u8buffer[b++];
+ ubuf.u8buffer[lbyte++] = ubuf.u8buffer[b++];
+ b++;
+ }
+ }
+ 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++)
+ ubuf.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++)
+ ubuf.s8buffer[sample] = (FLAC__int8)(buffer[channel][wide_sample]);
+ }
+ bytes_to_write = sample;
+ }
+ else if(bps+shift == 32) {
+ if(is_unsigned_samples) {
+ for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+ for(channel = 0; channel < channels; channel++, sample++)
+ ubuf.u32buffer[sample] = buffer[channel][wide_sample];
+ }
+ else {
+ for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+ for(channel = 0; channel < channels; channel++, sample++)
+ ubuf.s32buffer[sample] = buffer[channel][wide_sample];
+ }
+ if(is_big_endian != is_big_endian_host_) {
+ uint8_t tmp;
+ const uint32_t bytes = sample * 4;
+ uint32_t b;
+ for(b = 0; b < bytes; b += 4) {
+ tmp = ubuf.u8buffer[b];
+ ubuf.u8buffer[b] = ubuf.u8buffer[b+3];
+ ubuf.u8buffer[b+3] = tmp;
+ tmp = ubuf.u8buffer[b+1];
+ ubuf.u8buffer[b+1] = ubuf.u8buffer[b+2];
+ ubuf.u8buffer[b+2] = tmp;
+ }
+ }
+ bytes_to_write = 4 * 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(ubuf.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;
+
+ (void)decoder;
+
+ if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
+ FLAC__uint64 skip, until;
+
+ if(decoder_session->got_stream_info){
+ /* There was already a STREAMINFO received */
+ flac__utils_printf(stderr, 1, "%s: ERROR, more than one STREAMINFO found\n", decoder_session->inbasefilename);
+ if(!decoder_session->continue_through_decode_errors)
+ decoder_session->abort_flag = true;
+ return;
+ }
+
+ 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) != 0;
+ 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;
+
+ if(!flac__utils_canonicalize_skip_until_specification(decoder_session->skip_specification, decoder_session->sample_rate)) {
+ flac__utils_printf(stderr, 1, "%s: ERROR, value of --skip is too large\n", decoder_session->inbasefilename);
+ decoder_session->abort_flag = true;
+ return;
+ }
+ 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->format == FORMAT_RAW && ((decoder_session->bps % 8) != 0 || decoder_session->bps < 4)) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: bits per sample is %u, must be 8/16/24/32 for raw format output\n", decoder_session->inbasefilename, decoder_session->bps);
+ decoder_session->abort_flag = true;
+ return;
+ }
+
+ if(decoder_session->bps < 4 || decoder_session->bps > 32) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: bits per sample is %u, must be 4-32\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 if(decoder_session->bps == 0) {
+ flac__utils_printf(stderr, 1, "%s: WARNING: can't apply ReplayGain, bit-per-sample value is invalid\n", decoder_session->inbasefilename);
+ 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);
+ }
+ else if(metadata->type == FLAC__METADATA_TYPE_APPLICATION && decoder_session->warn_user_about_foreign_metadata) {
+ /* Foreign metadata signalling */
+ flac__utils_printf(stderr, 1, "%s: WARNING: found foreign metadata, use --keep-foreign-metadata to restore\n", decoder_session->inbasefilename);
+ decoder_session->warn_user_about_foreign_metadata = false;
+ }
+}
+
+void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+ DecoderSession *decoder_session = (DecoderSession*)client_data;
+ (void)decoder;
+ if(!decoder_session->error_callback_suppress_messages) {
+ stats_print_name(1, decoder_session->inbasefilename);
+ flac__utils_printf(stderr, 1, "*** Got error code %d:%s\n", status, FLAC__StreamDecoderErrorStatusString[status]);
+ }
+ if(!decoder_session->continue_through_decode_errors) {
+ /* if we got a sync error while looking for metadata, either it's not a FLAC file (more likely) or the file is corrupted */
+ if(
+ !decoder_session->error_callback_suppress_messages &&
+ status == FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC &&
+ FLAC__stream_decoder_get_state(decoder) == FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
+ ) {
+ flac__utils_printf(stderr, 1,
+ "\n"
+ "The input file is either not a FLAC file or is corrupted. If you are\n"
+ "convinced it is a FLAC file, you can rerun the same command and add the\n"
+ "-F parameter to try and recover as much as possible from the file.\n"
+ );
+ decoder_session->error_callback_suppress_messages = true;
+ }
+ else if(status == FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM)
+ decoder_session->aborting_due_to_unparseable = true;
+ decoder_session->abort_flag = 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"
+#ifdef _WIN32
+ "An error occurred opening the input file; it is likely that it does not exist,\n"
+ "is not readable or has a filename that exceeds the path length limit.\n"
+#else
+ "An error occurred opening the input file; it is likely that it does not exist\n"
+ "or is not readable.\n"
+#endif
+ );
+ }
+}
+
+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"
+ " https://github.com/xiph/flac/issues\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) {
+ const double progress = (double)decoder_session->samples_processed / (double)decoder_session->total_samples * 100.0;
+
+ if(decoder_session->total_samples > 0) {
+ if ((uint32_t)floor(progress + 0.5) == 100)
+ return;
+
+ stats_print_name(2, decoder_session->inbasefilename);
+ stats_print_info(2, "%s%u%% complete",
+ decoder_session->test_only? "testing, " : decoder_session->analysis_mode? "analyzing, " : "",
+ (uint32_t)floor(progress + 0.5)
+ );
+ }
+ else {
+ stats_print_name(2, decoder_session->inbasefilename);
+ stats_print_info(2, "%s %" PRIu64 " samples",
+ decoder_session->test_only? "tested" : decoder_session->analysis_mode? "analyzed" : "wrote",
+ decoder_session->samples_processed
+ );
+ }
+ }
+}
diff --git a/src/flac/decode.h b/src/flac/decode.h
new file mode 100644
index 0000000..24f5723
--- /dev/null
+++ b/src/flac/decode.h
@@ -0,0 +1,73 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef flac__decode_h
+#define flac__decode_h
+
+#ifdef 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 */
+ FLAC__bool relaxed_foreign_metadata_handling;
+ FileSubFormat force_subformat;
+
+ FileFormat format;
+ union {
+ struct {
+ FLAC__bool is_big_endian;
+ FLAC__bool is_unsigned_samples;
+ } raw;
+ struct {
+ foreign_metadata_t *foreign_metadata; /* NULL unless --keep-foreign-metadata requested */
+ } iff;
+ } format_options;
+} decode_options_t;
+
+/* outfile == 0 => test only */
+int flac__decode_file(const char *infilename, const char *outfilename, FLAC__bool analysis_mode, analysis_options aopts, decode_options_t options);
+
+#endif
diff --git a/src/flac/encode.c b/src/flac/encode.c
new file mode 100644
index 0000000..a945b35
--- /dev/null
+++ b/src/flac/encode.c
@@ -0,0 +1,2852 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <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 <time.h> /* for clock() */
+#include <sys/stat.h>
+#include "FLAC/all.h"
+#include "share/alloc.h"
+#include "share/grabbag.h"
+#include "share/compat.h"
+#include "share/private.h"
+#include "share/safe_str.h"
+#include "share/endswap.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 < 2^sizeof(size_t) / ( FLAC__MAX_CHANNELS * (FLAC__MAX_BITS_PER_SAMPLE/8) ) */
+#define CHUNK_OF_SAMPLES 2048
+
+typedef struct {
+ uint32_t sample_rate;
+ uint32_t channels;
+ uint32_t bits_per_sample; /* width of sample point, including 'shift' bits, valid bps is bits_per_sample-shift */
+ uint32_t shift; /* # of LSBs samples have been shifted left by */
+ uint32_t bytes_per_wide_sample; /* for convenience, always == channels*((bps+7)/8), or 0 if N/A to input format (like FLAC) */
+ FLAC__bool is_unsigned_samples;
+ FLAC__bool is_big_endian;
+ FLAC__uint32 channel_mask;
+} SampleInfo;
+
+/* this is the client_data attached to the FLAC decoder when encoding from a FLAC file */
+typedef struct {
+ FLAC__off_t filesize;
+ const FLAC__byte *lookahead;
+ uint32_t 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;
+
+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__bool treat_warnings_as_errors;
+ FLAC__bool continue_through_decode_errors;
+ FLAC__bool replay_gain;
+ FLAC__uint64 total_samples_to_encode; /* (i.e. "wide samples" aka "sample frames") WATCHOUT: may be 0 to mean 'unknown' */
+ FLAC__uint64 unencoded_size; /* an estimate of the input size, only used in the progress indicator */
+ FLAC__uint64 bytes_written;
+ FLAC__uint64 samples_written;
+#if 0 /* in case time.h with clock() isn't available for some reason */
+ uint32_t stats_frames_interval;
+ uint32_t old_frames_written;
+#else
+ clock_t old_clock_t;
+#endif
+
+ SampleInfo info;
+
+ FileFormat format;
+ union {
+ struct {
+ FLAC__uint64 data_bytes;
+ } iff;
+ struct {
+ FLAC__StreamDecoder *decoder;
+ FLACDecoderData client_data;
+ } flac;
+ } fmt;
+
+ FLAC__StreamEncoder *encoder;
+
+ FILE *fin;
+ FLAC__StreamMetadata *seek_table_template;
+ double progress, compression_ratio;
+} EncoderSession;
+
+const int FLAC_ENCODE__DEFAULT_PADDING = 8192;
+
+static FLAC__bool is_big_endian_host_;
+
+#define UBUFFER_INT8_SIZE 0x10000
+
+static union {
+ FLAC__int8 s8[UBUFFER_INT8_SIZE];
+ FLAC__uint8 u8[UBUFFER_INT8_SIZE];
+ FLAC__int16 s16[UBUFFER_INT8_SIZE/2];
+ FLAC__uint16 u16[UBUFFER_INT8_SIZE/2];
+ FLAC__int32 s32[UBUFFER_INT8_SIZE/4];
+ FLAC__uint32 u32[UBUFFER_INT8_SIZE/4];
+} ubuffer;
+
+
+static FLAC__int32 in_[FLAC__MAX_CHANNELS][CHUNK_OF_SAMPLES];
+static FLAC__int32 *input_[FLAC__MAX_CHANNELS];
+
+
+/*
+ * local routines
+ */
+static FLAC__bool EncoderSession_construct(EncoderSession *e, encode_options_t options, FLAC__off_t infilesize, FILE *infile, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, uint32_t lookahead_length);
+static void EncoderSession_destroy(EncoderSession *e);
+static int EncoderSession_finish_ok(EncoderSession *e, foreign_metadata_t *foreign_metadata, FLAC__bool error_on_compression_fail);
+static int EncoderSession_finish_error(EncoderSession *e);
+static FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t options);
+static FLAC__bool EncoderSession_process(EncoderSession *e, const FLAC__int32 * const buffer[], uint32_t samples);
+static FLAC__bool EncoderSession_format_is_iff(const EncoderSession *e);
+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, uint32_t sample_rate, FLAC__uint64 skip, FLAC__uint64 total_samples_in_input);
+static FLAC__bool verify_metadata(const EncoderSession *e, FLAC__StreamMetadata **metadata, uint32_t num_metadata);
+static FLAC__bool format_input(FLAC__int32 *dest[], uint32_t wide_samples, FLAC__bool is_big_endian, FLAC__bool is_unsigned_samples, uint32_t channels, uint32_t bps, uint32_t shift, size_t *channel_map);
+static void encoder_progress_callback(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, uint32_t frames_written, uint32_t 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, uint32_t sample_rate, 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_bytes(FILE *f, FLAC__byte *buf, size_t n, FLAC__bool eof_ok, const char *fn);
+static FLAC__bool read_uint16(FILE *f, FLAC__bool big_endian, FLAC__uint16 *val, const char *fn);
+static FLAC__bool read_uint32(FILE *f, FLAC__bool big_endian, FLAC__uint32 *val, const char *fn);
+static FLAC__bool read_uint64(FILE *f, FLAC__bool big_endian, FLAC__uint64 *val, const char *fn);
+static FLAC__bool read_sane_extended(FILE *f, FLAC__uint32 *val, const char *fn);
+static FLAC__bool fskip_ahead(FILE *f, FLAC__uint64 offset);
+static uint32_t count_channel_mask_bits(FLAC__uint32 mask);
+
+static FLAC__bool get_sample_info_raw(EncoderSession *e, encode_options_t options)
+{
+ e->info.sample_rate = options.format_options.raw.sample_rate;
+ e->info.channels = options.format_options.raw.channels;
+ e->info.bits_per_sample = options.format_options.raw.bps;
+ e->info.shift = 0;
+ e->info.bytes_per_wide_sample = options.format_options.raw.channels * ((options.format_options.raw.bps+7)/8);
+ e->info.is_unsigned_samples = options.format_options.raw.is_unsigned_samples;
+ e->info.is_big_endian = options.format_options.raw.is_big_endian;
+ e->info.channel_mask = 0;
+
+ return true;
+}
+
+static FLAC__bool get_sample_info_wave(EncoderSession *e, encode_options_t options)
+{
+ FLAC__bool got_fmt_chunk = false, got_data_chunk = false, got_ds64_chunk = false;
+ uint32_t sample_rate = 0, channels = 0, bps = 0, shift = 0, block_align = 0;
+ FLAC__uint32 channel_mask = 0;
+ FLAC__uint64 ds64_data_size = 0;
+
+ e->info.is_unsigned_samples = false;
+ e->info.is_big_endian = false;
+
+ if(e->format == FORMAT_WAVE64) {
+ /*
+ * lookahead[] already has "riff\x2E\x91\xCF\x11\xA5\xD6\x28\xDB", skip over remaining header
+ */
+ if(!fskip_ahead(e->fin, 16+8+16-12)) { /* riff GUID + riff size + WAVE GUID - lookahead */
+ flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping over remaining \"riff\" header\n", e->inbasefilename);
+ return false;
+ }
+ }
+ /* else lookahead[] already has "RIFFxxxxWAVE" or "RF64xxxxWAVE" */
+
+ while(!feof(e->fin) && !got_data_chunk) {
+ /* chunk IDs are 4 bytes for WAVE/RF64, 16 for Wave64 */
+ /* for WAVE/RF64 we want the 5th char zeroed so we can treat it like a C string */
+ char chunk_id[16] = { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' };
+
+ if(!read_bytes(e->fin, (FLAC__byte*)chunk_id, e->format==FORMAT_WAVE64?16:4, /*eof_ok=*/true, e->inbasefilename)) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: incomplete chunk identifier\n", e->inbasefilename);
+ return false;
+ }
+ if(feof(e->fin))
+ break;
+
+ if(e->format == FORMAT_RF64 && !memcmp(chunk_id, "ds64", 4)) { /* RF64 64-bit sizes chunk */
+ FLAC__uint32 xx, data_bytes;
+
+ if(got_ds64_chunk) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: file has multiple 'ds64' chunks\n", e->inbasefilename);
+ return false;
+ }
+ if(got_fmt_chunk) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: 'ds64' chunk appears after 'fmt ' or 'data' chunk\n", e->inbasefilename);
+ return false;
+ }
+
+ /* ds64 chunk size */
+ if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename))
+ return false;
+ data_bytes = xx;
+ if(data_bytes < 28) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: non-standard 'ds64' chunk has length = %u\n", e->inbasefilename, (uint32_t)data_bytes);
+ return false;
+ }
+ if(data_bytes & 1) /* should never happen, but enforce WAVE alignment rules */
+ data_bytes++;
+
+ /* RIFF 64-bit size, lo/hi */
+ if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename))
+ return false;
+ if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename))
+ return false;
+
+ /* 'data' 64-bit size */
+ if(!read_uint64(e->fin, /*big_endian=*/false, &ds64_data_size, e->inbasefilename))
+ return false;
+
+ data_bytes -= 16;
+
+ /* skip any extra data in the ds64 chunk */
+ if(!fskip_ahead(e->fin, data_bytes)) {
+ flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping over extra 'ds64' data\n", e->inbasefilename);
+ return false;
+ }
+
+ got_ds64_chunk = true;
+ }
+ else if(
+ !memcmp(chunk_id, "fmt ", 4) &&
+ (e->format!=FORMAT_WAVE64 || !memcmp(chunk_id, "fmt \xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 16))
+ ) { /* format chunk */
+ FLAC__uint16 x;
+ FLAC__uint32 xx, data_bytes;
+ FLAC__uint16 wFormatTag; /* wFormatTag word from the 'fmt ' chunk */
+
+ if(got_fmt_chunk) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: file has multiple 'fmt ' chunks\n", e->inbasefilename);
+ return false;
+ }
+
+ /* 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: chunk 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 uint32_t for bps <= 8 else signed.
+ */
+
+ /* fmt chunk size */
+ if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename))
+ return false;
+ data_bytes = xx;
+ if(e->format == FORMAT_WAVE64) {
+ /* other half of the size field should be 0 */
+ if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename))
+ return false;
+ if(xx) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: freakishly large Wave64 'fmt ' chunk has length = 0x%08X%08X\n", e->inbasefilename, (uint32_t)xx, (uint32_t)data_bytes);
+ return false;
+ }
+ /* subtract size of header */
+ if (data_bytes < 16+8) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: freakishly small Wave64 'fmt ' chunk has length = 0x%08X%08X\n", e->inbasefilename, (uint32_t)xx, (uint32_t)data_bytes);
+ return false;
+ }
+ data_bytes -= (16+8);
+ }
+ if(data_bytes < 16 || data_bytes > (UINT32_MAX-8)) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: non-standard 'fmt ' chunk has length = %u\n", e->inbasefilename, (uint32_t)data_bytes);
+ return false;
+ }
+ if(e->format != FORMAT_WAVE64) {
+ if(data_bytes & 1) /* should never happen, but enforce WAVE alignment rules */
+ data_bytes++;
+ }
+ else { /* Wave64 */
+ data_bytes = (data_bytes+7) & (~7u); /* should never happen, but enforce Wave64 alignment rules */
+ }
+
+ /* format code */
+ if(!read_uint16(e->fin, /*big_endian=*/false, &wFormatTag, e->inbasefilename))
+ return false;
+ if(wFormatTag != 1 /*WAVE_FORMAT_PCM*/ && wFormatTag != 65534 /*WAVE_FORMAT_EXTENSIBLE*/) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: unsupported format type %u\n", e->inbasefilename, (uint32_t)wFormatTag);
+ return false;
+ }
+
+ /* number of channels */
+ if(!read_uint16(e->fin, /*big_endian=*/false, &x, e->inbasefilename))
+ return false;
+ channels = (uint32_t)x;
+
+ /* sample rate */
+ if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename))
+ return false;
+ sample_rate = xx;
+
+ /* avg bytes per second (ignored) */
+ if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename))
+ return false;
+ /* block align */
+ if(!read_uint16(e->fin, /*big_endian=*/false, &x, e->inbasefilename))
+ return false;
+ block_align = x;
+ /* bits per sample */
+ if(!read_uint16(e->fin, /*big_endian=*/false, &x, e->inbasefilename))
+ return false;
+ bps = (uint32_t)x;
+
+ e->info.is_unsigned_samples = (bps <= 8);
+
+ if(wFormatTag == 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", e->inbasefilename, (uint32_t)wFormatTag, bps);
+ if(e->treat_warnings_as_errors)
+ return false;
+ }
+ 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", e->inbasefilename, (uint32_t)wFormatTag, bps);
+ return false;
+ }
+ }
+ if((bps+7)/8 * channels != block_align) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: legacy WAVE file has block alignment=%u, bits-per-sample=%u, channels=%u\n", e->inbasefilename, (uint32_t)wFormatTag, block_align, bps, channels);
+ return false;
+ }
+ if(channels > 2 && !options.channel_map_none) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: WAVE has >2 channels but is not WAVE_FORMAT_EXTENSIBLE; cannot assign channels\n", e->inbasefilename);
+ return false;
+ }
+ 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", e->inbasefilename, (uint32_t)data_bytes);
+ return false;
+ }
+ /* cbSize */
+ if(!read_uint16(e->fin, /*big_endian=*/false, &x, e->inbasefilename))
+ return false;
+ if(x < 22) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: invalid WAVEFORMATEXTENSIBLE chunk with cbSize %u\n", e->inbasefilename, (uint32_t)x);
+ return false;
+ }
+ /* valid bps */
+ if(!read_uint16(e->fin, /*big_endian=*/false, &x, e->inbasefilename))
+ return false;
+ if((uint32_t)x > bps) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: invalid WAVEFORMATEXTENSIBLE chunk with wValidBitsPerSample (%u) > wBitsPerSample (%u)\n", e->inbasefilename, (uint32_t)x, bps);
+ return false;
+ }
+ shift = bps - (uint32_t)x;
+ /* channel mask */
+ if(!read_uint32(e->fin, /*big_endian=*/false, &channel_mask, e->inbasefilename))
+ return false;
+
+ if(count_channel_mask_bits(channel_mask) > channels) {
+ flac__utils_printf(stderr, 1, "%s: WARNING: WAVEFORMATEXTENSIBLE chunk: channel mask 0x%04X has extra bits for non-existant channels (#channels=%u)\n", e->inbasefilename, (uint32_t)channel_mask, channels);
+ if(e->treat_warnings_as_errors)
+ return false;
+ }
+ /* first part of GUID */
+ if(!read_uint16(e->fin, /*big_endian=*/false, &x, e->inbasefilename))
+ return false;
+ if(x != 1) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: unsupported WAVEFORMATEXTENSIBLE chunk with non-PCM format %u\n", e->inbasefilename, (uint32_t)x);
+ return false;
+ }
+ data_bytes -= 26;
+ }
+
+ e->info.bytes_per_wide_sample = channels * (bps / 8);
+
+ /* skip any extra data in the fmt chunk */
+ if(!fskip_ahead(e->fin, data_bytes)) {
+ flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping over extra 'fmt' data\n", e->inbasefilename);
+ return false;
+ }
+
+ got_fmt_chunk = true;
+ }
+ else if(
+ !memcmp(chunk_id, "data", 4) &&
+ (e->format!=FORMAT_WAVE64 || !memcmp(chunk_id, "data\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 16))
+ ) { /* data chunk */
+ FLAC__uint32 xx;
+ FLAC__uint64 data_bytes;
+
+ if(!got_fmt_chunk) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: got 'data' chunk before 'fmt' chunk\n", e->inbasefilename);
+ return false;
+ }
+
+ /* data size */
+ if(e->format != FORMAT_WAVE64) {
+ if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename))
+ return false;
+ data_bytes = xx;
+ }
+ else { /* Wave64 */
+ if(!read_uint64(e->fin, /*big_endian=*/false, &data_bytes, e->inbasefilename))
+ return false;
+ /* subtract size of header */
+ if (data_bytes < 16+8) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: freakishly small Wave64 'data' chunk has length = 0x00000000%08X\n", e->inbasefilename, (uint32_t)data_bytes);
+ return false;
+ }
+ data_bytes -= (16+8);
+ }
+ if(e->format == FORMAT_RF64) {
+ if(!got_ds64_chunk) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: RF64 file has no 'ds64' chunk before 'data' chunk\n", e->inbasefilename);
+ return false;
+ }
+ if(data_bytes == 0xffffffff)
+ data_bytes = ds64_data_size;
+ }
+ if(options.ignore_chunk_sizes) {
+ if(data_bytes) {
+ flac__utils_printf(stderr, 1, "%s: WARNING: 'data' chunk has non-zero size, using --ignore-chunk-sizes is probably a bad idea\n", e->inbasefilename, chunk_id);
+ if(e->treat_warnings_as_errors)
+ return false;
+ }
+ data_bytes = (FLAC__uint64)0 - (FLAC__uint64)e->info.bytes_per_wide_sample; /* max out data_bytes; we'll use EOF as signal to stop reading */
+ }
+ else if(0 == data_bytes) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: 'data' chunk has size of 0\n", e->inbasefilename);
+ return false;
+ }
+
+ e->fmt.iff.data_bytes = data_bytes;
+
+ got_data_chunk = true;
+ break;
+ }
+ else {
+ FLAC__uint32 xx;
+ FLAC__uint64 skip;
+ if(!options.format_options.iff.foreign_metadata) {
+ if(e->format != FORMAT_WAVE64)
+ flac__utils_printf(stderr, 1, "%s: WARNING: skipping unknown chunk '%s' (use --keep-foreign-metadata to keep)\n", e->inbasefilename, chunk_id);
+ else
+ flac__utils_printf(stderr, 1, "%s: WARNING: skipping unknown chunk %02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X (use --keep-foreign-metadata to keep)\n",
+ e->inbasefilename,
+ (uint32_t)((const uint8_t *)chunk_id)[3],
+ (uint32_t)((const uint8_t *)chunk_id)[2],
+ (uint32_t)((const uint8_t *)chunk_id)[1],
+ (uint32_t)((const uint8_t *)chunk_id)[0],
+ (uint32_t)((const uint8_t *)chunk_id)[5],
+ (uint32_t)((const uint8_t *)chunk_id)[4],
+ (uint32_t)((const uint8_t *)chunk_id)[7],
+ (uint32_t)((const uint8_t *)chunk_id)[6],
+ (uint32_t)((const uint8_t *)chunk_id)[9],
+ (uint32_t)((const uint8_t *)chunk_id)[8],
+ (uint32_t)((const uint8_t *)chunk_id)[10],
+ (uint32_t)((const uint8_t *)chunk_id)[11],
+ (uint32_t)((const uint8_t *)chunk_id)[12],
+ (uint32_t)((const uint8_t *)chunk_id)[13],
+ (uint32_t)((const uint8_t *)chunk_id)[14],
+ (uint32_t)((const uint8_t *)chunk_id)[15]
+ );
+ if(e->treat_warnings_as_errors)
+ return false;
+ }
+
+ /* chunk size */
+ if(e->format != FORMAT_WAVE64) {
+ if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename))
+ return false;
+ skip = xx;
+ skip += skip & 1;
+ }
+ else { /* Wave64 */
+ if(!read_uint64(e->fin, /*big_endian=*/false, &skip, e->inbasefilename))
+ return false;
+ skip = (skip+7) & (~(FLAC__uint64)7);
+ /* subtract size of header */
+ if (skip < 16+8) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: freakishly small Wave64 chunk has length = 0x00000000%08X\n", e->inbasefilename, (uint32_t)skip);
+ return false;
+ }
+ skip -= (16+8);
+ }
+ if(skip) {
+ if(!fskip_ahead(e->fin, skip)) {
+ flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping over chunk\n", e->inbasefilename);
+ return false;
+ }
+ }
+ }
+ }
+
+ if(!got_fmt_chunk) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: didn't find fmt chunk\n", e->inbasefilename);
+ return false;
+ }
+ if(!got_data_chunk) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: didn't find data chunk\n", e->inbasefilename);
+ return false;
+ }
+
+ e->info.sample_rate = sample_rate;
+ e->info.channels = channels;
+ e->info.bits_per_sample = bps;
+ e->info.shift = shift;
+ e->info.channel_mask = channel_mask;
+
+ return true;
+}
+
+static FLAC__bool get_sample_info_aiff(EncoderSession *e, encode_options_t options)
+{
+ FLAC__bool got_comm_chunk = false, got_ssnd_chunk = false;
+ uint32_t sample_rate = 0, channels = 0, bps = 0, shift = 0;
+ FLAC__uint64 sample_frames = 0;
+ FLAC__uint32 channel_mask = 0;
+
+ e->info.is_unsigned_samples = false;
+ e->info.is_big_endian = true;
+
+ /*
+ * lookahead[] already has "FORMxxxxAIFF", do chunks
+ */
+ while(!feof(e->fin) && !got_ssnd_chunk) {
+ 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 */
+ if(!read_bytes(e->fin, (FLAC__byte*)chunk_id, 4, /*eof_ok=*/true, e->inbasefilename)) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: incomplete chunk identifier\n", e->inbasefilename);
+ return false;
+ }
+ if(feof(e->fin))
+ break;
+
+ if(!memcmp(chunk_id, "COMM", 4)) { /* common chunk */
+ FLAC__uint16 x;
+ FLAC__uint32 xx;
+ uint64_t skip;
+ const FLAC__bool is_aifc = e->format == FORMAT_AIFF_C;
+ const FLAC__uint32 minimum_comm_size = (is_aifc? 22 : 18);
+
+ if(got_comm_chunk) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: file has multiple 'COMM' chunks\n", e->inbasefilename);
+ return false;
+ }
+
+ /* COMM chunk size */
+ if(!read_uint32(e->fin, /*big_endian=*/true, &xx, e->inbasefilename))
+ return false;
+ else if(xx < minimum_comm_size) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: non-standard %s 'COMM' chunk has length = %u\n", e->inbasefilename, is_aifc? "AIFF-C" : "AIFF", (uint32_t)xx);
+ return false;
+ }
+ 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", e->inbasefilename, is_aifc? "AIFF-C" : "AIFF", (uint32_t)xx, minimum_comm_size);
+ if(e->treat_warnings_as_errors)
+ return false;
+ }
+ skip = (xx-minimum_comm_size)+(xx & 1);
+
+ /* number of channels */
+ if(!read_uint16(e->fin, /*big_endian=*/true, &x, e->inbasefilename))
+ return false;
+ channels = (uint32_t)x;
+ if(channels > 2 && !options.channel_map_none) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: unsupported number of channels %u for AIFF\n", e->inbasefilename, channels);
+ return false;
+ }
+
+ /* number of sample frames */
+ if(!read_uint32(e->fin, /*big_endian=*/true, &xx, e->inbasefilename))
+ return false;
+ sample_frames = xx;
+
+ /* bits per sample */
+ if(!read_uint16(e->fin, /*big_endian=*/true, &x, e->inbasefilename))
+ return false;
+ bps = (uint32_t)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(e->fin, &xx, e->inbasefilename))
+ return false;
+ sample_rate = xx;
+
+ /* check compression type for AIFF-C */
+ if(is_aifc) {
+ if(!read_uint32(e->fin, /*big_endian=*/true, &xx, e->inbasefilename))
+ return false;
+ if(xx == 0x736F7774) /* "sowt" */
+ e->info.is_big_endian = 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", e->inbasefilename, (char)(xx>>24), (char)((xx>>16)&8), (char)((xx>>8)&8), (char)(xx&8));
+ return false;
+ }
+ }
+
+ /* 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.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 of channels %u for AIFF\n", e->inbasefilename, channels);
+ return false;
+ }
+
+ e->info.bytes_per_wide_sample = channels * (bps / 8);
+
+ /* skip any extra data in the COMM chunk */
+ if(!fskip_ahead(e->fin, skip)) {
+ flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping over extra COMM data\n", e->inbasefilename);
+ return false;
+ }
+
+ got_comm_chunk = true;
+ }
+ else if(!memcmp(chunk_id, "SSND", 4) && !got_ssnd_chunk) { /* sound data chunk */
+ FLAC__uint32 xx;
+ FLAC__uint64 data_bytes;
+ uint32_t offset = 0;
+
+ if(!got_comm_chunk) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: got 'SSND' chunk before 'COMM' chunk\n", e->inbasefilename);
+ return false;
+ }
+
+ /* SSND chunk size */
+ if(!read_uint32(e->fin, /*big_endian=*/true, &xx, e->inbasefilename))
+ return false;
+ data_bytes = xx;
+ if(options.ignore_chunk_sizes) {
+ if(data_bytes) {
+ flac__utils_printf(stderr, 1, "%s: WARNING: 'SSND' chunk has non-zero size, using --ignore-chunk-sizes is probably a bad idea\n", e->inbasefilename, chunk_id);
+ if(e->treat_warnings_as_errors)
+ return false;
+ }
+ data_bytes = (FLAC__uint64)0 - (FLAC__uint64)e->info.bytes_per_wide_sample; /* max out data_bytes; we'll use EOF as signal to stop reading */
+ }
+ else if(data_bytes <= 8) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: 'SSND' chunk has size <= 8\n", e->inbasefilename);
+ return false;
+ }
+ else {
+ data_bytes -= 8; /* discount the offset and block size fields */
+ }
+
+ /* offset */
+ if(!read_uint32(e->fin, /*big_endian=*/true, &xx, e->inbasefilename))
+ return false;
+ offset = xx;
+ data_bytes -= offset;
+
+ /* block size */
+ if(!read_uint32(e->fin, /*big_endian=*/true, &xx, e->inbasefilename))
+ return false;
+ if(xx && !options.ignore_chunk_sizes)
+ data_bytes -= (xx - (data_bytes % xx));
+ if(options.ignore_chunk_sizes) {
+ if(xx) {
+ flac__utils_printf(stderr, 1, "%s: WARNING: 'SSND' chunk has non-zero blocksize, using --ignore-chunk-sizes is probably a bad idea\n", e->inbasefilename, chunk_id);
+ if(e->treat_warnings_as_errors)
+ return false;
+ }
+ }
+
+ /* skip any SSND offset bytes */
+ if(!fskip_ahead(e->fin, offset)) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: skipping offset in SSND chunk\n", e->inbasefilename);
+ return false;
+ }
+
+ e->fmt.iff.data_bytes = data_bytes;
+
+ got_ssnd_chunk = true;
+ }
+ else {
+ FLAC__uint32 xx;
+ if(!options.format_options.iff.foreign_metadata) {
+ flac__utils_printf(stderr, 1, "%s: WARNING: skipping unknown chunk '%s' (use --keep-foreign-metadata to keep)\n", e->inbasefilename, chunk_id);
+ if(e->treat_warnings_as_errors)
+ return false;
+ }
+
+ /* chunk size */
+ if(!read_uint32(e->fin, /*big_endian=*/true, &xx, e->inbasefilename))
+ return false;
+ else {
+ uint64_t skip = xx + (xx & 1);
+
+ FLAC__ASSERT(skip <= LONG_MAX);
+ if(!fskip_ahead(e->fin, skip)) {
+ flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping over chunk\n", e->inbasefilename);
+ return false;
+ }
+ }
+ }
+ }
+
+ if(!got_comm_chunk) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: didn't find COMM chunk\n", e->inbasefilename);
+ return false;
+ }
+ if(!got_ssnd_chunk && sample_frames) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: didn't find SSND chunk\n", e->inbasefilename);
+ return false;
+ }
+
+ e->info.sample_rate = sample_rate;
+ e->info.channels = channels;
+ e->info.bits_per_sample = bps;
+ e->info.shift = shift;
+ e->info.channel_mask = channel_mask;
+
+ return true;
+}
+
+static FLAC__bool get_sample_info_flac(EncoderSession *e)
+{
+ if (!(
+ FLAC__stream_decoder_set_md5_checking(e->fmt.flac.decoder, false) &&
+ FLAC__stream_decoder_set_metadata_respond_all(e->fmt.flac.decoder)
+ )) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: setting up decoder for FLAC input\n", e->inbasefilename);
+ return false;
+ }
+
+ if (e->format == FORMAT_OGGFLAC) {
+ if (FLAC__stream_decoder_init_ogg_stream(e->fmt.flac.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=*/e) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: initializing decoder for Ogg FLAC input, state = %s\n", e->inbasefilename, FLAC__stream_decoder_get_resolved_state_string(e->fmt.flac.decoder));
+ return false;
+ }
+ }
+ else if (FLAC__stream_decoder_init_stream(e->fmt.flac.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=*/e) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: initializing decoder for FLAC input, state = %s\n", e->inbasefilename, FLAC__stream_decoder_get_resolved_state_string(e->fmt.flac.decoder));
+ return false;
+ }
+
+ if (!FLAC__stream_decoder_process_until_end_of_metadata(e->fmt.flac.decoder) || e->fmt.flac.client_data.fatal_error) {
+ if (e->fmt.flac.client_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", e->inbasefilename);
+ else
+ flac__utils_printf(stderr, 1, "%s: ERROR: reading metadata in FLAC input, state = %s\n", e->inbasefilename, FLAC__stream_decoder_get_resolved_state_string(e->fmt.flac.decoder));
+ return false;
+ }
+
+ if (e->fmt.flac.client_data.num_metadata_blocks == 0) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: reading metadata in FLAC input, got no metadata blocks\n", e->inbasefilename);
+ return false;
+ }
+ else if (e->fmt.flac.client_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", e->inbasefilename);
+ return false;
+ }
+ else if (e->fmt.flac.client_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", e->inbasefilename);
+ return false;
+ }
+
+ e->info.sample_rate = e->fmt.flac.client_data.metadata_blocks[0]->data.stream_info.sample_rate;
+ e->info.channels = e->fmt.flac.client_data.metadata_blocks[0]->data.stream_info.channels;
+ e->info.bits_per_sample = e->fmt.flac.client_data.metadata_blocks[0]->data.stream_info.bits_per_sample;
+ e->info.shift = 0;
+ e->info.bytes_per_wide_sample = 0;
+ e->info.is_unsigned_samples = false; /* not applicable for FLAC input */
+ e->info.is_big_endian = false; /* not applicable for FLAC input */
+ e->info.channel_mask = 0;
+
+ return true;
+}
+
+/*
+ * public routines
+ */
+int flac__encode_file(FILE *infile, FLAC__off_t infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, uint32_t lookahead_length, encode_options_t options)
+{
+ EncoderSession encoder_session;
+ size_t channel_map[FLAC__MAX_CHANNELS];
+
+ if(!EncoderSession_construct(&encoder_session, options, infilesize, infile, infilename, outfilename, lookahead, lookahead_length))
+ 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;
+ }
+
+ /* read foreign metadata if requested */
+ if(EncoderSession_format_is_iff(&encoder_session) && options.format_options.iff.foreign_metadata) {
+ const char *error;
+ if(!(
+ options.format == FORMAT_WAVE || options.format == FORMAT_RF64?
+ flac__foreign_metadata_read_from_wave(options.format_options.iff.foreign_metadata, infilename, &error) :
+ options.format == FORMAT_WAVE64?
+ flac__foreign_metadata_read_from_wave64(options.format_options.iff.foreign_metadata, infilename, &error) :
+ flac__foreign_metadata_read_from_aiff(options.format_options.iff.foreign_metadata, infilename, &error)
+ )) {
+ if(options.relaxed_foreign_metadata_handling) {
+ flac__utils_printf(stderr, 1, "%s: WARNING reading foreign metadata: %s\n", encoder_session.inbasefilename, error);
+ if(encoder_session.treat_warnings_as_errors)
+ return EncoderSession_finish_error(&encoder_session);
+ }
+ else {
+ flac__utils_printf(stderr, 1, "%s: ERROR reading foreign metadata: %s\n", encoder_session.inbasefilename, error);
+ return EncoderSession_finish_error(&encoder_session);
+ }
+ }
+ }
+
+ /* initialize encoder session with info about the audio (channels/bps/resolution/endianness/etc) */
+ switch(options.format) {
+ case FORMAT_RAW:
+ if(!get_sample_info_raw(&encoder_session, options))
+ return EncoderSession_finish_error(&encoder_session);
+ break;
+ case FORMAT_WAVE:
+ case FORMAT_WAVE64:
+ case FORMAT_RF64:
+ if(!get_sample_info_wave(&encoder_session, options))
+ return EncoderSession_finish_error(&encoder_session);
+ break;
+ case FORMAT_AIFF:
+ case FORMAT_AIFF_C:
+ if(!get_sample_info_aiff(&encoder_session, options))
+ return EncoderSession_finish_error(&encoder_session);
+ break;
+ case FORMAT_FLAC:
+ case FORMAT_OGGFLAC:
+ /*
+ * set up FLAC decoder for the input
+ */
+ if (0 == (encoder_session.fmt.flac.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(!get_sample_info_flac(&encoder_session))
+ return EncoderSession_finish_error(&encoder_session);
+ break;
+ default:
+ FLAC__ASSERT(0);
+ /* double protection */
+ return EncoderSession_finish_error(&encoder_session);
+ }
+
+ /* some more checks */
+ if(encoder_session.info.channels == 0 || encoder_session.info.channels > FLAC__MAX_CHANNELS) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: unsupported number of channels %u\n", encoder_session.inbasefilename, encoder_session.info.channels);
+ return EncoderSession_finish_error(&encoder_session);
+ }
+ if(!FLAC__format_sample_rate_is_valid(encoder_session.info.sample_rate)) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: unsupported sample rate %u\n", encoder_session.inbasefilename, encoder_session.info.sample_rate);
+ return EncoderSession_finish_error(&encoder_session);
+ }
+ if(encoder_session.info.bits_per_sample-encoder_session.info.shift < 4 || encoder_session.info.bits_per_sample-encoder_session.info.shift > 32) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: unsupported bits-per-sample %u\n", encoder_session.inbasefilename, encoder_session.info.bits_per_sample-encoder_session.info.shift);
+ return EncoderSession_finish_error(&encoder_session);
+ }
+
+ {
+ FLAC__uint64 total_samples_in_input; /* WATCHOUT: may be 0 to mean "unknown" */
+ FLAC__uint64 skip;
+ FLAC__uint64 until; /* a value of 0 mean end-of-stream (i.e. --until=-0) */
+ uint32_t consecutive_eos_count = 0;
+
+ switch(options.format) {
+ case FORMAT_RAW:
+ if(infilesize < 0)
+ total_samples_in_input = 0;
+ else
+ total_samples_in_input = (FLAC__uint64)infilesize / encoder_session.info.bytes_per_wide_sample;
+ break;
+ case FORMAT_WAVE:
+ case FORMAT_WAVE64:
+ case FORMAT_RF64:
+ case FORMAT_AIFF:
+ case FORMAT_AIFF_C:
+ /* truncation in the division removes any padding byte that was counted in encoder_session.fmt.iff.data_bytes */
+ total_samples_in_input = encoder_session.fmt.iff.data_bytes / encoder_session.info.bytes_per_wide_sample;
+
+ /* check for chunks trailing the audio data */
+ if(!options.ignore_chunk_sizes && !options.format_options.iff.foreign_metadata
+ && infilesize != (FLAC__off_t)(-1)) {
+ FLAC__off_t current_position = ftello(encoder_session.fin);
+ if(current_position > 0) {
+ FLAC__uint64 end_of_data_chunk = current_position + encoder_session.fmt.iff.data_bytes;
+ if(end_of_data_chunk < (FLAC__uint64)infilesize) {
+ flac__utils_printf(stderr, 1, "%s: WARNING: there is data trailing the audio data. Use --keep-foreign-metadata or --ignore-chunk-sizes to keep it\n", encoder_session.inbasefilename);
+ if(encoder_session.treat_warnings_as_errors)
+ return EncoderSession_finish_error(&encoder_session);
+ }
+ else if(end_of_data_chunk > (FLAC__uint64)infilesize) {
+ flac__utils_printf(stderr, 1, "%s: WARNING: the length of the data chunk overruns the end of the file. Please consult the manual on the --ignore-chunk-sizes option\n", encoder_session.inbasefilename);
+ if(encoder_session.treat_warnings_as_errors)
+ return EncoderSession_finish_error(&encoder_session);
+ }
+ }
+ }
+ break;
+ case FORMAT_FLAC:
+ case FORMAT_OGGFLAC:
+ total_samples_in_input = encoder_session.fmt.flac.client_data.metadata_blocks[0]->data.stream_info.total_samples;
+ break;
+ default:
+ FLAC__ASSERT(0);
+ /* double protection */
+ return EncoderSession_finish_error(&encoder_session);
+ }
+
+ /*
+ * now that we know the sample rate, canonicalize the
+ * --skip string to an absolute sample number:
+ */
+ if(!flac__utils_canonicalize_skip_until_specification(&options.skip_specification, encoder_session.info.sample_rate)) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: value of --skip is too large\n", encoder_session.inbasefilename, encoder_session.info.bits_per_sample-encoder_session.info.shift);
+ return EncoderSession_finish_error(&encoder_session);
+ }
+ FLAC__ASSERT(options.skip_specification.value.samples >= 0);
+ skip = (FLAC__uint64)options.skip_specification.value.samples;
+
+ /*
+ * now that we possibly know the input size, canonicalize the
+ * --until string to an absolute sample number:
+ */
+ if(!canonicalize_until_specification(&options.until_specification, encoder_session.inbasefilename, encoder_session.info.sample_rate, skip, total_samples_in_input))
+ return EncoderSession_finish_error(&encoder_session);
+ until = (FLAC__uint64)options.until_specification.value.samples;
+
+ /* adjust encoding parameters based on skip and until values */
+ switch(options.format) {
+ case FORMAT_RAW:
+ FLAC__ASSERT(sizeof(FLAC__off_t) == 8);
+ if(skip >= INT64_MAX / encoder_session.info.bytes_per_wide_sample) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: value of --skip is too large\n", encoder_session.inbasefilename, encoder_session.info.bits_per_sample-encoder_session.info.shift);
+ return EncoderSession_finish_error(&encoder_session);
+ }
+ infilesize -= (FLAC__off_t)skip * encoder_session.info.bytes_per_wide_sample;
+ encoder_session.total_samples_to_encode = total_samples_in_input - skip;
+ break;
+ case FORMAT_WAVE:
+ case FORMAT_WAVE64:
+ case FORMAT_RF64:
+ case FORMAT_AIFF:
+ case FORMAT_AIFF_C:
+ FLAC__ASSERT(sizeof(FLAC__off_t) == 8);
+ if(skip >= INT64_MAX / encoder_session.info.bytes_per_wide_sample) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: value of --skip is too large\n", encoder_session.inbasefilename, encoder_session.info.bits_per_sample-encoder_session.info.shift);
+ return EncoderSession_finish_error(&encoder_session);
+ }
+ encoder_session.fmt.iff.data_bytes -= skip * encoder_session.info.bytes_per_wide_sample;
+ if(options.ignore_chunk_sizes) {
+ encoder_session.total_samples_to_encode = 0;
+ FLAC__ASSERT(0 == until);
+ }
+ else {
+ encoder_session.total_samples_to_encode = total_samples_in_input - skip;
+ }
+ break;
+ case FORMAT_FLAC:
+ case FORMAT_OGGFLAC:
+ encoder_session.total_samples_to_encode = total_samples_in_input - skip;
+ break;
+ default:
+ FLAC__ASSERT(0);
+ /* double protection */
+ return EncoderSession_finish_error(&encoder_session);
+ }
+ if(until > 0) {
+ const FLAC__uint64 trim = total_samples_in_input - until;
+ FLAC__ASSERT(total_samples_in_input > 0);
+ if(options.format == FORMAT_RAW)
+ infilesize -= (FLAC__off_t)trim * encoder_session.info.bytes_per_wide_sample;
+ else if(EncoderSession_format_is_iff(&encoder_session))
+ encoder_session.fmt.iff.data_bytes -= trim * encoder_session.info.bytes_per_wide_sample;
+ encoder_session.total_samples_to_encode -= trim;
+ }
+ switch(options.format) {
+ case FORMAT_RAW:
+ encoder_session.unencoded_size = encoder_session.total_samples_to_encode * encoder_session.info.bytes_per_wide_sample;
+ break;
+ case FORMAT_WAVE:
+ /* +44 for the size of the WAVE 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 * encoder_session.info.bytes_per_wide_sample + 44;
+ break;
+ case FORMAT_WAVE64:
+ /* +44 for the size of the WAVE 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 * encoder_session.info.bytes_per_wide_sample + 104;
+ break;
+ case FORMAT_RF64:
+ /* +72 for the size of the RF64 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 * encoder_session.info.bytes_per_wide_sample + 80;
+ break;
+ case FORMAT_AIFF:
+ case FORMAT_AIFF_C:
+ /* +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 * encoder_session.info.bytes_per_wide_sample + 54;
+ break;
+ case FORMAT_FLAC:
+ case FORMAT_OGGFLAC:
+ if(infilesize < 0)
+ /* if we don't know, use 0 as hint to progress indicator (which is the only place this is used): */
+ encoder_session.unencoded_size = 0;
+ else if(skip == 0 && until == 0)
+ encoder_session.unencoded_size = (FLAC__uint64)infilesize;
+ else if(total_samples_in_input)
+ encoder_session.unencoded_size = (FLAC__uint64)infilesize * encoder_session.total_samples_to_encode / total_samples_in_input;
+ else
+ encoder_session.unencoded_size = (FLAC__uint64)infilesize;
+ break;
+ default:
+ FLAC__ASSERT(0);
+ /* double protection */
+ return EncoderSession_finish_error(&encoder_session);
+ }
+
+ if(encoder_session.total_samples_to_encode == 0) {
+ encoder_session.unencoded_size = 0;
+ flac__utils_printf(stderr, 2, "(No runtime statistics possible; please wait for encoding to finish...)\n");
+ }
+
+ if(options.format == FORMAT_FLAC || options.format == FORMAT_OGGFLAC)
+ encoder_session.fmt.flac.client_data.samples_left_to_process = encoder_session.total_samples_to_encode;
+
+ stats_new_file();
+ /* init the encoder */
+ if(!EncoderSession_init_encoder(&encoder_session, options))
+ return EncoderSession_finish_error(&encoder_session);
+
+ /* skip over any samples as requested */
+ if(skip > 0) {
+ switch(options.format) {
+ case FORMAT_RAW:
+ {
+ uint32_t skip_bytes = encoder_session.info.bytes_per_wide_sample * (uint32_t)skip;
+ if(skip_bytes > lookahead_length) {
+ skip_bytes -= lookahead_length;
+ lookahead_length = 0;
+ if(!fskip_ahead(encoder_session.fin, 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;
+ }
+ }
+ break;
+ case FORMAT_WAVE:
+ case FORMAT_WAVE64:
+ case FORMAT_RF64:
+ case FORMAT_AIFF:
+ case FORMAT_AIFF_C:
+ if(!fskip_ahead(encoder_session.fin, skip * encoder_session.info.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);
+ }
+ break;
+ case FORMAT_FLAC:
+ case FORMAT_OGGFLAC:
+ /*
+ * 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
+ */
+ if(!FLAC__stream_decoder_seek_absolute(encoder_session.fmt.flac.decoder, 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(encoder_session.fmt.flac.decoder));
+ return EncoderSession_finish_error(&encoder_session);
+ }
+ break;
+ default:
+ FLAC__ASSERT(0);
+ /* double protection */
+ return EncoderSession_finish_error(&encoder_session);
+ }
+ }
+
+ /*
+ * now do samples from the file
+ */
+ switch(options.format) {
+ case FORMAT_RAW:
+ if(infilesize < 0) {
+ size_t bytes_read;
+ while(!feof(infile)) {
+ if(lookahead_length > 0) {
+ FLAC__ASSERT(lookahead_length < CHUNK_OF_SAMPLES * encoder_session.info.bytes_per_wide_sample);
+ memcpy(ubuffer.u8, lookahead, lookahead_length);
+ bytes_read = fread(ubuffer.u8+lookahead_length, sizeof(uint8_t), CHUNK_OF_SAMPLES * encoder_session.info.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(ubuffer.u8, sizeof(uint8_t), CHUNK_OF_SAMPLES * encoder_session.info.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 % encoder_session.info.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 {
+ uint32_t wide_samples = bytes_read / encoder_session.info.bytes_per_wide_sample;
+ if(!format_input(input_, wide_samples, encoder_session.info.is_big_endian, encoder_session.info.is_unsigned_samples, encoder_session.info.channels, encoder_session.info.bits_per_sample, encoder_session.info.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);
+ }
+ }
+ }
+ }
+ else {
+ size_t bytes_read;
+ 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 * encoder_session.info.bytes_per_wide_sample);
+ wanted = (size_t) min((FLAC__uint64)wanted, max_input_bytes - total_input_bytes_read);
+
+ if(lookahead_length > 0) {
+ if(lookahead_length <= wanted) {
+ memcpy(ubuffer.u8, lookahead, lookahead_length);
+ wanted -= lookahead_length;
+ bytes_read = lookahead_length;
+ }
+ else {
+ /* This happens when --until is used on a very short file */
+ FLAC__ASSERT(lookahead_length < CHUNK_OF_SAMPLES * encoder_session.info.bytes_per_wide_sample);
+ memcpy(ubuffer.u8, lookahead, wanted);
+ wanted = 0;
+ bytes_read = wanted;
+ }
+ if(wanted > 0) {
+ bytes_read += fread(ubuffer.u8+lookahead_length, sizeof(uint8_t), 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(ubuffer.u8, sizeof(uint8_t), 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 %" PRIu64 " samples, got %" PRIu64 " samples\n", encoder_session.inbasefilename, encoder_session.total_samples_to_encode, 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 % encoder_session.info.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 {
+ uint32_t wide_samples = bytes_read / encoder_session.info.bytes_per_wide_sample;
+ if(!format_input(input_, wide_samples, encoder_session.info.is_big_endian, encoder_session.info.is_unsigned_samples, encoder_session.info.channels, encoder_session.info.bits_per_sample, encoder_session.info.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);
+ }
+ total_input_bytes_read += bytes_read;
+ }
+ }
+ }
+ }
+ break;
+ case FORMAT_WAVE:
+ case FORMAT_WAVE64:
+ case FORMAT_RF64:
+ case FORMAT_AIFF:
+ case FORMAT_AIFF_C:
+ while(encoder_session.fmt.iff.data_bytes > 0) {
+ const size_t bytes_to_read =
+ (size_t) min (sizeof (ubuffer.u8),
+ min (encoder_session.fmt.iff.data_bytes,
+ CHUNK_OF_SAMPLES * (uint64_t) encoder_session.info.bytes_per_wide_sample));
+ size_t bytes_read = fread(ubuffer.u8, sizeof(uint8_t), bytes_to_read, 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.ignore_chunk_sizes) {
+ flac__utils_printf(stderr, 1, "%s: INFO: hit EOF with --ignore-chunk-sizes, got %" PRIu64 " samples\n", encoder_session.inbasefilename, encoder_session.samples_written);
+ }
+ else {
+ flac__utils_printf(stderr, 1, "%s: WARNING: unexpected EOF; expected %" PRIu64 " samples, got %" PRIu64 " samples\n", encoder_session.inbasefilename, encoder_session.total_samples_to_encode, encoder_session.samples_written);
+ if(encoder_session.treat_warnings_as_errors)
+ return EncoderSession_finish_error(&encoder_session);
+ }
+ encoder_session.fmt.iff.data_bytes = 0;
+ }
+ }
+ else {
+ if(bytes_read % encoder_session.info.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 {
+ uint32_t wide_samples = bytes_read / encoder_session.info.bytes_per_wide_sample;
+ if(!format_input(input_, wide_samples, encoder_session.info.is_big_endian, encoder_session.info.is_unsigned_samples, encoder_session.info.channels, encoder_session.info.bits_per_sample, encoder_session.info.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);
+ }
+ encoder_session.fmt.iff.data_bytes -= bytes_read;
+ }
+ }
+ }
+ break;
+ case FORMAT_FLAC:
+ case FORMAT_OGGFLAC:
+ consecutive_eos_count = 0;
+ while(!encoder_session.fmt.flac.client_data.fatal_error && encoder_session.fmt.flac.client_data.samples_left_to_process > 0) {
+ FLAC__StreamDecoderState decoder_state;
+ /* 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:
+ */
+ decoder_state = FLAC__stream_decoder_get_state(encoder_session.fmt.flac.decoder);
+ if(encoder_session.continue_through_decode_errors && decoder_state == FLAC__STREAM_DECODER_END_OF_STREAM)
+ break;
+
+ consecutive_eos_count = decoder_state == FLAC__STREAM_DECODER_END_OF_STREAM ? consecutive_eos_count + 1 : 0;
+
+ /* Exit loop if we get two or more consecutive FLAC__STREAM_DECODER_END_OF_STREAM events. */
+ if(consecutive_eos_count >= 2) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: %d consecutive FLAC__STREAM_DECODER_END_OF_STREAM events.\n", encoder_session.inbasefilename, consecutive_eos_count);
+ break;
+ }
+
+ if(decoder_state == FLAC__STREAM_DECODER_ABORTED || !FLAC__stream_decoder_process_single(encoder_session.fmt.flac.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(encoder_session.fmt.flac.decoder));
+ return EncoderSession_finish_error(&encoder_session);
+ }
+ }
+ if(encoder_session.fmt.flac.client_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(encoder_session.fmt.flac.decoder));
+ return EncoderSession_finish_error(&encoder_session);
+ }
+ break;
+ default:
+ FLAC__ASSERT(0);
+ /* double protection */
+ return EncoderSession_finish_error(&encoder_session);
+ }
+
+ }
+
+ return EncoderSession_finish_ok(
+ &encoder_session,
+ EncoderSession_format_is_iff(&encoder_session)? options.format_options.iff.foreign_metadata : 0,
+ options.error_on_compression_fail
+ );
+}
+
+FLAC__bool EncoderSession_construct(EncoderSession *e, encode_options_t options, FLAC__off_t infilesize, FILE *infile, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, uint32_t lookahead_length)
+{
+ uint32_t 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 = options.use_ogg;
+#endif
+ e->verify = options.verify;
+ e->treat_warnings_as_errors = options.treat_warnings_as_errors;
+ e->continue_through_decode_errors = options.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->total_samples_to_encode = 0;
+ e->unencoded_size = 0;
+ e->bytes_written = 0;
+ e->samples_written = 0;
+#if 0 /* in case time.h with clock() isn't available for some reason */
+ e->stats_frames_interval = 0;
+ e->old_frames_written = 0;
+#else
+ e->old_clock_t = 0;
+#endif
+ e->compression_ratio = 0.0;
+
+ memset(&e->info, 0, sizeof(e->info));
+
+ e->format = options.format;
+
+ switch(options.format) {
+ case FORMAT_RAW:
+ break;
+ case FORMAT_WAVE:
+ case FORMAT_WAVE64:
+ case FORMAT_RF64:
+ case FORMAT_AIFF:
+ case FORMAT_AIFF_C:
+ e->fmt.iff.data_bytes = 0;
+ break;
+ case FORMAT_FLAC:
+ case FORMAT_OGGFLAC:
+ e->fmt.flac.decoder = 0;
+ e->fmt.flac.client_data.filesize = infilesize;
+ e->fmt.flac.client_data.lookahead = lookahead;
+ e->fmt.flac.client_data.lookahead_length = lookahead_length;
+ e->fmt.flac.client_data.num_metadata_blocks = 0;
+ e->fmt.flac.client_data.samples_left_to_process = 0;
+ e->fmt.flac.client_data.fatal_error = false;
+ break;
+ default:
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ FLAC__ASSERT(0);
+#endif
+ /* double protection */
+ return false;
+ }
+
+ 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->format == FORMAT_FLAC || e->format == FORMAT_OGGFLAC) {
+ size_t i;
+ if(e->fmt.flac.decoder)
+ FLAC__stream_decoder_delete(e->fmt.flac.decoder);
+ e->fmt.flac.decoder = 0;
+ for(i = 0; i < e->fmt.flac.client_data.num_metadata_blocks; i++)
+ FLAC__metadata_object_delete(e->fmt.flac.client_data.metadata_blocks[i]);
+ e->fmt.flac.client_data.num_metadata_blocks = 0;
+ }
+
+ 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, foreign_metadata_t *foreign_metadata, FLAC__bool error_on_compression_fail)
+{
+ 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;
+ }
+
+ /*@@@@@@ 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;
+ }
+ }
+
+ if (e->compression_ratio >= 1.0 && error_on_compression_fail) {
+ flac__utils_printf(stderr, 1,
+ "FAILURE: Compression failed (ratio %0.3f, should be < 1.0).\n"
+ "This happens for some files for one or more of the following reasons:\n"
+ " * Recompressing an existing FLAC from a higher to a lower compression setting.\n"
+ " * Insufficient input data (e.g. very short files, < 10000 frames).\n"
+ " * The audio data is not compressible (e.g. a full range white noise signal).\n"
+ , e->compression_ratio);
+ ret = 1;
+ }
+
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ /* Always delete output file when fuzzing */
+ flac_unlink(e->outfilename);
+#endif
+
+ 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);
+ EncoderSession_destroy(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 */
+ /* Windows cannot unlink an open file, so close it first */
+ EncoderSession_destroy(e);
+ flac_unlink(e->outfilename);
+ }
+ else
+ EncoderSession_destroy(e);
+
+ return 1;
+}
+
+typedef struct {
+ uint32_t 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)
+{
+ uint32_t 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_nofree_muladd2_(m->metadata, sizeof(*m->metadata), /*times (*/m->num_metadata, /*+*/1/*)*/)))
+ return false;
+ m->metadata = (FLAC__StreamMetadata**)x;
+ if(0 == (x = safe_realloc_nofree_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)
+{
+ const uint32_t channels = e->info.channels;
+ const uint32_t bps = e->info.bits_per_sample - e->info.shift;
+ const uint32_t sample_rate = e->info.sample_rate;
+ FLACDecoderData *flac_decoder_data = (e->format == FORMAT_FLAC || e->format == FORMAT_OGGFLAC)? &e->fmt.flac.client_data : 0;
+ FLAC__StreamMetadata padding;
+ FLAC__StreamMetadata **metadata = 0;
+ static_metadata_t static_metadata;
+ uint32_t num_metadata = 0, ic;
+ 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;
+
+ 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, sample_rate, 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
+ */
+ {
+ uint32_t i;
+ /*
+ * 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], &e->info.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 || (e->info.channel_mask && !flac__utils_set_channel_mask_tag(vc, e->info.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(cs->num_tracks > 0 && 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) {
+ if(sample_rate == 0)
+ p = FLAC_ENCODE__DEFAULT_PADDING;
+ else
+ p = e->total_samples_to_encode / sample_rate < 20*60? FLAC_ENCODE__DEFAULT_PADDING : FLAC_ENCODE__DEFAULT_PADDING*8;
+ }
+ if(p > 0)
+ p += (e->replay_gain ? GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED : 0);
+ p = min(p, (int)((1u << FLAC__STREAM_METADATA_LENGTH_LEN) - 1));
+ 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
+ */
+ const foreign_metadata_t *foreign_metadata = EncoderSession_format_is_iff(e)? options.format_options.iff.foreign_metadata : 0;
+ uint32_t i;
+
+ 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(e->info.channel_mask) {
+ options.vorbis_comment_with_channel_mask_tag = FLAC__metadata_object_clone(options.vorbis_comment);
+ if(!flac__utils_set_channel_mask_tag(options.vorbis_comment_with_channel_mask_tag, e->info.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_with_channel_mask_tag, /*needs_delete=*/true);
+ }
+ else
+ 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;
+ }
+ }
+ if(options.padding != 0) {
+ padding.is_last = false; /* the encoder will set this for us */
+ padding.type = FLAC__METADATA_TYPE_PADDING;
+ if(sample_rate == 0)
+ padding.length = (uint32_t)(options.padding>0? options.padding : FLAC_ENCODE__DEFAULT_PADDING) + (e->replay_gain ? GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED : 0);
+ else
+ padding.length = (uint32_t)(options.padding>0? options.padding : (e->total_samples_to_encode / sample_rate < 20*60? FLAC_ENCODE__DEFAULT_PADDING : FLAC_ENCODE__DEFAULT_PADDING*8)) + (e->replay_gain ? GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED : 0);
+ padding.length = min(padding.length, (1u << FLAC__STREAM_METADATA_LENGTH_LEN) - 1);
+ 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(ic = 0; ic < options.num_compression_settings; ic++) {
+ switch(options.compression_settings[ic].type) {
+ case CST_BLOCKSIZE:
+ FLAC__stream_encoder_set_blocksize(e->encoder, options.compression_settings[ic].value.t_unsigned);
+ break;
+ case CST_COMPRESSION_LEVEL:
+ FLAC__stream_encoder_set_compression_level(e->encoder, options.compression_settings[ic].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[ic].value.t_bool);
+ break;
+ case CST_LOOSE_MID_SIDE:
+ FLAC__stream_encoder_set_loose_mid_side_stereo(e->encoder, options.compression_settings[ic].value.t_bool);
+ break;
+ case CST_APODIZATION:
+ if(strlen(apodizations)+strlen(options.compression_settings[ic].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 {
+ safe_strncat(apodizations, options.compression_settings[ic].value.t_string, sizeof(apodizations));
+ safe_strncat(apodizations, ";", sizeof(apodizations));
+ }
+ break;
+ case CST_MAX_LPC_ORDER:
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ FLAC__stream_encoder_set_max_lpc_order(e->encoder, options.compression_settings[ic].value.t_unsigned);
+#endif
+ break;
+ case CST_QLP_COEFF_PRECISION:
+ FLAC__stream_encoder_set_qlp_coeff_precision(e->encoder, options.compression_settings[ic].value.t_unsigned);
+ break;
+ case CST_DO_QLP_COEFF_PREC_SEARCH:
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ FLAC__stream_encoder_set_do_qlp_coeff_prec_search(e->encoder, options.compression_settings[ic].value.t_bool);
+#endif
+ break;
+ case CST_DO_ESCAPE_CODING:
+ FLAC__stream_encoder_set_do_escape_coding(e->encoder, options.compression_settings[ic].value.t_bool);
+ break;
+ case CST_DO_EXHAUSTIVE_MODEL_SEARCH:
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ FLAC__stream_encoder_set_do_exhaustive_model_search(e->encoder, options.compression_settings[ic].value.t_bool);
+#endif
+ break;
+ case CST_MIN_RESIDUAL_PARTITION_ORDER:
+ FLAC__stream_encoder_set_min_residual_partition_order(e->encoder, options.compression_settings[ic].value.t_unsigned);
+ break;
+ case CST_MAX_RESIDUAL_PARTITION_ORDER:
+ FLAC__stream_encoder_set_max_residual_partition_order(e->encoder, options.compression_settings[ic].value.t_unsigned);
+ break;
+ case CST_RICE_PARAMETER_SEARCH_DIST:
+ FLAC__stream_encoder_set_rice_parameter_search_dist(e->encoder, options.compression_settings[ic].value.t_unsigned);
+ break;
+ }
+ }
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ if(*apodizations)
+ FLAC__stream_encoder_set_apodization(e->encoder, apodizations);
+#endif
+ 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_set_limit_min_bitrate(e->encoder, options.limit_min_bitrate);
+
+ 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);
+ }
+ else if(e->is_stdout) {
+ flac__utils_printf(stderr, 1, "%s: WARNING, cannot write back MD5 sum when encoding to stdout\n", e->inbasefilename);
+ if(e->treat_warnings_as_errors) {
+ static_metadata_clear(&static_metadata);
+ return 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;
+
+#if 0 /* in case time.h with clock() isn't available for some reason */
+ e->stats_frames_interval =
+ (FLAC__stream_encoder_get_do_exhaustive_model_search(e->encoder) && FLAC__stream_encoder_get_do_qlp_coeff_prec_search(e->encoder))? 0x1f :
+ (FLAC__stream_encoder_get_do_exhaustive_model_search(e->encoder) || FLAC__stream_encoder_get_do_qlp_coeff_prec_search(e->encoder))? 0x3f :
+ 0xff;
+#endif
+
+ static_metadata_clear(&static_metadata);
+
+ return true;
+}
+
+FLAC__bool EncoderSession_process(EncoderSession *e, const FLAC__int32 * const buffer[], uint32_t samples)
+{
+ if(e->replay_gain) {
+ if(!grabbag__replaygain_analyze(buffer, e->info.channels==2, e->info.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 EncoderSession_format_is_iff(const EncoderSession *e)
+{
+ return
+ e->format == FORMAT_WAVE ||
+ e->format == FORMAT_WAVE64 ||
+ e->format == FORMAT_RF64 ||
+ e->format == FORMAT_AIFF ||
+ e->format == FORMAT_AIFF_C;
+}
+
+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 FLAC__HAS_OGG
+ if(e->use_ogg)
+ return true;
+#endif
+
+ if(num_requested_seek_points < 0) {
+ 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->info.sample_rate, e->seek_table_template, &has_real_points))
+ return false;
+ }
+
+ if(0 != cuesheet) {
+ uint32_t 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, uint32_t sample_rate, FLAC__uint64 skip, FLAC__uint64 total_samples_in_input)
+{
+ /* convert from mm:ss.sss to sample number if necessary */
+ if(!flac__utils_canonicalize_skip_until_specification(spec, sample_rate)) {
+ flac__utils_printf(stderr, 1, "%s: ERROR, value of --until is too large\n", inbasefilename);
+ return false;
+ }
+
+ /* 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, uint32_t num_metadata)
+{
+ FLAC__bool metadata_picture_has_type1 = false;
+ FLAC__bool metadata_picture_has_type2 = false;
+ uint32_t 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[], uint32_t wide_samples, FLAC__bool is_big_endian, FLAC__bool is_unsigned_samples, uint32_t channels, uint32_t bps, uint32_t shift, size_t *channel_map)
+{
+ uint32_t wide_sample, sample, channel;
+ 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(channel = 0; channel < channels; channel++)
+ for(sample = channel, wide_sample = 0; wide_sample < wide_samples; wide_sample++, sample+=channels)
+ out[channel][wide_sample] = (FLAC__int32)ubuffer.u8[sample] - 0x80;
+ }
+ else {
+ for(channel = 0; channel < channels; channel++)
+ for(sample = channel, wide_sample = 0; wide_sample < wide_samples; wide_sample++, sample+=channels)
+ out[channel][wide_sample] = (FLAC__int32)ubuffer.s8[sample];
+ }
+ }
+ else if(bps == 16) {
+ if(is_unsigned_samples) {
+ if(is_big_endian != is_big_endian_host_) {
+ for(channel = 0; channel < channels; channel++)
+ for(sample = channel, wide_sample = 0; wide_sample < wide_samples; wide_sample++, sample+=channels)
+ out[channel][wide_sample] = (FLAC__int32)(ENDSWAP_16(ubuffer.u16[sample])) - 0x8000;
+ }
+ else {
+ for(channel = 0; channel < channels; channel++)
+ for(sample = channel, wide_sample = 0; wide_sample < wide_samples; wide_sample++, sample+=channels)
+ out[channel][wide_sample] = (FLAC__int32)ubuffer.u16[sample] - 0x8000;
+ }
+ }
+ else {
+ if(is_big_endian != is_big_endian_host_) {
+ for(channel = 0; channel < channels; channel++)
+ for(sample = channel, wide_sample = 0; wide_sample < wide_samples; wide_sample++, sample+=channels)
+ out[channel][wide_sample] = (int16_t)(ENDSWAP_16(ubuffer.s16[sample]));
+
+ }
+ else {
+ for(channel = 0; channel < channels; channel++)
+ for(sample = channel, wide_sample = 0; wide_sample < wide_samples; wide_sample++, sample+=channels)
+ out[channel][wide_sample] = ubuffer.s16[sample];
+ }
+ }
+ }
+ else if(bps == 24) {
+ if(!is_big_endian) {
+ if(is_unsigned_samples) {
+ for(channel = 0; channel < channels; channel++) {
+ uint32_t b = 3*channel;
+ for(wide_sample = 0; wide_sample < wide_samples; wide_sample++) {
+ uint32_t t;
+ t = ubuffer.u8[b];
+ t |= (uint32_t)(ubuffer.u8[b+1]) << 8;
+ t |= (uint32_t)(ubuffer.u8[b+2]) << 16;
+ out[channel][wide_sample] = (FLAC__int32)t - 0x800000;
+ b += 3*channels;
+ }
+ }
+ }
+ else {
+ for(channel = 0; channel < channels; channel++) {
+ uint32_t b = 3*channel;
+ for(wide_sample = 0; wide_sample < wide_samples; wide_sample++) {
+ uint32_t t;
+ t = ubuffer.u8[b];
+ t |= (uint32_t)(ubuffer.u8[b+1]) << 8;
+ t |= (uint32_t)((int32_t)(ubuffer.s8[b+2])) << 16;
+ out[channel][wide_sample] = t;
+ b += 3*channels;
+ }
+ }
+ }
+ }
+ else {
+ if(is_unsigned_samples) {
+ for(channel = 0; channel < channels; channel++) {
+ uint32_t b = 3*channel;
+ for(wide_sample = 0; wide_sample < wide_samples; wide_sample++) {
+ uint32_t t;
+ t = ubuffer.u8[b]; t <<= 8;
+ t |= ubuffer.u8[b+1]; t <<= 8;
+ t |= ubuffer.u8[b+2];
+ out[channel][wide_sample] = (FLAC__int32)t - 0x800000;
+ b += 3*channels;
+ }
+ }
+ }
+ else {
+ for(channel = 0; channel < channels; channel++) {
+ uint32_t b = 3*channel;
+ for(wide_sample = 0; wide_sample < wide_samples; wide_sample++) {
+ uint32_t t;
+ t = ubuffer.s8[b]; t <<= 8;
+ t |= ubuffer.u8[b+1]; t <<= 8;
+ t |= ubuffer.u8[b+2];
+ out[channel][wide_sample] = t;
+ b += 3*channels;
+ }
+ }
+ }
+ }
+ }
+ else if(bps == 32) {
+ if(is_unsigned_samples) {
+ if(is_big_endian != is_big_endian_host_) {
+ for(channel = 0; channel < channels; channel++)
+ for(sample = channel, wide_sample = 0; wide_sample < wide_samples; wide_sample++, sample+=channels)
+ out[channel][wide_sample] = ENDSWAP_32(ubuffer.u32[sample]) - 0x80000000;
+ }
+ else {
+ for(channel = 0; channel < channels; channel++)
+ for(sample = channel, wide_sample = 0; wide_sample < wide_samples; wide_sample++, sample+=channels)
+ out[channel][wide_sample] = ubuffer.u32[sample] - 0x80000000;
+ }
+ }
+ else {
+ if(is_big_endian != is_big_endian_host_) {
+ for(channel = 0; channel < channels; channel++)
+ for(sample = channel, wide_sample = 0; wide_sample < wide_samples; wide_sample++, sample+=channels)
+ out[channel][wide_sample] = ENDSWAP_32(ubuffer.s32[sample]);
+ }
+ else {
+ for(channel = 0; channel < channels; channel++)
+ for(sample = channel, wide_sample = 0; wide_sample < wide_samples; wide_sample++, sample+=channels)
+ out[channel][wide_sample] = ubuffer.s32[sample];
+ }
+ }
+ }
+ else {
+ flac__utils_printf(stderr, 1, "ERROR: unsupported input format\n");
+ return false;
+ }
+ 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, uint32_t frames_written, uint32_t total_frames_estimate, void *client_data)
+{
+ EncoderSession *e = (EncoderSession*)client_data;
+
+ const FLAC__uint64 uesize = e->unencoded_size;
+
+ (void)encoder, (void)total_frames_estimate, (void) frames_written;
+
+ e->bytes_written = bytes_written;
+ e->samples_written = samples_written;
+
+ e->progress = e->total_samples_to_encode ? (double)samples_written / (double)e->total_samples_to_encode : 0;
+ e->compression_ratio = (e->progress && uesize) ? (double)e->bytes_written / ((double)uesize * min(1.0, e->progress)) : 0;
+
+#if 0 /* in case time.h with clock() isn't available for some reason */
+ if(e->total_samples_to_encode > 0 && frames_written - e->old_frames_written > e->stats_frames_interval) {
+ print_stats(e);
+ e->old_frames_written = frames_written;
+ }
+#else
+ if(e->total_samples_to_encode > 0 && (clock() - e->old_clock_t) > (CLOCKS_PER_SEC/4)) {
+ print_stats(e);
+ e->old_clock_t = clock();
+ }
+
+#endif
+}
+
+FLAC__StreamDecoderReadStatus flac_decoder_read_callback(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+ size_t n = 0;
+ EncoderSession *e = (EncoderSession*)client_data;
+ FLACDecoderData *data = &e->fmt.flac.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, e->fin);
+ if(ferror(e->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)
+{
+ EncoderSession *e = (EncoderSession*)client_data;
+ (void)decoder;
+
+ if(fseeko(e->fin, (FLAC__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)
+{
+ EncoderSession *e = (EncoderSession*)client_data;
+ FLAC__off_t pos;
+ (void)decoder;
+
+ if((pos = ftello(e->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)
+{
+ const EncoderSession *e = (EncoderSession*)client_data;
+ const FLACDecoderData *data = &e->fmt.flac.client_data;
+ (void)decoder;
+
+ if(data->filesize < 0)
+ 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)
+{
+ EncoderSession *e = (EncoderSession*)client_data;
+ (void)decoder;
+
+ return feof(e->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)
+{
+ EncoderSession *e = (EncoderSession*)client_data;
+ FLACDecoderData *data = &e->fmt.flac.client_data;
+ FLAC__uint64 n = min(data->samples_left_to_process, frame->header.blocksize);
+ (void)decoder;
+
+ /* Do some checks */
+ if(frame->header.channels != e->info.channels) {
+ print_error_with_state(e, "ERROR: number of channels of input changed mid-stream");
+ data->fatal_error = true;
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+ }
+ if(frame->header.bits_per_sample > e->info.bits_per_sample) {
+ print_error_with_state(e, "ERROR: bits-per-sample of input changed mid-stream");
+ data->fatal_error = true;
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+ }
+
+ if(!EncoderSession_process(e, buffer, (uint32_t)n)) {
+ print_error_with_state(e, "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)
+{
+ EncoderSession *e = (EncoderSession*)client_data;
+ FLACDecoderData *data = &e->fmt.flac.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)
+{
+ EncoderSession *e = (EncoderSession*)client_data;
+ FLACDecoderData *data = &e->fmt.flac.client_data;
+ (void)decoder;
+
+ stats_print_name(1, e->inbasefilename);
+ flac__utils_printf(stderr, 1, "ERROR got %s while decoding FLAC input\n", FLAC__StreamDecoderErrorStatusString[status]);
+ if(!e->continue_through_decode_errors)
+ data->fatal_error = true;
+}
+
+FLAC__bool parse_cuesheet(FLAC__StreamMetadata **cuesheet, const char *cuesheet_filename, const char *inbasefilename, uint32_t sample_rate, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset, FLAC__bool treat_warnings_as_errors)
+{
+ FILE *f;
+ uint32_t 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 = flac_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, sample_rate, 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;
+}
+
+static void print_stats(const EncoderSession *encoder_session)
+{
+ if(flac__utils_verbosity_ >= 2) {
+ char ratiostr[16];
+
+ FLAC__ASSERT(encoder_session->total_samples_to_encode > 0);
+
+ if (encoder_session->compression_ratio > 0.0)
+ flac_snprintf(ratiostr, sizeof(ratiostr), "%0.3f", encoder_session->compression_ratio);
+ else
+ flac_snprintf(ratiostr, sizeof(ratiostr), "N/A");
+
+ if(encoder_session->samples_written == encoder_session->total_samples_to_encode) {
+ stats_print_name(2, encoder_session->inbasefilename);
+ stats_print_info(2, "%swrote %" PRIu64 " bytes, ratio=%s",
+ encoder_session->verify? "Verify OK, " : "",
+ encoder_session->bytes_written,
+ ratiostr
+ );
+ }
+ else {
+ stats_print_name(2, encoder_session->inbasefilename);
+ stats_print_info(2, "%u%% complete, ratio=%s", (uint32_t)floor(encoder_session->progress * 100.0 + 0.5), ratiostr);
+ }
+ }
+}
+
+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"
+#ifdef _WIN32
+ "is not writeable, the disk is full or the file has a filename that exceeds the\n"
+ "path length limit.\n"
+#else
+ "is not writable, or the disk is full.\n"
+#endif
+ );
+ }
+ }
+ 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://xiph.org/flac/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;
+ uint32_t frame_number;
+ uint32_t channel;
+ uint32_t 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=%" PRIu64 ", frame=%u, channel=%u, sample=%u, expected %d, got %d\n", 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://xiph.org/flac/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://github.com/xiph/flac/issues\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_bytes(FILE *f, FLAC__byte *buf, size_t n, FLAC__bool eof_ok, const char *fn)
+{
+ size_t bytes_read = fread(buf, 1, n, f);
+
+ if(bytes_read == 0) {
+ if(!eof_ok) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: unexpected EOF\n", fn);
+ return false;
+ }
+ else
+ return true;
+ }
+ if(bytes_read < n) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: unexpected EOF\n", fn);
+ return false;
+ }
+ return true;
+}
+
+FLAC__bool read_uint16(FILE *f, FLAC__bool big_endian, FLAC__uint16 *val, const char *fn)
+{
+ if(!read_bytes(f, (FLAC__byte*)val, 2, /*eof_ok=*/false, fn))
+ return false;
+ if(is_big_endian_host_ != big_endian) {
+ FLAC__byte tmp, *b = (FLAC__byte*)val;
+ tmp = b[1]; b[1] = b[0]; b[0] = tmp;
+ }
+ return true;
+}
+
+FLAC__bool read_uint32(FILE *f, FLAC__bool big_endian, FLAC__uint32 *val, const char *fn)
+{
+ if(!read_bytes(f, (FLAC__byte*)val, 4, /*eof_ok=*/false, fn))
+ return false;
+ if(is_big_endian_host_ != big_endian) {
+ 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_uint64(FILE *f, FLAC__bool big_endian, FLAC__uint64 *val, const char *fn)
+{
+ if(!read_bytes(f, (FLAC__byte*)val, 8, /*eof_ok=*/false, fn))
+ return false;
+ if(is_big_endian_host_ != big_endian) {
+ FLAC__byte tmp, *b = (FLAC__byte*)val;
+ tmp = b[7]; b[7] = b[0]; b[0] = tmp;
+ tmp = b[6]; b[6] = b[1]; b[1] = tmp;
+ tmp = b[5]; b[5] = b[2]; b[2] = tmp;
+ tmp = b[4]; b[4] = b[3]; b[3] = tmp;
+ }
+ return true;
+}
+
+FLAC__bool read_sane_extended(FILE *f, FLAC__uint32 *val, 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', or if the
+ * value is negative, between zero and one, or too large to be represented by
+ * 'val'; return true otherwise.
+ */
+{
+ uint32_t i;
+ FLAC__byte buf[10];
+ FLAC__uint64 p = 0;
+ FLAC__int16 e;
+ FLAC__int16 shift;
+
+ if(!read_bytes(f, buf, sizeof(buf), /*eof_ok=*/false, fn))
+ return false;
+ e = ((FLAC__uint16)(buf[0])<<8 | (FLAC__uint16)(buf[1]))-0x3FFF;
+ shift = 63-e;
+ 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 = 0; i < 8; ++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 uint8_t dump[8192];
+ struct flac_stat_s stb;
+
+ if(flac_fstat(fileno(f), &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFREG)
+ {
+ if(fseeko(f, offset, SEEK_CUR) == 0)
+ return true;
+ }
+ while(offset > 0) {
+ const long need = (long)min(offset, sizeof(dump));
+ if((long)fread(dump, 1, need, f) < need)
+ return false;
+ offset -= need;
+ }
+ return true;
+}
+
+uint32_t count_channel_mask_bits(FLAC__uint32 mask)
+{
+ uint32_t count = 0;
+ while(mask) {
+ if(mask & 1)
+ count++;
+ mask >>= 1;
+ }
+ return count;
+}
+
diff --git a/src/flac/encode.h b/src/flac/encode.h
new file mode 100644
index 0000000..2d65c50
--- /dev/null
+++ b/src/flac/encode.h
@@ -0,0 +1,116 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef flac__encode_h
+#define flac__encode_h
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "FLAC/metadata.h"
+#include "foreign_metadata.h"
+#include "utils.h"
+#include "share/compat.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 */
+
+ FLAC__bool is_first_file;
+ FLAC__bool is_last_file;
+ FLAC__bool replay_gain;
+ FLAC__bool ignore_chunk_sizes;
+ FLAC__bool error_on_compression_fail;
+ FLAC__bool limit_min_bitrate;
+ FLAC__bool relaxed_foreign_metadata_handling;
+
+ FLAC__StreamMetadata *vorbis_comment;
+ FLAC__StreamMetadata *vorbis_comment_with_channel_mask_tag;
+ FLAC__StreamMetadata *pictures[64];
+ unsigned num_pictures;
+
+ FileFormat format;
+ union {
+ struct {
+ FLAC__bool is_big_endian;
+ FLAC__bool is_unsigned_samples;
+ unsigned channels;
+ unsigned bps;
+ unsigned sample_rate;
+ } raw;
+ struct {
+ foreign_metadata_t *foreign_metadata; /* NULL unless --keep-foreign-metadata requested */
+ } iff;
+ } format_options;
+
+ struct {
+ FLAC__bool disable_constant_subframes;
+ FLAC__bool disable_fixed_subframes;
+ FLAC__bool disable_verbatim_subframes;
+ FLAC__bool do_md5;
+ } debug;
+} encode_options_t;
+
+int flac__encode_file(FILE *infile, FLAC__off_t infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, uint32_t lookahead_length, encode_options_t options);
+
+#endif
diff --git a/src/flac/foreign_metadata.c b/src/flac/foreign_metadata.c
new file mode 100644
index 0000000..f63fc3e
--- /dev/null
+++ b/src/flac/foreign_metadata.c
@@ -0,0 +1,952 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <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 "share/compat.h"
+#include "foreign_metadata.h"
+
+#ifdef min
+#undef min
+#endif
+#define min(x,y) ((x)<(y)?(x):(y))
+
+const char *FLAC__FOREIGN_METADATA_APPLICATION_ID[FLAC__FOREIGN_METADATA_NUMBER_OF_RECOGNIZED_APPLICATION_IDS] = { "aiff" , "riff", "w64 " };
+
+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__uint64 unpack64le_(const FLAC__byte *b)
+{
+ return (FLAC__uint64)b[0] + ((FLAC__uint64)b[1]<<8) + ((FLAC__uint64)b[2]<<16) + ((FLAC__uint64)b[3]<<24) + ((FLAC__uint64)b[4]<<32) + ((FLAC__uint64)b[5]<<40) + ((FLAC__uint64)b[6]<<48) + ((FLAC__uint64)b[7]<<56);
+}
+
+/* copies 'size' bytes from file 'fin' to 'fout', filling in *error with 'read_error' or 'write_error' as necessary */
+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)
+{
+ 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;
+}
+
+/* compare 'size' bytes from file 'fin' to 'fout', filling in *error with 'read_error' or 'write_error' as necessary */
+static FLAC__bool compare_data_(FILE *fin, FILE *fout, size_t size, const char **error, const char * const read_error, const char * const write_error, const char * const compare_error)
+{
+ FLAC__byte buffer_in[4096];
+ FLAC__byte buffer_out[4096]; /* sizes need to be the same */
+ size_t left;
+ for(left = size; left > 0; ) {
+ size_t need = min(sizeof(buffer_in), left);
+ if(fread(buffer_in, 1, need, fin) < need) {
+ if(error) *error = read_error;
+ return false;
+ }
+ if(fread(buffer_out, 1, need, fout) < need) {
+ if(error) *error = write_error;
+ return false;
+ }
+ if(memcmp(buffer_in, buffer_out, need)) {
+ if(error) *error = compare_error;
+ return false;
+ }
+ left -= need;
+ }
+ return true;
+}
+
+static FLAC__bool append_block_(foreign_metadata_t *fm, FLAC__off_t offset, FLAC__uint32 size, const char **error)
+{
+ foreign_block_t *fb;
+ if(size >= ((1u << FLAC__STREAM_METADATA_LENGTH_LEN) - FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8)) {
+ if(error) *error = "found foreign metadata chunk is too large (max is 16MiB per chunk)";
+ return false;
+ }
+ fb = safe_realloc_nofree_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];
+ FLAC__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 = (FLAC__off_t)8 + (FLAC__off_t)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;
+ }
+ /* WATCHOUT: For SSND we ignore the blockSize and are not saving any
+ * unaligned part at the end of the chunk. In retrospect it is pretty
+ * pointless to save the unaligned data before the PCM but now it is
+ * done and cast in stone.
+ */
+ }
+ if(!append_block_(fm, offset, 8 + (memcmp(buffer, "SSND", 4)? size : 8 + fm->ssnd_offset_size), error))
+ return false;
+ /* skip to next chunk */
+ 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];
+ FLAC__off_t offset, eof_offset = -1, ds64_data_size = -1;
+ 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, "RF64", 4)) || memcmp(buffer+8, "WAVE", 4)) {
+ if(error) *error = "unsupported RIFF layout (002)";
+ return false;
+ }
+ if(!memcmp(buffer, "RF64", 4))
+ fm->is_rf64 = true;
+ if(fm->is_rf64 && sizeof(FLAC__off_t) < 8) {
+ if(error) *error = "RF64 is not supported on this compile (r00)";
+ return false;
+ }
+ if(!append_block_(fm, offset, 12, error))
+ return false;
+ if(!fm->is_rf64 || unpack32le_(buffer+4) != 0xffffffff) {
+ eof_offset = (FLAC__off_t)8 + (FLAC__off_t)unpack32le_(buffer+4);
+ if(eof_offset & 1) /* fix odd RIFF size */
+ eof_offset++;
+ }
+ while(!feof(f)) {
+ FLAC__off_t 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(fm->is_rf64 && fm->num_blocks < 2) {
+ if(error) *error = "invalid RF64 file: \"data\" chunk before \"ds64\" chunk (r01)";
+ return false;
+ }
+ }
+ if(!append_block_(fm, offset, 8 + (memcmp(buffer, "data", 4)? size : 0), error))
+ return false;
+ /* parse ds64 chunk if necessary */
+ if(fm->is_rf64 && fm->num_blocks == 2) {
+ FLAC__byte buffer2[7*4];
+ if(memcmp(buffer, "ds64", 4)) {
+ if(error) *error = "invalid RF64 file: \"ds64\" chunk does not immediately follow \"WAVE\" marker (r02)";
+ return false;
+ }
+ /* unpack the size again since we don't want the padding byte effect */
+ size = unpack32le_(buffer+4);
+ if(size < (FLAC__off_t)sizeof(buffer2)) {
+ if(error) *error = "invalid RF64 file: \"ds64\" chunk size is < 28 (r03)";
+ return false;
+ }
+ if(size > (FLAC__off_t)sizeof(buffer2)) {
+ if(error) *error = "RF64 file has \"ds64\" chunk with extra size table, which is not currently supported (r04)";
+ return false;
+ }
+ if(fread(buffer2, 1, sizeof(buffer2), f) < sizeof(buffer2)) {
+ if(error) *error = "unexpected EOF reading \"ds64\" chunk data in RF64 file (r05)";
+ return false;
+ }
+ ds64_data_size = (FLAC__off_t)unpack64le_(buffer2+8);
+ if(ds64_data_size == (FLAC__off_t)(-1)) {
+ if(error) *error = "RF64 file has \"ds64\" chunk with data size == -1 (r08)";
+ return false;
+ }
+ /* check if pad byte needed */
+ if(ds64_data_size & 1)
+ ds64_data_size++;
+ /* @@@ [2^63 limit] */
+ if(ds64_data_size < 0) {
+ if(error) *error = "RF64 file too large (r09)";
+ return false;
+ }
+ if(unpack32le_(buffer2+24)) {
+ if(error) *error = "RF64 file has \"ds64\" chunk with extra size table, which is not currently supported (r06)";
+ return false;
+ }
+ eof_offset = (FLAC__off_t)8 + (FLAC__off_t)unpack64le_(buffer2);
+ /* @@@ [2^63 limit] */
+ if((FLAC__off_t)unpack64le_(buffer2) < 0 || eof_offset < 0) {
+ if(error) *error = "RF64 file too large (r07)";
+ return false;
+ }
+ }
+ else { /* skip to next chunk */
+ if(fm->is_rf64 && !memcmp(buffer, "data", 4) && unpack32le_(buffer+4) == 0xffffffff) {
+ if(fseeko(f, ds64_data_size, SEEK_CUR) < 0) {
+ if(error) *error = "invalid RF64 file: seek error (r10)";
+ return false;
+ }
+ }
+ else {
+ if(fseeko(f, size, SEEK_CUR) < 0) {
+ if(error) *error = "invalid WAVE file: seek error (009)";
+ return false;
+ }
+ }
+ }
+ }
+ if(fm->is_rf64 && eof_offset == (FLAC__off_t)(-1)) {
+ if(error) *error = "invalid RF64 file: all RIFF sizes are -1 (r11)";
+ 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 read_from_wave64_(foreign_metadata_t *fm, FILE *f, const char **error)
+{
+ FLAC__byte buffer[40];
+ FLAC__off_t offset, eof_offset = -1;
+ if((offset = ftello(f)) < 0) {
+ if(error) *error = "ftello() error (001)";
+ return false;
+ }
+ if(
+ fread(buffer, 1, 40, f) < 40 ||
+ /* RIFF GUID 66666972-912E-11CF-A5D6-28DB04C10000 */
+ memcmp(buffer, "\x72\x69\x66\x66\x2E\x91\xCF\x11\xA5\xD6\x28\xDB\x04\xC1\x00\x00", 16) ||
+ /* WAVE GUID 65766177-ACF3-11D3-8CD1-00C04F8EDB8A */
+ memcmp(buffer+24, "\x77\x61\x76\x65\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 16)
+ ) {
+ if(error) *error = "unsupported Wave64 layout (002)";
+ return false;
+ }
+ if(sizeof(FLAC__off_t) < 8) {
+ if(error) *error = "Wave64 is not supported on this compile (r00)";
+ return false;
+ }
+ if(!append_block_(fm, offset, 40, error))
+ return false;
+ eof_offset = (FLAC__off_t)unpack64le_(buffer+16); /*@@@ [2^63 limit] */
+ while(!feof(f)) {
+ FLAC__uint64 size;
+ if((offset = ftello(f)) < 0) {
+ if(error) *error = "ftello() error (003)";
+ return false;
+ }
+ if((size = fread(buffer, 1, 24, f)) < 24) {
+ if(size == 0 && feof(f))
+ break;
+ if(error) *error = "invalid Wave64 file (004)";
+ return false;
+ }
+ size = unpack64le_(buffer+16);
+ /* check if pad bytes needed */
+ if(size & 7)
+ size = (size+7) & (~((FLAC__uint64)7));
+ /* fmt GUID 20746D66-ACF3-11D3-8CD1-00C04F8EDB8A */
+ if(!memcmp(buffer, "\x66\x6D\x74\x20\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 16)) {
+ if(fm->format_block) {
+ if(error) *error = "invalid Wave64 file: multiple \"fmt \" chunks (005)";
+ return false;
+ }
+ if(fm->audio_block) {
+ if(error) *error = "invalid Wave64 file: \"data\" chunk before \"fmt \" chunk (006)";
+ return false;
+ }
+ fm->format_block = fm->num_blocks;
+ }
+ /* data GUID 61746164-ACF3-11D3-8CD1-00C04F8EDB8A */
+ else if(!memcmp(buffer, "\x64\x61\x74\x61\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 16)) {
+ if(fm->audio_block) {
+ if(error) *error = "invalid Wave64 file: multiple \"data\" chunks (007)";
+ return false;
+ }
+ if(!fm->format_block) {
+ if(error) *error = "invalid Wave64 file: \"data\" chunk before \"fmt \" chunk (008)";
+ return false;
+ }
+ fm->audio_block = fm->num_blocks;
+ }
+ if(!append_block_(fm, offset, memcmp(buffer, "\x64\x61\x74\x61\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 16)? (FLAC__uint32)size : 16+8, error))
+ return false;
+ /* skip to next chunk */
+ if(fseeko(f, size-24, SEEK_CUR) < 0) {
+ if(error) *error = "invalid Wave64 file: seek error (009)";
+ return false;
+ }
+ }
+ if(eof_offset != ftello(f)) {
+ if(error) *error = "invalid Wave64 file: unexpected EOF (010)";
+ return false;
+ }
+ if(!fm->format_block) {
+ if(error) *error = "invalid Wave64 file: missing \"fmt \" chunk (011)";
+ return false;
+ }
+ if(!fm->audio_block) {
+ if(error) *error = "invalid Wave64 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 uint32_t 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[32];
+ FLAC__off_t offset;
+ FLAC__uint32 length;
+ FLAC__bool first_block = true, type_found = false, ds64_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 (002)";
+ return false;
+ }
+ if(first_block) {
+ uint32_t i;
+ for(i = 0; i < FLAC__FOREIGN_METADATA_NUMBER_OF_RECOGNIZED_APPLICATION_IDS; i++)
+ if(memcmp(id, FLAC__FOREIGN_METADATA_APPLICATION_ID[i], sizeof(id)) == 0) {
+ fm->type = i;
+ first_block = false;
+ }
+ if(first_block) /* means no first foreign metadata block was found yet */
+ continue;
+ }
+ else if(memcmp(id, FLAC__FOREIGN_METADATA_APPLICATION_ID[fm->type], sizeof(id)))
+ continue;
+ offset = FLAC__metadata_simple_iterator_get_block_offset(it);
+ length = FLAC__metadata_simple_iterator_get_block_length(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(fseeko(f, offset, SEEK_SET) < 0) {
+ if(error) *error = "seek error (003)";
+ return false;
+ }
+ if(fread(buffer, 1, 4, f) != 4) {
+ if(error) *error = "read error (004)";
+ return false;
+ }
+ if(fm->num_blocks == 0) { /* first block? */
+ /* Initialize bools */
+ fm->is_wavefmtex = 0;
+ fm->is_aifc = 0;
+ fm->is_sowt = 0;
+ fm->is_rf64 = 0 == memcmp(buffer, "RF64", 4);
+
+ if(fm->type == FOREIGN_BLOCK_TYPE__RIFF && (0 == memcmp(buffer, "RIFF", 4) || fm->is_rf64))
+ type_found = true;
+ else if(fm->type == FOREIGN_BLOCK_TYPE__WAVE64 && 0 == memcmp(buffer, "riff", 4)) /* use first 4 bytes instead of whole GUID */
+ type_found = true;
+ else if(fm->type == FOREIGN_BLOCK_TYPE__AIFF && 0 == memcmp(buffer, "FORM", 4)) {
+ type_found = true;
+ if(fread(buffer+4, 1, 8, f) != 8) {
+ if(error) *error = "read error (020)";
+ return false;
+ }
+ fm->is_aifc = 0 == memcmp(buffer+8, "AIFC", 4);
+ }
+ 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;
+ if(fread(buffer+4, 1, 8, f) != 8) {
+ if(error) *error = "read error (020)";
+ return false;
+ }
+ fm->is_wavefmtex = 0 == memcmp(buffer+8, "\xfe\xff", 2);
+ }
+ 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->is_rf64 && fm->num_blocks == 1) {
+ if(memcmp(buffer, "ds64", 4)) {
+ if(error) *error = "invalid RF64 metadata: second chunk is not \"ds64\" (011)";
+ return false;
+ }
+ ds64_found = true;
+ }
+ }
+ else if(fm->type == FOREIGN_BLOCK_TYPE__WAVE64) {
+ if(!memcmp(buffer, "fmt ", 4)) { /* use first 4 bytes instead of whole GUID */
+ if(fm->format_block) {
+ if(error) *error = "invalid Wave64 metadata: multiple \"fmt \" chunks (012)";
+ return false;
+ }
+ if(fm->audio_block) {
+ if(error) *error = "invalid Wave64 metadata: \"data\" chunk before \"fmt \" chunk (013)";
+ return false;
+ }
+ fm->format_block = fm->num_blocks;
+ }
+ else if(!memcmp(buffer, "data", 4)) { /* use first 4 bytes instead of whole GUID */
+ if(fm->audio_block) {
+ if(error) *error = "invalid Wave64 metadata: multiple \"data\" chunks (014)";
+ return false;
+ }
+ if(!fm->format_block) {
+ if(error) *error = "invalid Wave64 metadata: \"data\" chunk before \"fmt \" chunk (015)";
+ 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 (016)";
+ return false;
+ }
+ if(fm->audio_block) {
+ if(error) *error = "invalid AIFF metadata: \"SSND\" chunk before \"COMM\" chunk (017)";
+ return false;
+ }
+ fm->format_block = fm->num_blocks;
+ if(fm->is_aifc) {
+ if(fread(buffer+4, 1, 26, f) != 26) {
+ if(error) *error = "read error (020)";
+ return false;
+ }
+ fm->is_sowt = 0 == memcmp(buffer+26, "sowt", 2);
+ fm->aifc_comm_length = length;
+ }
+ }
+ else if(!memcmp(buffer, "SSND", 4)) {
+ if(fm->audio_block) {
+ if(error) *error = "invalid AIFF metadata: multiple \"SSND\" chunks (018)";
+ return false;
+ }
+ if(!fm->format_block) {
+ if(error) *error = "invalid AIFF metadata: \"SSND\" chunk before \"COMM\" chunk (019)";
+ 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 (020)";
+ 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 (021)";
+ return false;
+ }
+ if(!append_block_(fm, offset, FLAC__metadata_simple_iterator_get_block_length(it)-sizeof(id), error))
+ return false;
+ }
+ if(fm->is_rf64 && !ds64_found) {
+ if(error) *error = "invalid RF64 file: second chunk is not \"ds64\" (023)";
+ return false;
+ }
+ if(!fm->format_block) {
+ if(error)
+ *error =
+ fm->type==FOREIGN_BLOCK_TYPE__RIFF? "invalid WAVE file: missing \"fmt \" chunk (024)" :
+ fm->type==FOREIGN_BLOCK_TYPE__WAVE64? "invalid Wave64 file: missing \"fmt \" chunk (025)" :
+ "invalid AIFF file: missing \"COMM\" chunk (026)";
+ return false;
+ }
+ if(!fm->audio_block) {
+ if(error)
+ *error =
+ fm->type==FOREIGN_BLOCK_TYPE__RIFF? "invalid WAVE file: missing \"data\" chunk (027)" :
+ fm->type==FOREIGN_BLOCK_TYPE__WAVE64? "invalid Wave64 file: missing \"data\" chunk (028)" :
+ "invalid AIFF file: missing \"SSND\" chunk (029)";
+ return false;
+ }
+ return true;
+}
+
+static FLAC__bool write_to_iff_(foreign_metadata_t *fm, FILE *fin, FILE *fout, FLAC__off_t offset1, FLAC__off_t offset2, FLAC__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";
+ return false;
+ }
+
+ /* don't write first (RIFF/RF64/FORM) chunk, or ds64 chunk in the case of RF64 */
+ for(i = fm->is_rf64?2:1; i < fm->format_block; i++) {
+ if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) {
+ if(error) *error = "seek failed in FLAC file";
+ return false;
+ }
+ if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in FLAC file", "write failed in WAVE/AIFF file"))
+ return false;
+ }
+
+ if(fm->is_aifc) {
+ /* Need to restore compression type name */
+ if(fseeko(fout, 30, SEEK_CUR) < 0) {
+ if(error) *error = "seek failed in AIFF-C file";
+ return false;
+ }
+ if(fseeko(fin, fm->blocks[i].offset+30, SEEK_SET) < 0) {
+ if(error) *error = "seek failed in FLAC file";
+ return false;
+ }
+ if(!copy_data_(fin, fout, fm->aifc_comm_length-34, error, "read failed in FLAC file", "write failed in WAVE/AIFF file"))
+ return false;
+ /* Now seek back */
+ if(fseeko(fout, ((FLAC__int32)(fm->aifc_comm_length) * -1) + 4, SEEK_CUR) < 0) {
+ if(error) *error = "seek failed in AIFF-C file";
+ 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";
+ return false;
+ }
+ if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in FLAC file", "write failed in WAVE/AIFF file"))
+ return false;
+ }
+ if(fseeko(fout, offset3, SEEK_SET) < 0) {
+ if(error) *error = "seek failed in WAVE/AIFF file";
+ 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";
+ return false;
+ }
+ if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in FLAC file", "write failed in WAVE/AIFF file"))
+ return false;
+ }
+ return true;
+}
+
+static FLAC__bool compare_with_iff_(foreign_metadata_t *fm, FILE *fin, FILE *fout, FLAC__off_t offset3, const char **error)
+{
+ size_t i;
+
+ /* Compare blocks before audio data */
+ for(i = 0; i <= (fm->audio_block); i++) {
+ if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) {
+ if(error) *error = "seek failed in FLAC file";
+ return false;
+ }
+ if(!compare_data_(fin, fout, fm->blocks[i].size, error, "read failed in FLAC file", "read failed in WAVE/AIFF file",
+ i==0?"stored main chunk length differs from written length":(
+ i==fm->format_block?"stored foreign format block differs from written block. Perhaps the file is being restored to a different format than that of the original file":(
+ i==fm->audio_block?"stored audio length differs from written length. Perhaps the file changed in length after being originally encoded":"restore of foreign metadata failed"))))
+ return false;
+ }
+
+ /* Seek beyond audio */
+ if(fseeko(fout, offset3, SEEK_SET) < 0) {
+ if(error) *error = "seek failed in WAVE/AIFF file";
+ return false;
+ }
+ for(; i < fm->num_blocks; i++) {
+ if(fseeko(fin, fm->blocks[i].offset, SEEK_SET) < 0) {
+ if(error) *error = "seek failed in FLAC file";
+ return false;
+ }
+ if(!compare_data_(fin, fout, fm->blocks[i].size, error, "read failed in FLAC file", "read failed in WAVE/AIFF file", "restore of foreign metadata failed"))
+ return false;
+ }
+ return true;
+}
+
+foreign_metadata_t *flac__foreign_metadata_new(foreign_block_type_t type)
+{
+ /* calloc() to zero all the member variables */
+ foreign_metadata_t *x = calloc(sizeof(foreign_metadata_t), 1);
+ if(x) {
+ x->type = type;
+ x->is_rf64 = false;
+ }
+ 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 = flac_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 = flac_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_read_from_wave64(foreign_metadata_t *fm, const char *filename, const char **error)
+{
+ FLAC__bool ok;
+ FILE *f = flac_fopen(filename, "rb");
+ if(!f) {
+ if(error) *error = "can't open Wave64 file for reading (000)";
+ return false;
+ }
+ ok = read_from_wave64_(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 = flac_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 = flac_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 = flac_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, FLAC__off_t offset1, FLAC__off_t offset2, FLAC__off_t offset3, const char **error)
+{
+ FLAC__bool ok;
+ FILE *fin, *fout;
+ if(0 == (fin = flac_fopen(infilename, "rb"))) {
+ if(error) *error = "can't open FLAC file for reading (000)";
+ return false;
+ }
+ if(0 == (fout = flac_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;
+}
+
+FLAC__bool flac__foreign_metadata_compare_with_iff(foreign_metadata_t *fm, const char *infilename, const char *outfilename, FLAC__off_t offset3, const char **error)
+{
+ FLAC__bool ok;
+ FILE *fin, *fout;
+ if(0 == (fin = flac_fopen(infilename, "rb"))) {
+ if(error) *error = "can't open FLAC file for reading";
+ return false;
+ }
+ if(0 == (fout = flac_fopen(outfilename, "rb"))) {
+ if(error) *error = "can't open WAVE/AIFF file for comparing";
+ fclose(fin);
+ return false;
+ }
+ ok = compare_with_iff_(fm, fin, fout, 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
index 0000000..fa68d46
--- /dev/null
+++ b/src/flac/foreign_metadata.h
@@ -0,0 +1,83 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef flac__foreign_metadata_h
+#define flac__foreign_metadata_h
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "FLAC/metadata.h"
+#include "utils.h"
+#include "share/compat.h"
+
+#define FLAC__FOREIGN_METADATA_NUMBER_OF_RECOGNIZED_APPLICATION_IDS 3
+
+extern const char *FLAC__FOREIGN_METADATA_APPLICATION_ID[FLAC__FOREIGN_METADATA_NUMBER_OF_RECOGNIZED_APPLICATION_IDS];
+
+/* WATCHOUT: these enums are used to index internal arrays */
+typedef enum {
+ FOREIGN_BLOCK_TYPE__AIFF = 0, /* for AIFF and AIFF-C */
+ FOREIGN_BLOCK_TYPE__RIFF = 1, /* for WAVE and RF64 */
+ FOREIGN_BLOCK_TYPE__WAVE64 = 2 /* only for Sony's flavor */
+} 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 */
+ FLAC__off_t offset;
+ /* size is the actual size in bytes of the chunk to be stored/recreated. */
+ /* It includes the 8 bytes of chunk type and size, and any padding byte for alignment. */
+ /* For 'data'/'SSND' chunks, the size does not include the actual sound or padding bytes */
+ /* because these are not stored, they are recreated from the compressed FLAC stream. */
+ /* So for RIFF 'data', size is 8, and for AIFF 'SSND', size is 8 + 8 + ssnd_offset_size */
+ /* 32 bit size is OK because we only care about the non-sound data and FLAC metadata */
+ /* only supports a few megs anyway. */
+ FLAC__uint32 size;
+} foreign_block_t;
+
+typedef struct {
+ foreign_block_type_t type; /* currently we don't support multiple foreign types in a stream (and 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__bool is_rf64; /* always false if type!=RIFF */
+ FLAC__bool is_wavefmtex; /* always false if type!=RIFF */
+ FLAC__bool is_aifc; /* always false if type!=AIFF */
+ FLAC__bool is_sowt; /* always false if type!=AIFF */
+ FLAC__uint32 aifc_comm_length;
+ 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_read_from_wave64(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, FLAC__off_t offset1, FLAC__off_t offset2, FLAC__off_t offset3, const char **error);
+FLAC__bool flac__foreign_metadata_compare_with_iff(foreign_metadata_t *fm, const char *infilename, const char *outfilename, FLAC__off_t offset3, const char **error);
+
+#endif
diff --git a/src/flac/iffscan.c b/src/flac/iffscan.c
new file mode 100644
index 0000000..a5472e0
--- /dev/null
+++ b/src/flac/iffscan.c
@@ -0,0 +1,129 @@
+/* iffscan - Simple AIFF/RIFF chunk scanner
+ * Copyright (C) 2007-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "share/compat.h"
+#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__uint64 unpack64le_(const FLAC__byte *b)
+{
+ return (FLAC__uint64)b[0] + ((FLAC__uint64)b[1]<<8) + ((FLAC__uint64)b[2]<<16) + ((FLAC__uint64)b[3]<<24) + ((FLAC__uint64)b[4]<<32) + ((FLAC__uint64)b[5]<<40) + ((FLAC__uint64)b[6]<<48) + ((FLAC__uint64)b[7]<<56);
+}
+
+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[36];
+ foreign_metadata_t *fm;
+ const char *fn, *error;
+ size_t i;
+ FLAC__uint32 size;
+
+#ifdef _WIN32
+ if (get_utf8_argv(&argc, &argv) != 0) {
+ fprintf(stderr, "ERROR: failed to convert command line parameters to UTF-8\n");
+ return 1;
+ }
+#endif
+
+ if(argc != 2) {
+ flac_fprintf(stderr, "usage: %s { file.wav | file.aif }\n", argv[0]);
+ return 1;
+ }
+ fn = argv[1];
+ if(0 == (f = flac_fopen(fn, "rb")) || fread(buf, 1, 4, f) != 4) {
+ flac_fprintf(stderr, "ERROR opening %s for reading\n", fn);
+ return 1;
+ }
+ fclose(f);
+ if(0 == (fm = flac__foreign_metadata_new(memcmp(buf, "RIFF", 4) && memcmp(buf, "RF64", 4)? FOREIGN_BLOCK_TYPE__AIFF : FOREIGN_BLOCK_TYPE__RIFF))) {
+ flac_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)) {
+ flac_fprintf(stderr, "ERROR reading chunks from %s: %s\n", fn, error);
+ return 1;
+ }
+ }
+ else {
+ if(!flac__foreign_metadata_read_from_wave(fm, fn, &error)) {
+ flac_fprintf(stderr, "ERROR reading chunks from %s: %s\n", fn, error);
+ return 1;
+ }
+ }
+ if(0 == (f = flac_fopen(fn, "rb"))) {
+ flac_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) {
+ flac_fprintf(stderr, "ERROR seeking in %s\n", fn);
+ return 1;
+ }
+ if(fread(buf, 1, i==0?12:8, f) != (i==0?12:8)) {
+ flac_fprintf(stderr, "ERROR reading %s\n", fn);
+ return 1;
+ }
+ size = unpack32_((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);
+ else if(fm->type == FOREIGN_BLOCK_TYPE__RIFF && i == 1 && !memcmp(buf, "ds64", 4)) {
+ if(fread(buf+8, 1, 36-8, f) != 36-8) {
+ flac_fprintf(stderr, "ERROR reading %s\n", fn);
+ return 1;
+ }
+ printf("\n RIFF size=%016" PRIx64 "=(%20" PRIu64 ")", unpack64le_((FLAC__byte*)buf+8), unpack64le_((FLAC__byte*)buf+8));
+ printf("\n data size=%016" PRIx64 "=(%20" PRIu64 ")", unpack64le_((FLAC__byte*)buf+16), unpack64le_((FLAC__byte*)buf+16));
+ printf("\n sample count=%016" PRIx64 "=(%20" PRIu64 ")", unpack64le_((FLAC__byte*)buf+24), unpack64le_((FLAC__byte*)buf+24));
+ printf("\n table size=%08x=(%10u)", unpack32le_((FLAC__byte*)buf+32), unpack32le_((FLAC__byte*)buf+32));
+ }
+ printf("\n");
+ }
+ fclose(f);
+ flac__foreign_metadata_delete(fm);
+ return 0;
+}
diff --git a/src/flac/local_string_utils.c b/src/flac/local_string_utils.c
new file mode 100644
index 0000000..7e25233
--- /dev/null
+++ b/src/flac/local_string_utils.c
@@ -0,0 +1,109 @@
+/* flac - Command-line FLAC encoder/decoder
+ */
+
+#ifdef 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
index 0000000..01f891f
--- /dev/null
+++ b/src/flac/local_string_utils.h
@@ -0,0 +1,28 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#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
index 0000000..c22e602
--- /dev/null
+++ b/src/flac/main.c
@@ -0,0 +1,2442 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <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 "share/compat.h"
+#include "share/endswap.h"
+#include "share/safe_str.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 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
+
+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_uint32_t(compression_setting_type_t type, uint32_t 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, const FileFormat format);
+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);
+
+/*
+ * 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 },
+ { "preserve-modtime" , share__no_argument, 0, 0 },
+ { "keep-foreign-metadata" , share__no_argument, 0, 0 },
+ { "keep-foreign-metadata-if-present" , 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-raw-format" , share__no_argument, 0, 0 },
+ { "force-aiff-format" , share__no_argument, 0, 0 },
+ { "force-rf64-format" , share__no_argument, 0, 0 },
+ { "force-wave64-format" , share__no_argument, 0, 0 },
+ { "force-legacy-wave-format" , share__no_argument, 0, 0 },
+ { "force-extensible-wave-format",share__no_argument,0, 0 },
+ { "force-aiff-c-none-format" , share__no_argument, 0, 0 },
+ { "force-aiff-c-sowt-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 },
+ { "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 },
+ { "error-on-compression-fail" , share__no_argument, 0, 0 },
+ { "limit-min-bitrate" , share__no_argument, 0, 0 },
+
+ /*
+ * analysis options
+ */
+ { "residual-gnuplot", share__no_argument, 0, 0 },
+ { "residual-text", share__no_argument, 0, 0 },
+
+ /*
+ * negatives
+ */
+ { "no-preserve-modtime" , share__no_argument, 0, 0 },
+ { "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-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 },
+ { "no-error-on-compression-fail", 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_raw_format;
+ FLAC__bool force_aiff_format;
+ FLAC__bool force_rf64_format;
+ FLAC__bool force_wave64_format;
+ FLAC__bool force_legacy_wave_format;
+ FLAC__bool force_extensible_wave_format;
+ FLAC__bool force_aiff_c_none_format;
+ FLAC__bool force_aiff_c_sowt_format;
+ FLAC__bool delete_input;
+ FLAC__bool preserve_modtime;
+ FLAC__bool keep_foreign_metadata;
+ FLAC__bool keep_foreign_metadata_if_present;
+ FLAC__bool replay_gain;
+ FLAC__bool ignore_chunk_sizes;
+ 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;
+ FLAC__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 */
+ FLAC__bool error_on_compression_fail;
+ FLAC__bool limit_min_bitrate;
+
+ uint32_t num_files;
+ char **filenames;
+
+ FLAC__StreamMetadata *vorbis_comment;
+ FLAC__StreamMetadata *pictures[64];
+ uint32_t 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
+ */
+
+
+#ifndef FUZZ_TOOL_FLAC
+int main(int argc, char *argv[])
+#else
+static int main_to_fuzz(int argc, char *argv[])
+#endif
+{
+ int retval = 0;
+
+#ifdef __EMX__
+ _response(&argc, &argv);
+ _wildcard(&argc, &argv);
+#endif
+#ifdef _WIN32
+ if (get_utf8_argv(&argc, &argv) != 0) {
+ fprintf(stderr, "ERROR: failed to convert command line parameters to UTF-8\n");
+ return 1;
+ }
+#endif
+
+ srand((uint32_t)time(0));
+#ifdef _WIN32
+ {
+ const char *var;
+ var = getenv("LC_ALL");
+ if (!var)
+ var = getenv("LC_NUMERIC");
+ if (!var)
+ var = getenv("LANG");
+ if (!var || strcmp(var, "C") != 0)
+ setlocale(LC_ALL, "");
+ }
+#else
+ setlocale(LC_ALL, "");
+#endif
+ 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 || (uint32_t)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 && option_values.format_bps != 32)
+ return usage_error("ERROR: invalid bits per sample '%u' (must be 8/16/24/32)\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?1:0) +
+ (option_values.force_aiff_format?1:0) +
+ (option_values.force_rf64_format?1:0) +
+ (option_values.force_wave64_format?1:0) +
+ (option_values.force_legacy_wave_format?1:0) +
+ (option_values.force_extensible_wave_format?1:0) +
+ (option_values.force_aiff_c_none_format?1:0) +
+ (option_values.force_aiff_c_sowt_format?1:0)
+ > 1)
+ return usage_error("ERROR: only one of force format options 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.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.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");
+ 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");
+ }
+ }
+ 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 || option_values.keep_foreign_metadata_if_present) {
+ /* 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");
+ 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\n", FLAC__VERSION_STRING);
+ flac__utils_printf(stderr, 2, "Copyright (C) 2000-2009 Josh Coalson, 2011-2023 Xiph.Org Foundation\n");
+ 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 {
+ uint32_t 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 {
+ uint32_t 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;
+ if(encode_file(option_values.filenames[i], first, i == (option_values.num_files-1)))
+ retval = 1;
+ else
+ 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 != (error = grabbag__replaygain_store_to_file_album(outfilename, album_gain, album_peak, option_values.preserve_modtime))) {
+ 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.show_version = 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_raw_format = false;
+ option_values.force_aiff_format = false;
+ option_values.force_rf64_format = false;
+ option_values.force_wave64_format = false;
+ option_values.force_legacy_wave_format = false;
+ option_values.force_extensible_wave_format = false;
+ option_values.force_aiff_c_none_format = false;
+ option_values.force_aiff_c_sowt_format = false;
+ option_values.delete_input = false;
+ option_values.preserve_modtime = true;
+ option_values.keep_foreign_metadata = false;
+ option_values.keep_foreign_metadata_if_present = false;
+ option_values.replay_gain = false;
+ option_values.ignore_chunk_sizes = 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 = (FLAC__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.error_on_compression_fail = false;
+ option_values.limit_min_bitrate = 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) {
+ uint32_t i = 0;
+ if(0 == (option_values.filenames = 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;
+
+ 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, "preserve-modtime")) {
+ option_values.preserve_modtime = true;
+ }
+ else if(0 == strcmp(long_option, "keep-foreign-metadata")) {
+ option_values.keep_foreign_metadata = true;
+ }
+ else if(0 == strcmp(long_option, "keep-foreign-metadata-if-present")) {
+ option_values.keep_foreign_metadata_if_present = 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;
+ FLAC__int64 ix;
+ ix = strtoll(option_argument, &end, 10);
+ if(0 == strlen(option_argument) || *end)
+ return usage_error("ERROR: --%s must be a number\n", long_option);
+ option_values.format_input_size = (FLAC__off_t)ix;
+ if(option_values.format_input_size != ix) /* check if FLAC__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 uint32_t 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-raw-format")) {
+ option_values.force_raw_format = true;
+ }
+ else if(0 == strcmp(long_option, "force-aiff-format")) {
+ option_values.force_aiff_format = true;
+ }
+ else if(0 == strcmp(long_option, "force-rf64-format")) {
+ option_values.force_rf64_format = true;
+ }
+ else if(0 == strcmp(long_option, "force-wave64-format")) {
+ option_values.force_wave64_format = true;
+ }
+ else if(0 == strcmp(long_option, "force-legacy-wave-format")) {
+ option_values.force_legacy_wave_format = true;
+ }
+ else if(0 == strcmp(long_option, "force-extensible-wave-format")) {
+ option_values.force_extensible_wave_format = true;
+ }
+ else if(0 == strcmp(long_option, "force-aiff-c-none-format")) {
+ option_values.force_aiff_c_none_format = true;
+ }
+ else if(0 == strcmp(long_option, "force-aiff-c-sowt-format")) {
+ option_values.force_aiff_c_sowt_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;
+ }
+#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;
+ }
+ else if(0 == strcmp(long_option, "limit-min-bitrate")) {
+ option_values.limit_min_bitrate = true;
+ }
+ /*
+ * negatives
+ */
+ else if(0 == strcmp(long_option, "no-preserve-modtime")) {
+ option_values.preserve_modtime = false;
+ }
+ 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")) {
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ flac__utils_verbosity_ = 2;
+#endif
+ }
+ 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;
+ option_values.keep_foreign_metadata_if_present = 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-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 if(0 == strcmp(long_option, "no-error-on-compression-fail")) {
+ option_values.error_on_compression_fail = false;
+ }
+ else if(0 == strcmp(long_option, "error-on-compression-fail")) {
+ option_values.error_on_compression_fail = true;
+ }
+ }
+ 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':
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ flac__utils_verbosity_ = 1;
+#endif
+ 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_uint32_t(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 {
+ size_t len = strlen(option_values.requested_seek_points);
+ flac_snprintf(option_values.requested_seek_points+len, sizeof(option_values.requested_seek_points) - len, "%s;", option_argument);
+ }
+ }
+ 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':
+ {
+ uint32_t i ;
+ 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_uint32_t(CST_BLOCKSIZE, (uint32_t)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':
+ {
+ uint32_t i ;
+ FLAC__ASSERT(0 != option_argument);
+ i = atoi(option_argument);
+ if(i > 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_uint32_t(CST_MAX_LPC_ORDER, 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':
+ {
+ uint32_t i ;
+ FLAC__ASSERT(0 != option_argument);
+ i = atoi(option_argument);
+ if((i > 0 && (i < FLAC__MIN_QLP_COEFF_PRECISION || i > 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_uint32_t(CST_QLP_COEFF_PRECISION, i);
+ }
+ break;
+ case 'r':
+ {
+ uint32_t i;
+ char * p;
+ FLAC__ASSERT(0 != option_argument);
+ p = strchr(option_argument, ',');
+ if(0 == p) {
+ add_compression_setting_uint32_t(CST_MIN_RESIDUAL_PARTITION_ORDER, 0);
+ i = atoi(option_argument);
+ if(i > FLAC__MAX_RICE_PARTITION_ORDER)
+ 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_uint32_t(CST_MAX_RESIDUAL_PARTITION_ORDER, i);
+ }
+ else {
+ i = atoi(option_argument);
+ if(i > FLAC__MAX_RICE_PARTITION_ORDER)
+ 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_uint32_t(CST_MIN_RESIDUAL_PARTITION_ORDER, i);
+ i = atoi(++p);
+ if(i > FLAC__MAX_RICE_PARTITION_ORDER)
+ 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_uint32_t(CST_MAX_RESIDUAL_PARTITION_ORDER, i);
+ }
+ }
+ break;
+ case 'R':
+ {
+ uint32_t i;
+ i = atoi(option_argument);
+ add_compression_setting_uint32_t(CST_RICE_PARAMETER_SEARCH_DIST, i);
+ }
+ break;
+ default:
+ FLAC__ASSERT(0);
+ }
+ }
+
+ return 0;
+}
+
+void free_options(void)
+{
+ uint32_t 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]))
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ die("too many compression settings");
+#else
+ return;
+#endif
+ 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]))
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ die("too many compression settings");
+#else
+ return;
+#endif
+ 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_uint32_t(compression_setting_type_t type, uint32_t value)
+{
+ if(option_values.num_compression_settings >= sizeof(option_values.compression_settings)/sizeof(option_values.compression_settings[0]))
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ die("too many compression settings");
+#else
+ return;
+#endif
+ if(type == CST_COMPRESSION_LEVEL) {
+ /* Compression level always goes first */
+ option_values.compression_settings[0].type = type;
+ option_values.compression_settings[0].value.t_unsigned = value;
+ }
+ else {
+ 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);
+
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ (void) vfprintf(stderr, message, args);
+#endif
+
+ 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-2009 Josh Coalson\n");
+ printf("Copyright (C) 2011-2023 Xiph.Org Foundation\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 along\n");
+ printf("with this program; if not, write to the Free Software Foundation, Inc.,\n");
+ printf("51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n");
+ printf("===============================================================================\n");
+}
+
+static void usage_summary(void)
+{
+ printf("Usage:\n");
+ printf("\n");
+ printf(" Encoding: flac [<general/encoding/format options>] [INPUTFILE [...]]\n");
+ printf(" Decoding: flac -d [<general/decoding/format options>] [FLACFILE [...]]\n");
+ printf(" Testing: flac -t [<general options>] [FLACFILE [...]]\n");
+ printf("Analyzing: flac -a [<general/analysis options>] [FLACFILE [...]]\n");
+ printf("\n");
+ printf("Be sure to read the list of known bugs at:\n");
+ printf("http://xiph.org/flac/documentation_bugs.html\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("Be sure to read the list of known bugs at:\n");
+ printf("http://xiph.org/flac/documentation_bugs.html\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(" --preserve-modtime Output files keep timestamp of input (default)\n");
+ printf(" --keep-foreign-metadata Save/restore WAVE or AIFF non-audio chunks\n");
+ printf(" --keep-foreign-metadata-if-present Save/restore WAVE or AIFF non-audio\n");
+ printf(" but not return an error when no such chunks are found\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");
+ printf(" --ignore-chunk-sizes Ignore data chunk sizes in WAVE/AIFF files\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(" -A subdivide_tukey(2)\n");
+ printf(" -7, --compression-level-7 Synonymous with -l 12 -b 4096 -m -r 6\n");
+ printf(" -A subdivide_tukey(2)\n");
+ printf(" -8, --compression-level-8, --best Synonymous with -l 12 -b 4096 -m -r 6\n");
+ printf(" -A subdivide_tukey(3)\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(" --limit-min-bitrate Limit minimum bitrate (for streaming)\n");
+ printf("format options:\n");
+ printf(" --force-raw-format Treat input or output as raw samples\n");
+ printf(" --force-aiff-format Decode to AIFF format\n");
+ printf(" --force-rf64-format Decode to RF64 format\n");
+ printf(" --force-wave64-format Decode to Wave64 format\n");
+ printf(" --force-legacy-wave-format Decode to legacy wave format\n");
+ printf(" --force-extensible-wave-format Decode to extensible wave format\n");
+ printf(" --force-aiff-c-none-format Decode to AIFF-C NONE format\n");
+ printf(" --force-aiff-c-sowt-format Decode to AIFF-C sowt format\n");
+ printf("raw 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("negative options:\n");
+ printf(" --no-adaptive-mid-side\n");
+ printf(" --no-cued-seekpoints\n");
+ printf(" --no-decode-through-errors\n");
+ printf(" --no-delete-input-file\n");
+ printf(" --no-error-on-compression-fail\n");
+ printf(" --no-preserve-modtime\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");
+ printf(" --no-ignore-chunk-sizes\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, Wave64, RF64 file, AIFF (or uncompressed\n");
+ printf(" AIFF-C) file, or raw samples. The output file(s) will be in native FLAC\n");
+ printf(" 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("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(" --preserve-modtime Output files have their timestamps/permissions\n");
+ printf(" set to match those of their inputs (this is\n");
+ printf(" default). Use --no-preserve-modtime to make\n");
+ printf(" output files have the current time and default\n");
+ printf(" permissions.\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(" With this option, FLAC will pick the right\n");
+ printf(" output format on decoding.\n");
+ printf(" --keep-foreign-metadata-if-present As previous option, but do not throw\n");
+ printf(" an error in case no foreign metadata is found,\n");
+ printf(" the wrong kind of foreign metadata is found (on\n");
+ printf(" decoding) or if the foreign could not be parsed,\n");
+ printf(" i.e. all foreign metadata related errors are\n");
+ printf(" treated as warnings.\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");
+ 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");
+ 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. Only mono and stereo files\n");
+ printf(" are allowed, and the sample rate must be 8,\n");
+ printf(" 11.025, 12, 16, 18.9, 22.05, 24, 28, 32, 36,\n");
+ printf(" 37.8, 44.1, 48, 56, 64, 72, 75.6, 88.2, 96, 112,\n");
+ printf(" 128, 144, 151.2, 176.4, 192, 224, 256, 288,\n");
+ printf(" 302.4, 352.8, 384, 448, 512, 576, or 604.8 kHz.\n");
+ printf(" NOTE: this option may also leave a few extra\n");
+ printf(" 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 specifies 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; for subset streams this\n");
+ printf(" must be <= 4608 if the samplerate <= 48kHz,\n");
+ printf(" for subset streams with a higher samplerates it\n");
+ printf(" must be <= 16384.\n");
+ printf(" -0, --compression-level-0, --fast Synonymous with -l 0 -b 1152 -r 3\n");
+ printf(" --no-mid-side\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(" --no-mid-side\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(" -A subdivide_tukey(2)\n");
+ printf(" -7, --compression-level-7 Synonymous with -l 12 -b 4096 -m -r 6\n");
+ printf(" -A subdivide_tukey(2)\n");
+ printf(" -8, --compression-level-8, --best Synonymous with -l 12 -b 4096 -m -r 6\n");
+ printf(" -A subdivide_tukey(3)\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, partial_tukey(n)\n");
+ printf(" punchout_tukey(n) and subdivide_tukey(n).\n");
+ printf(" More than one may be specified but encoding\n");
+ printf(" time is a multiple of the number of\n");
+ printf(" functions since they are each tried in \n");
+ printf(" turn. The encoder chooses suitable\n");
+ printf(" defaults in the absence 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 minimum 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 to 15 inclusive; min defaults to 0;\n");
+ printf(" the default is -r 0; above 4 does not\n");
+ printf(" usually help much)\n");
+ printf(" --limit-min-bitrate Limit minimum bitrate by not allowing\n");
+ printf(" frames consisting of only constant\n");
+ printf(" subframes. This ensures a bitrate of at\n");
+ printf(" least 1 bit/sample, for example 48kbit/s\n");
+ printf(" for 48kHz input. This is mostly beneficial\n");
+ printf(" for internet streaming.\n");
+ printf("format options:\n");
+ printf(" --force-raw-format Force input (when encoding) or output (when\n");
+ printf(" decoding) to be treated as raw samples\n");
+ printf(" --force-aiff-format\n");
+ printf(" --force-rf64-format\n");
+ printf(" --force-wave64-format\n");
+ printf(" Force the decoder to output AIFF/RF64/WAVE64 format respectively.\n");
+ printf(" This option is not needed if the output filename (as set by -o)\n");
+ printf(" ends with *.aif* or *.aiff*, *.rf64* and *.w64* respectively. Also,\n");
+ printf(" this option has no effect when encoding since input is\n");
+ printf(" auto-detected. When none of these options nor\n");
+ printf(" --keep-foreign-metadata are given and no output filename is set,\n");
+ printf(" the output format is WAV by default.\n");
+ printf(" --force-legacy-wave-format\n");
+ printf(" --force-extensible-wave-format\n");
+ printf(" Instruct the decoder to output a WAVE file with WAVE_FORMAT_PCM and\n");
+ printf(" WAVE_FORMAT_EXTENSIBLE respectively. If none of these options nor\n");
+ printf(" --keep-foreign-metadata are given, FLAC outputs WAVE_FORMAT_PCM\n");
+ printf(" for mono or stereo with a bit depth of 8 or 16 bits, and\n");
+ printf(" WAVE_FORMAT_EXTENSIBLE for all other audio formats.\n");
+ printf(" --force-aiff-c-none-format\n");
+ printf(" --force-aiff-c-sowt-format\n");
+ printf(" Instruct the decoder to output an AIFF-C file with format NONE and\n");
+ printf(" sowt respectively.\n");
+ printf("raw 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. 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, --cuesheet, 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("negative options:\n");
+ printf(" --no-adaptive-mid-side\n");
+ printf(" --no-cued-seekpoints\n");
+ printf(" --no-decode-through-errors\n");
+ printf(" --no-delete-input-file\n");
+ printf(" --no-preserve-modtime\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");
+ printf(" --no-ignore-chunk-sizes\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 */
+ flac__utils_printf(stderr, 1, "WARNING: %s is not a%s file; treating as a%s file\n", infilename, FileFormatString[wrong], FileFormatString[right]);
+}
+
+int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_last_file)
+{
+ FILE *encode_infile;
+ FLAC__byte lookahead[12];
+ uint32_t lookahead_length = 0, master_chunk_size = 0;
+ FileFormat input_format = FORMAT_RAW;
+ int retval;
+ FLAC__off_t infilesize;
+ encode_options_t encode_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' */
+ size_t infilename_length;
+
+ if(0 == outfilename) {
+ flac__utils_printf(stderr, 1, "ERROR: filename too long: %s", infilename);
+ return 1;
+ }
+
+ if(0 == strcmp(infilename, "-")) {
+ infilesize = (FLAC__off_t)(-1);
+ encode_infile = grabbag__file_get_binary_stdin();
+ }
+ else
+ {
+ infilesize = grabbag__file_get_filesize(infilename);
+ if(0 == (encode_infile = flac_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 */
+ infilename_length = strlen(infilename);
+ if(infilename_length >= 4 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-4), ".wav"))
+ input_format = FORMAT_WAVE;
+ else if(infilename_length >= 5 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-5), ".rf64"))
+ input_format = FORMAT_RF64;
+ else if(infilename_length >= 4 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-4), ".w64"))
+ input_format = FORMAT_WAVE64;
+ else if(infilename_length >= 4 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-4), ".aif"))
+ input_format = FORMAT_AIFF;
+ else if(infilename_length >= 5 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-5), ".aiff"))
+ input_format = FORMAT_AIFF;
+ else if(infilename_length >= 5 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-5), ".flac"))
+ input_format = FORMAT_FLAC;
+ else if(infilename_length >= 4 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-4), ".oga"))
+ input_format = FORMAT_OGGFLAC;
+ else if(infilename_length >= 4 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-4), ".ogg"))
+ input_format = FORMAT_OGGFLAC;
+
+ /* attempt to guess the file type based on the first 12 bytes */
+ if((lookahead_length = fread(lookahead, 1, 12, encode_infile)) < 12) {
+ /* all supported non-raw formats have at least 12 bytes of header to read */
+ if(input_format != FORMAT_RAW) {
+ format_mistake(infilename, input_format, FORMAT_RAW);
+ if(option_values.treat_warnings_as_errors) {
+ conditional_fclose(encode_infile);
+ return 1;
+ }
+ }
+ /* force to raw */
+ input_format = FORMAT_RAW;
+ }
+ else {
+ if(!memcmp(lookahead, "ID3", 3)) {
+ flac__utils_printf(stderr, 1, "ERROR: input file %s has an ID3v2 tag\n", infilename);
+ conditional_fclose(encode_infile);
+ return 1;
+ }
+ else if(!memcmp(lookahead, "RIFF", 4) && !memcmp(lookahead+8, "WAVE", 4))
+ input_format = FORMAT_WAVE;
+ else if(!memcmp(lookahead, "RF64", 4) && !memcmp(lookahead+8, "WAVE", 4))
+ input_format = FORMAT_RF64;
+ else if(!memcmp(lookahead, "riff\x2E\x91\xCF\x11\xA5\xD6\x28\xDB", 12)) /* just check 1st 12 bytes of GUID */
+ input_format = FORMAT_WAVE64;
+ else if(!memcmp(lookahead, "FORM", 4) && !memcmp(lookahead+8, "AIFF", 4))
+ input_format = FORMAT_AIFF;
+ else if(!memcmp(lookahead, "FORM", 4) && !memcmp(lookahead+8, "AIFC", 4))
+ input_format = FORMAT_AIFF_C;
+ else if(!memcmp(lookahead, FLAC__STREAM_SYNC_STRING, sizeof(FLAC__STREAM_SYNC_STRING)))
+ input_format = FORMAT_FLAC;
+ /*@@@ this could be made more accurate by looking at the first packet to make sure it's Ogg FLAC and not, say, Ogg Vorbis. we do catch such problems later though. */
+ else if(!memcmp(lookahead, "OggS", 4))
+ input_format = FORMAT_OGGFLAC;
+ else {
+ /* didn't find header of any supported format */
+ if(input_format != FORMAT_RAW) {
+ format_mistake(infilename, input_format, FORMAT_RAW);
+ if(option_values.treat_warnings_as_errors) {
+ conditional_fclose(encode_infile);
+ return 1;
+ }
+ }
+ /* force to raw */
+ input_format = FORMAT_RAW;
+ }
+ }
+ }
+
+ if(!option_values.ignore_chunk_sizes
+ && (input_format == FORMAT_WAVE || input_format == FORMAT_AIFF || input_format == FORMAT_AIFF_C)
+ && infilesize >= UINT32_MAX) {
+ conditional_fclose(encode_infile);
+ return usage_error("ERROR: file %s is too large to be valid.\n"
+ "Please consult the manual on the --ignore-chunk-sizes option\n\n", infilename);
+ }
+
+ if(input_format == FORMAT_WAVE || input_format == FORMAT_AIFF || input_format == FORMAT_AIFF_C) {
+ memcpy(&master_chunk_size,lookahead+4,sizeof(master_chunk_size));
+ if((input_format != FORMAT_WAVE) != CPU_IS_BIG_ENDIAN /* logical xor */)
+ /* true for WAVE on big endian CPUs or AIFF/AIFF-C on little endian CPUs */
+ master_chunk_size = ENDSWAP_32(master_chunk_size);
+
+ if(infilesize != (FLAC__off_t)(-1) && infilesize > 8 && (infilesize - 8) != master_chunk_size) {
+ flac__utils_printf(stderr, 1, "WARNING: %s chunk size of file %s does not agree with filesize\n", (input_format == FORMAT_WAVE)?"RIFF":"FORM", infilename);
+ if(option_values.treat_warnings_as_errors)
+ return 1;
+ }
+ }
+
+ if(option_values.keep_foreign_metadata || option_values.keep_foreign_metadata_if_present) {
+ 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 != FORMAT_WAVE && input_format != FORMAT_WAVE64 && input_format != FORMAT_RF64 && input_format != FORMAT_AIFF && input_format != FORMAT_AIFF_C) {
+ conditional_fclose(encode_infile);
+ return usage_error("ERROR: --keep-foreign-metadata can only be used with WAVE, Wave64, RF64, 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) != (FLAC__off_t)(-1)) {
+ if(input_format == 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 == 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 != 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(input_format == 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");
+ }
+ }
+ else {
+ 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: raw format options (--endian, --sign, --channels, --bps, and --sample-rate) are not allowed for non-raw input\n");
+ }
+ }
+
+ if(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, &encode_options.skip_specification) || encode_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, &encode_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)
+ encode_options.until_specification.is_relative = true;
+
+ encode_options.verify = option_values.verify;
+ encode_options.treat_warnings_as_errors = option_values.treat_warnings_as_errors;
+#if FLAC__HAS_OGG
+ encode_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;
+ }
+ encode_options.serial_number = option_values.serial_number++;
+#endif
+ encode_options.lax = option_values.lax;
+ encode_options.padding = option_values.padding;
+ encode_options.num_compression_settings = option_values.num_compression_settings;
+ FLAC__ASSERT(sizeof(encode_options.compression_settings) >= sizeof(option_values.compression_settings));
+ memcpy(encode_options.compression_settings, option_values.compression_settings, sizeof(option_values.compression_settings));
+ encode_options.requested_seek_points = option_values.requested_seek_points;
+ encode_options.num_requested_seek_points = option_values.num_requested_seek_points;
+ encode_options.cuesheet_filename = option_values.cuesheet_filename;
+ encode_options.continue_through_decode_errors = option_values.continue_through_decode_errors;
+ encode_options.cued_seekpoints = option_values.cued_seekpoints;
+ encode_options.channel_map_none = option_values.channel_map_none;
+ encode_options.is_first_file = is_first_file;
+ encode_options.is_last_file = is_last_file;
+ encode_options.replay_gain = option_values.replay_gain;
+ encode_options.ignore_chunk_sizes = option_values.ignore_chunk_sizes;
+ encode_options.vorbis_comment = option_values.vorbis_comment;
+ FLAC__ASSERT(sizeof(encode_options.pictures) >= sizeof(option_values.pictures));
+ memcpy(encode_options.pictures, option_values.pictures, sizeof(option_values.pictures));
+ encode_options.num_pictures = option_values.num_pictures;
+ encode_options.format = input_format;
+ encode_options.debug.disable_constant_subframes = option_values.debug.disable_constant_subframes;
+ encode_options.debug.disable_fixed_subframes = option_values.debug.disable_fixed_subframes;
+ encode_options.debug.disable_verbatim_subframes = option_values.debug.disable_verbatim_subframes;
+ encode_options.debug.do_md5 = option_values.debug.do_md5;
+ encode_options.error_on_compression_fail = option_values.error_on_compression_fail;
+ encode_options.limit_min_bitrate = option_values.limit_min_bitrate;
+ encode_options.relaxed_foreign_metadata_handling = option_values.keep_foreign_metadata_if_present;
+
+ /* 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";
+ size_t dest_len = strlen(outfilename) + strlen(tmp_suffix) + 1;
+ /*@@@@ still a remote possibility that a file with this filename exists */
+ if((internal_outfilename = safe_malloc_(dest_len)) == NULL) {
+ flac__utils_printf(stderr, 1, "ERROR allocating memory for tempfile name\n");
+ conditional_fclose(encode_infile);
+ return 1;
+ }
+ flac_snprintf(internal_outfilename, dest_len, "%s%s", outfilename, tmp_suffix);
+ }
+
+ if(input_format == FORMAT_RAW) {
+ encode_options.format_options.raw.is_big_endian = option_values.format_is_big_endian;
+ encode_options.format_options.raw.is_unsigned_samples = option_values.format_is_unsigned_samples;
+ encode_options.format_options.raw.channels = option_values.format_channels;
+ encode_options.format_options.raw.bps = option_values.format_bps;
+ encode_options.format_options.raw.sample_rate = option_values.format_sample_rate;
+
+ retval = flac__encode_file(encode_infile, infilesize, infilename, internal_outfilename? internal_outfilename : outfilename, lookahead, lookahead_length, encode_options);
+ }
+ else if(input_format == FORMAT_FLAC || input_format == FORMAT_OGGFLAC) {
+ retval = flac__encode_file(encode_infile, infilesize, infilename, internal_outfilename? internal_outfilename : outfilename, lookahead, lookahead_length, encode_options);
+ }
+ else if(input_format == FORMAT_WAVE || input_format == FORMAT_WAVE64 || input_format == FORMAT_RF64 || input_format == FORMAT_AIFF || input_format == FORMAT_AIFF_C) {
+ encode_options.format_options.iff.foreign_metadata = 0;
+
+ /* initialize foreign metadata if requested */
+ if(option_values.keep_foreign_metadata || option_values.keep_foreign_metadata_if_present) {
+ encode_options.format_options.iff.foreign_metadata =
+ flac__foreign_metadata_new(
+ input_format==FORMAT_WAVE || input_format==FORMAT_RF64?
+ FOREIGN_BLOCK_TYPE__RIFF :
+ input_format==FORMAT_WAVE64?
+ FOREIGN_BLOCK_TYPE__WAVE64 :
+ FOREIGN_BLOCK_TYPE__AIFF
+ );
+ if(0 == encode_options.format_options.iff.foreign_metadata) {
+ flac__utils_printf(stderr, 1, "ERROR: creating foreign metadata object\n");
+ conditional_fclose(encode_infile);
+ if(internal_outfilename != 0)
+ free(internal_outfilename);
+ return 1;
+ }
+ }
+
+ retval = flac__encode_file(encode_infile, infilesize, infilename, internal_outfilename? internal_outfilename : outfilename, lookahead, lookahead_length, encode_options);
+
+ if(encode_options.format_options.iff.foreign_metadata)
+ flac__foreign_metadata_delete(encode_options.format_options.iff.foreign_metadata);
+ }
+ else {
+ FLAC__ASSERT(0);
+ retval = 1; /* double protection */
+ }
+
+ 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, option_values.preserve_modtime)) ||
+ 0 != (error = grabbag__replaygain_store_to_file_title(internal_outfilename? internal_outfilename : outfilename, title_gain, title_peak, option_values.preserve_modtime))
+ ) {
+ flac__utils_printf(stderr, 1, "%s: ERROR writing ReplayGain reference/title tags (%s)\n", outfilename, error);
+ retval = 1;
+ }
+ }
+ if(option_values.preserve_modtime && strcmp(infilename, "-"))
+ grabbag__file_copy_metadata(infilename, internal_outfilename? internal_outfilename : outfilename);
+ }
+ }
+
+ /* rename temporary file if necessary */
+ if(retval == 0 && internal_outfilename != 0) {
+ if(flac_rename(internal_outfilename, outfilename) < 0) {
+#if defined _MSC_VER || defined __MINGW32__ || defined __EMX__
+ /* on some flavors of windows, flac_rename() will fail if the destination already exists, so we unlink and try again */
+ if(flac_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(flac_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)
+ flac_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 = FORMAT_WAVE;
+ FileSubFormat output_subformat = SUBFORMAT_UNSPECIFIED;
+ decode_options_t decode_options;
+ foreign_metadata_t *foreign_metadata = 0;
+ const char *outfilename = get_outfilename(infilename, ". "); /* Placeholder until we know what the actual suffix is */
+ size_t infilename_length;
+
+ if(0 == outfilename) {
+ flac__utils_printf(stderr, 1, "ERROR: filename too long: %s", infilename);
+ return 1;
+ }
+
+ if(!option_values.analyze && !option_values.test_only &&(option_values.keep_foreign_metadata || option_values.keep_foreign_metadata_if_present)) {
+ const char *error;
+ 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 == FORMAT_RAW)
+ return usage_error("ERROR: --keep-foreign-metadata cannot be used with raw output\n");
+ decode_options.format_options.iff.foreign_metadata = 0;
+ /* initialize foreign metadata structure */
+ foreign_metadata = flac__foreign_metadata_new(FOREIGN_BLOCK_TYPE__RIFF); /* RIFF is just a placeholder */
+ if(0 == foreign_metadata) {
+ flac__utils_printf(stderr, 1, "ERROR: creating foreign metadata object\n");
+ return 1;
+ }
+ if(!flac__foreign_metadata_read_from_flac(foreign_metadata, infilename, &error)) {
+ if(option_values.keep_foreign_metadata_if_present) {
+ flac__utils_printf(stderr, 1, "%s: WARNING reading foreign metadata: %s\n", infilename, error);
+ if(option_values.treat_warnings_as_errors) {
+ flac__foreign_metadata_delete(foreign_metadata);
+ return 1;
+ }
+ else {
+ /* Couldn't find foreign metadata, stop processing */
+ flac__foreign_metadata_delete(foreign_metadata);
+ foreign_metadata = 0;
+ }
+ }
+ else {
+ flac__utils_printf(stderr, 1, "%s: ERROR reading foreign metadata: %s\n", infilename, error);
+ flac__foreign_metadata_delete(foreign_metadata);
+ return 1;
+ }
+ }
+ }
+
+ if(option_values.force_raw_format)
+ output_format = 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 = FORMAT_AIFF;
+ else if(
+ option_values.force_rf64_format ||
+ (strlen(outfilename) >= 5 && 0 == FLAC__STRCASECMP(outfilename+(strlen(outfilename)-5), ".rf64"))
+ )
+ output_format = FORMAT_RF64;
+ else if(
+ option_values.force_wave64_format ||
+ (strlen(outfilename) >= 4 && 0 == FLAC__STRCASECMP(outfilename+(strlen(outfilename)-4), ".w64"))
+ )
+ output_format = FORMAT_WAVE64;
+ else if(foreign_metadata != NULL) {
+ /* Pick a format based on what the foreign metadata contains */
+ if(foreign_metadata->type == FOREIGN_BLOCK_TYPE__WAVE64)
+ output_format = FORMAT_WAVE64;
+ else if(foreign_metadata->is_rf64)
+ output_format = FORMAT_RF64;
+ else if(foreign_metadata->type == FOREIGN_BLOCK_TYPE__AIFF) {
+ output_format = FORMAT_AIFF;
+ if(foreign_metadata->is_aifc) {
+ output_format = FORMAT_AIFF_C;
+ }
+ }
+ else
+ output_format = FORMAT_WAVE;
+ }
+ else
+ output_format = FORMAT_WAVE;
+
+ /* Now do subformats */
+ if(option_values.force_legacy_wave_format)
+ output_subformat = SUBFORMAT_WAVE_PCM;
+ else if(option_values.force_extensible_wave_format)
+ output_subformat = SUBFORMAT_WAVE_EXTENSIBLE;
+ else if(option_values.force_aiff_c_none_format) {
+ output_format = FORMAT_AIFF_C;
+ output_subformat = SUBFORMAT_AIFF_C_NONE;
+ }
+ else if(option_values.force_aiff_c_sowt_format) {
+ output_format = FORMAT_AIFF_C;
+ output_subformat = SUBFORMAT_AIFF_C_SOWT;
+ }
+ else if(foreign_metadata != NULL) {
+ if(foreign_metadata->is_wavefmtex)
+ output_subformat = SUBFORMAT_WAVE_EXTENSIBLE;
+ else if(output_format == FORMAT_WAVE)
+ output_subformat = SUBFORMAT_WAVE_PCM;
+ else if(foreign_metadata->is_aifc) {
+ if(foreign_metadata->is_sowt)
+ output_subformat = SUBFORMAT_AIFF_C_SOWT;
+ else
+ output_subformat = SUBFORMAT_AIFF_C_NONE;
+ }
+ }
+
+
+ /* Check whether output format agrees with foreign metadata */
+ if(foreign_metadata != NULL) {
+ if((output_format != FORMAT_WAVE && output_format != FORMAT_RF64) && foreign_metadata->type == FOREIGN_BLOCK_TYPE__RIFF) {
+ flac__foreign_metadata_delete(foreign_metadata);
+ return usage_error("ERROR: foreign metadata type RIFF cannot be restored to a%s file, only to WAVE and RF64\n",FileFormatString[output_format]);
+ }
+ if((output_format != FORMAT_AIFF && output_format != FORMAT_AIFF_C) && foreign_metadata->type == FOREIGN_BLOCK_TYPE__AIFF) {
+ flac__foreign_metadata_delete(foreign_metadata);
+ return usage_error("ERROR: foreign metadata type AIFF cannot be restored to a%s file, only to AIFF and AIFF-C\n",FileFormatString[output_format]);
+ }
+ if(output_format != FORMAT_WAVE64 && foreign_metadata->type == FOREIGN_BLOCK_TYPE__WAVE64) {
+ flac__foreign_metadata_delete(foreign_metadata);
+ return usage_error("ERROR: foreign metadata type Wave64 cannot be restored to a%s file, only to Wave64\n",FileFormatString[output_format]);
+ }
+ }
+
+ /* Now reassemble outfilename */
+ get_decoded_outfilename(infilename, output_format);
+
+ /*
+ * 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) != (FLAC__off_t)(-1)) {
+ flac__utils_printf(stderr, 1, "ERROR: output file %s already exists, use -f to override\n", outfilename);
+ flac__foreign_metadata_delete(foreign_metadata);
+ return 1;
+ }
+
+ if(!option_values.test_only && !option_values.analyze) {
+ if(output_format == FORMAT_RAW && (option_values.format_is_big_endian < 0 || option_values.format_is_unsigned_samples < 0)) {
+ flac__foreign_metadata_delete(foreign_metadata);
+ return usage_error("ERROR: for decoding to a raw file you must specify a value for --endian and --sign\n");
+ }
+ }
+
+ infilename_length = strlen(infilename);
+ if(option_values.use_ogg)
+ treat_as_ogg = true;
+ else if(infilename_length >= 4 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-4), ".oga"))
+ treat_as_ogg = true;
+ else if(infilename_length >= 4 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-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);
+ flac__foreign_metadata_delete(foreign_metadata);
+ return 1;
+ }
+#endif
+
+ if(!flac__utils_parse_skip_until_specification(option_values.skip_specification, &decode_options.skip_specification) || decode_options.skip_specification.is_relative) {
+ flac__foreign_metadata_delete(foreign_metadata);
+ return usage_error("ERROR: invalid value for --skip\n");
+ }
+
+ if(!flac__utils_parse_skip_until_specification(option_values.until_specification, &decode_options.until_specification)) { /*@@@ more checks: no + without --skip, no - unless known total_samples_to_{en,de}code */
+ flac__foreign_metadata_delete(foreign_metadata);
+ 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)
+ decode_options.until_specification.is_relative = true;
+
+ if(option_values.cue_specification) {
+ if(!flac__utils_parse_cue_specification(option_values.cue_specification, &decode_options.cue_specification)) {
+ flac__foreign_metadata_delete(foreign_metadata);
+ return usage_error("ERROR: invalid value for --cue\n");
+ }
+ decode_options.has_cue_specification = true;
+ }
+ else
+ decode_options.has_cue_specification = false;
+
+ decode_options.treat_warnings_as_errors = option_values.treat_warnings_as_errors;
+ decode_options.continue_through_decode_errors = option_values.continue_through_decode_errors;
+ decode_options.relaxed_foreign_metadata_handling = option_values.keep_foreign_metadata_if_present;
+ decode_options.replaygain_synthesis_spec = option_values.replaygain_synthesis_spec;
+ decode_options.force_subformat = output_subformat;
+#if FLAC__HAS_OGG
+ decode_options.is_ogg = treat_as_ogg;
+ decode_options.use_first_serial_number = !option_values.has_serial_number;
+ decode_options.serial_number = option_values.serial_number;
+#endif
+ decode_options.channel_map_none = option_values.channel_map_none;
+ decode_options.format = output_format;
+
+ if(output_format == FORMAT_RAW) {
+ decode_options.format_options.raw.is_big_endian = option_values.format_is_big_endian;
+ decode_options.format_options.raw.is_unsigned_samples = option_values.format_is_unsigned_samples;
+
+ retval = flac__decode_file(infilename, option_values.test_only? 0 : outfilename, option_values.analyze, option_values.aopts, decode_options);
+ }
+ else {
+ decode_options.format_options.iff.foreign_metadata = foreign_metadata;
+
+ retval = flac__decode_file(infilename, option_values.test_only? 0 : outfilename, option_values.analyze, option_values.aopts, decode_options);
+
+ }
+
+ if(foreign_metadata)
+ flac__foreign_metadata_delete(foreign_metadata);
+
+ if(retval == 0 && strcmp(infilename, "-")) {
+ if(option_values.preserve_modtime && strcmp(outfilename, "-"))
+ grabbag__file_copy_metadata(infilename, outfilename);
+ if(option_values.delete_input && !option_values.test_only && !option_values.analyze)
+ flac_unlink(infilename);
+ }
+
+ return retval;
+}
+
+const char *get_encoded_outfilename(const char *infilename)
+{
+ const char *suffix = (option_values.use_ogg? ".oga" : ".flac");
+ const char *p;
+
+ if(option_values.output_prefix) {
+ p = grabbag__file_get_basename(infilename);
+ }
+ else {
+ p = infilename;
+ }
+
+ return get_outfilename(p, suffix);
+}
+
+const char *get_decoded_outfilename(const char *infilename, const FileFormat format)
+{
+ const char *suffix;
+ const char *p;
+
+ if(option_values.output_prefix) {
+ p = grabbag__file_get_basename(infilename);
+ }
+ else {
+ p = infilename;
+ }
+
+ if(option_values.analyze) {
+ suffix = ".ana";
+ }
+ else if(format == FORMAT_RAW) {
+ suffix = ".raw";
+ }
+ else if(format == FORMAT_AIFF) {
+ suffix = ".aiff";
+ }
+ else if(format == FORMAT_AIFF_C) {
+ suffix = ".aifc";
+ }
+ else if(format == FORMAT_RF64) {
+ suffix = ".rf64";
+ }
+ else if(format == FORMAT_WAVE64) {
+ suffix = ".w64";
+ }
+ else {
+ suffix = ".wav";
+ }
+ return get_outfilename(p, suffix);
+}
+
+const char *get_outfilename(const char *infilename, const char *suffix)
+{
+ if(0 == option_values.cmdline_forced_outfilename) {
+ static char buffer[4096];
+
+ if(0 == strcmp(infilename, "-") || option_values.force_to_stdout) {
+ buffer [0] = '-';
+ buffer [1] = 0;
+ }
+ 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;
+}
diff --git a/src/flac/utils.c b/src/flac/utils.c
new file mode 100644
index 0000000..446150d
--- /dev/null
+++ b/src/flac/utils.c
@@ -0,0 +1,439 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <math.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "utils.h"
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+#include "share/compat.h"
+#ifndef _WIN32
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE
+#endif
+#include <wchar.h>
+#ifdef HAVE_TERMIOS_H
+# include <termios.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+#endif
+
+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') {
+ if(ret > UINT64_MAX / 10) /* check for overflow */
+ return false;
+ else if(ret == UINT64_MAX / 10) {
+ FLAC__uint64 tmp = ret;
+ ret = ret * 10 + (c - '0');
+ if(ret < tmp)
+ return false;
+ }
+ else
+ 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;
+ uint32_t i;
+ char c, *endptr;
+
+ /* 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;
+ ret += strtod(s, &endptr);
+ if (endptr == s || *endptr)
+ return false;
+
+ *value = ret;
+ return true;
+}
+
+static FLAC__bool local__parse_cue_(const char *s, const char *end, uint32_t *track, uint32_t *indx)
+{
+ FLAC__bool got_track = false, got_index = false;
+ uint32_t 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;
+ *indx = 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, uint32_t track, uint32_t indx, 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 >= indx))
+ 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 <= indx))
+ 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) flac_vfprintf(stream, format, args);
+
+ va_end(args);
+
+#ifdef _MSC_VER
+ if(stream == stderr)
+ fflush(stream); /* for some reason stderr is buffered in at least some if not all MSC libs */
+#endif
+ }
+}
+
+/* variables and functions for console status output */
+static FLAC__bool is_name_printed;
+static int stats_char_count = 0;
+static int console_width;
+static int console_chars_left;
+
+int get_console_width(void)
+{
+ int width = 0;
+#if defined _WIN32
+ width = win_get_console_width();
+#elif defined __EMX__
+ int s[2];
+ _scrsize (s);
+ width = s[0];
+#elif defined TIOCGWINSZ
+ struct winsize w;
+ if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1)
+ width = w.ws_col;
+#endif
+ if (width <= 0)
+ width = 80;
+ return width;
+}
+
+size_t strlen_console(const char *text)
+{
+#ifdef _WIN32
+ return strlen_utf8(text);
+#elif defined(__DJGPP__) /* workaround for DJGPP missing wcswidth() */
+ return strlen(text);
+#else
+ size_t len;
+ wchar_t *wtmp;
+
+ len = strlen(text)+1;
+ wtmp = (wchar_t *)malloc(len*sizeof(wchar_t));
+ if (wtmp == NULL) return len-1;
+ mbstowcs(wtmp, text, len);
+ len = wcswidth(wtmp, len);
+ free(wtmp);
+
+ return len;
+#endif
+}
+
+void stats_new_file(void)
+{
+ is_name_printed = false;
+}
+
+void stats_clear(void)
+{
+ while (stats_char_count > 0 && stats_char_count--)
+ fprintf(stderr, "\b");
+}
+
+void stats_print_name(int level, const char *name)
+{
+ int len;
+
+ if (flac__utils_verbosity_ >= level) {
+ stats_clear();
+ if(is_name_printed) return;
+
+ console_width = get_console_width();
+ len = strlen_console(name)+2;
+ console_chars_left = console_width - (len % console_width);
+ flac_fprintf(stderr, "%s: ", name);
+ is_name_printed = true;
+ }
+}
+
+void stats_print_info(int level, const char *format, ...)
+{
+ char tmp[80];
+ int len, clear_len;
+
+ if (flac__utils_verbosity_ >= level) {
+ va_list args;
+ va_start(args, format);
+ len = flac_vsnprintf(tmp, sizeof(tmp), format, args);
+ va_end(args);
+ stats_clear();
+ if (len >= console_chars_left) {
+ clear_len = console_chars_left;
+ while (clear_len > 0 && clear_len--) fprintf(stderr, " ");
+ fprintf(stderr, "\n");
+ console_chars_left = console_width;
+ }
+ stats_char_count = fprintf(stderr, "%s", tmp);
+ fflush(stderr);
+ }
+}
+
+#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;
+ if(val > INT64_MAX)
+ return false;
+ 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;
+}
+
+FLAC__bool flac__utils_canonicalize_skip_until_specification(utils__SkipUntilSpecification *spec, uint32_t sample_rate)
+{
+ FLAC__ASSERT(0 != spec);
+ if(!spec->value_is_samples) {
+ double samples = spec->value.seconds * (double)sample_rate;
+ if(samples >= (double)INT64_MAX || samples <= (double)INT64_MIN)
+ return false;
+ spec->value.samples = (FLAC__int64)(samples);
+ spec->value_is_samples = true;
+ }
+ return 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((entry.length = flac_snprintf(tag, sizeof(tag), "%s=0x%04X", CHANNEL_MASK_TAG, (uint32_t)channel_mask)) >= sizeof(tag))
+ 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;
+ uint32_t 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(FLAC__STRNCASECMP(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
index 0000000..931b4a6
--- /dev/null
+++ b/src/flac/utils.h
@@ -0,0 +1,77 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef flac__utils_h
+#define flac__utils_h
+
+#ifdef 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 enum { FORMAT_RAW, FORMAT_WAVE, FORMAT_WAVE64, FORMAT_RF64, FORMAT_AIFF, FORMAT_AIFF_C, FORMAT_FLAC, FORMAT_OGGFLAC } FileFormat;
+static const char * const FileFormatString[] = { " raw", " WAVE", " Wave64", "n RF64", "n AIFF", "n AIFF-C", " FLAC", "n Ogg FLAC" };
+
+typedef enum { SUBFORMAT_UNSPECIFIED = 0, SUBFORMAT_WAVE_PCM, SUBFORMAT_WAVE_EXTENSIBLE, SUBFORMAT_AIFF_C_NONE, SUBFORMAT_AIFF_C_SOWT } FileSubFormat;
+
+
+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, ...);
+
+int get_console_width(void);
+size_t strlen_console(const char *text);
+void stats_new_file(void);
+void stats_clear(void);
+void stats_print_name(int level, const char *name);
+void stats_print_info(int level, const char *format, ...);
+
+FLAC__bool flac__utils_parse_skip_until_specification(const char *s, utils__SkipUntilSpecification *spec);
+FLAC__bool flac__utils_canonicalize_skip_until_specification(utils__SkipUntilSpecification *spec, uint32_t 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/version.rc b/src/flac/version.rc
new file mode 100644
index 0000000..00842b9
--- /dev/null
+++ b/src/flac/version.rc
@@ -0,0 +1,38 @@
+#include <winver.h>
+#include "config.h"
+
+#if (defined GIT_COMMIT_HASH && defined GIT_COMMIT_DATE)
+# ifdef GIT_COMMIT_TAG
+# define VERSIONSTRING GIT_COMMIT_TAG
+# else
+# define VERSIONSTRING "git-" GIT_COMMIT_HASH
+# endif
+#else
+# define VERSIONSTRING PACKAGE_VERSION
+#endif
+
+#define xstr(s) str(s)
+#define str(s) #s
+
+VS_VERSION_INFO VERSIONINFO
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+FILEFLAGS 0
+FILEOS VOS__WINDOWS32
+FILETYPE VFT_DLL
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "FileDescription", "flac command line tool for Windows"
+ VALUE "ProductName", "Free Lossless Audio Codec"
+ VALUE "ProductVersion", VERSIONSTRING
+ VALUE "CompanyName", "Xiph.Org"
+ VALUE "LegalCopyright", "2000-2009 Josh Coalson, 2011-2023 Xiph.Org Foundation"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/src/flac/vorbiscomment.c b/src/flac/vorbiscomment.c
new file mode 100644
index 0000000..3941ec2
--- /dev/null
+++ b/src/flac/vorbiscomment.c
@@ -0,0 +1,254 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "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>
+#include "share/compat.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 */
+ uint32_t 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, uint32_t *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 = NULL;
+
+ 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 FLAC__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 = flac_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;
+#ifdef _WIN32 /* everything in UTF-8 already. Must not alter */
+ entry.entry = (FLAC__byte *)field->field;
+#else
+ 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;
+ }
+#endif
+ 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 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(parsed.field_value_length > 0 && !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
index 0000000..a6dcb16
--- /dev/null
+++ b/src/flac/vorbiscomment.h
@@ -0,0 +1,27 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#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++/CMakeLists.txt b/src/libFLAC++/CMakeLists.txt
new file mode 100644
index 0000000..3be43ba
--- /dev/null
+++ b/src/libFLAC++/CMakeLists.txt
@@ -0,0 +1,41 @@
+add_library(FLAC++
+ metadata.cpp
+ stream_decoder.cpp
+ stream_encoder.cpp
+ version.rc)
+set_property(TARGET FLAC++ PROPERTY PROJECT_LABEL "libFLAC++")
+target_compile_definitions(FLAC++
+ PRIVATE $<$<BOOL:${BUILD_SHARED_LIBS}>:FLACPP_API_EXPORTS>
+ PUBLIC $<$<NOT:$<BOOL:${BUILD_SHARED_LIBS}>>:FLAC__NO_DLL>)
+if(NOT WIN32)
+ target_compile_definitions(FLAC++ PRIVATE $<$<BOOL:${BUILD_SHARED_LIBS}>:FLAC__USE_VISIBILITY_ATTR>)
+endif()
+target_include_directories(FLAC++ INTERFACE
+ "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>"
+ "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
+target_link_libraries(FLAC++ PUBLIC FLAC)
+if(BUILD_SHARED_LIBS)
+ set_target_properties(FLAC++ PROPERTIES
+ VERSION 10.0.1
+ SOVERSION 10)
+ if(NOT WIN32)
+ set_target_properties(FLAC++ PROPERTIES CXX_VISIBILITY_PRESET hidden)
+ endif()
+endif()
+
+add_library(FLAC::FLAC++ ALIAS FLAC++)
+
+install(TARGETS FLAC++ EXPORT targets
+ ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}/"
+ LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/"
+ RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}/")
+
+if(INSTALL_PKGCONFIG_MODULES)
+ set(prefix "${CMAKE_INSTALL_PREFIX}")
+ set(exec_prefix "${CMAKE_INSTALL_PREFIX}")
+ set(libdir "${CMAKE_INSTALL_FULL_LIBDIR}")
+ set(includedir "${CMAKE_INSTALL_FULL_INCLUDEDIR}")
+ configure_file(flac++.pc.in flac++.pc @ONLY)
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/flac++.pc"
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
+endif()
diff --git a/src/libFLAC++/Makefile.am b/src/libFLAC++/Makefile.am
new file mode 100644
index 0000000..0b2853b
--- /dev/null
+++ b/src/libFLAC++/Makefile.am
@@ -0,0 +1,68 @@
+# libFLAC++ - Free Lossless Audio Codec library
+# Copyright (C) 2002-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# 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
+noinst_LTLIBRARIES = libFLAC++-static.la
+
+m4datadir = $(datadir)/aclocal
+m4data_DATA = libFLAC++.m4
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = flac++.pc
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+EXTRA_DIST = \
+ CMakeLists.txt \
+ flac++.pc.in \
+ libFLAC++.m4 \
+ version.rc
+
+libFLAC___sources = \
+ metadata.cpp \
+ stream_decoder.cpp \
+ stream_encoder.cpp
+
+if OS_IS_WINDOWS
+if HAVE_WINDRES
+libFLAC___la_DEPENDENCIES = version.o
+windows_resource_link = -Wl,version.o
+endif
+endif
+
+# see 'http://www.gnu.org/software/libtool/manual/libtool.html#Libtool-versioning' for numbering convention
+libFLAC___la_LDFLAGS = $(AM_LDFLAGS) -no-undefined -version-info 10:1:0 $(windows_resource_link)
+libFLAC___la_LIBADD = ../libFLAC/libFLAC.la
+libFLAC___la_SOURCES = $(libFLAC___sources)
+
+libFLAC___static_la_SOURCES = $(libFLAC___sources)
+libFLAC___static_la_LIBADD = ../libFLAC/libFLAC-static.la
+
+.rc.o:
+ $(RC) $(AM_CPPFLAGS) $< $@
diff --git a/src/libFLAC++/Makefile.in b/src/libFLAC++/Makefile.in
new file mode 100644
index 0000000..eff1fca
--- /dev/null
+++ b/src/libFLAC++/Makefile.in
@@ -0,0 +1,831 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in 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.
+
+@SET_MAKE@
+
+# libFLAC++ - Free Lossless Audio Codec library
+# Copyright (C) 2002-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# 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.
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@HAVE_WINDRES_FALSE@libFLAC___la_DEPENDENCIES = ../libFLAC/libFLAC.la
+@OS_IS_WINDOWS_FALSE@libFLAC___la_DEPENDENCIES = \
+@OS_IS_WINDOWS_FALSE@ ../libFLAC/libFLAC.la
+subdir = src/libFLAC++
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/add_cflags.m4 \
+ $(top_srcdir)/m4/add_cxxflags.m4 \
+ $(top_srcdir)/m4/ax_add_fortify_source.m4 \
+ $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_enable_debug.m4 \
+ $(top_srcdir)/m4/bswap.m4 $(top_srcdir)/m4/clang.m4 \
+ $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gcc_version.m4 \
+ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/ogg.m4 \
+ $(top_srcdir)/m4/really_gcc.m4 \
+ $(top_srcdir)/m4/stack_protect.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = flac++.pc
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(m4datadir)" \
+ "$(DESTDIR)$(pkgconfigdir)"
+LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES)
+libFLAC___static_la_DEPENDENCIES = ../libFLAC/libFLAC-static.la
+am__objects_1 = metadata.lo stream_decoder.lo stream_encoder.lo
+am_libFLAC___static_la_OBJECTS = $(am__objects_1)
+libFLAC___static_la_OBJECTS = $(am_libFLAC___static_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+am_libFLAC___la_OBJECTS = $(am__objects_1)
+libFLAC___la_OBJECTS = $(am_libFLAC___la_OBJECTS)
+libFLAC___la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(libFLAC___la_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/metadata.Plo \
+ ./$(DEPDIR)/stream_decoder.Plo ./$(DEPDIR)/stream_encoder.Plo
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+SOURCES = $(libFLAC___static_la_SOURCES) $(libFLAC___la_SOURCES)
+DIST_SOURCES = $(libFLAC___static_la_SOURCES) $(libFLAC___la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+DATA = $(m4data_DATA) $(pkgconfig_DATA)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/flac++.pc.in \
+ $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_64_BIT_WORDS = @ENABLE_64_BIT_WORDS@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLAC__HAS_OGG = @FLAC__HAS_OGG@
+FLAC__TEST_LEVEL = @FLAC__TEST_LEVEL@
+FLAC__TEST_WITH_VALGRIND = @FLAC__TEST_WITH_VALGRIND@
+GCC_MAJOR_VERSION = @GCC_MAJOR_VERSION@
+GCC_MINOR_VERSION = @GCC_MINOR_VERSION@
+GCC_VERSION = @GCC_VERSION@
+GIT_COMMIT_VERSION_HASH = @GIT_COMMIT_VERSION_HASH@
+GIT_FOUND = @GIT_FOUND@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_FUZZING_ENGINE = @LIB_FUZZING_ENGINE@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OBJ_FORMAT = @OBJ_FORMAT@
+OGG_CFLAGS = @OGG_CFLAGS@
+OGG_LIBS = @OGG_LIBS@
+OGG_PACKAGE = @OGG_PACKAGE@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+lib_LTLIBRARIES = libFLAC++.la
+noinst_LTLIBRARIES = libFLAC++-static.la
+m4datadir = $(datadir)/aclocal
+m4data_DATA = libFLAC++.m4
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = flac++.pc
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+EXTRA_DIST = \
+ CMakeLists.txt \
+ flac++.pc.in \
+ libFLAC++.m4 \
+ version.rc
+
+libFLAC___sources = \
+ metadata.cpp \
+ stream_decoder.cpp \
+ stream_encoder.cpp
+
+@HAVE_WINDRES_TRUE@@OS_IS_WINDOWS_TRUE@libFLAC___la_DEPENDENCIES = version.o
+@HAVE_WINDRES_TRUE@@OS_IS_WINDOWS_TRUE@windows_resource_link = -Wl,version.o
+
+# see 'http://www.gnu.org/software/libtool/manual/libtool.html#Libtool-versioning' for numbering convention
+libFLAC___la_LDFLAGS = $(AM_LDFLAGS) -no-undefined -version-info 10:1:0 $(windows_resource_link)
+libFLAC___la_LIBADD = ../libFLAC/libFLAC.la
+libFLAC___la_SOURCES = $(libFLAC___sources)
+libFLAC___static_la_SOURCES = $(libFLAC___sources)
+libFLAC___static_la_LIBADD = ../libFLAC/libFLAC-static.la
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cpp .lo .o .obj .rc
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/libFLAC++/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/libFLAC++/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+flac++.pc: $(top_builddir)/config.status $(srcdir)/flac++.pc.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libFLAC++-static.la: $(libFLAC___static_la_OBJECTS) $(libFLAC___static_la_DEPENDENCIES) $(EXTRA_libFLAC___static_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(CXXLINK) $(libFLAC___static_la_OBJECTS) $(libFLAC___static_la_LIBADD) $(LIBS)
+
+libFLAC++.la: $(libFLAC___la_OBJECTS) $(libFLAC___la_DEPENDENCIES) $(EXTRA_libFLAC___la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libFLAC___la_LINK) -rpath $(libdir) $(libFLAC___la_OBJECTS) $(libFLAC___la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/metadata.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream_decoder.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream_encoder.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.cpp.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-m4dataDATA: $(m4data_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(m4data_DATA)'; test -n "$(m4datadir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(m4datadir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(m4datadir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(m4datadir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(m4datadir)" || exit $$?; \
+ done
+
+uninstall-m4dataDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(m4data_DATA)'; test -n "$(m4datadir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(m4datadir)'; $(am__uninstall_files_from_dir)
+install-pkgconfigDATA: $(pkgconfig_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \
+ done
+
+uninstall-pkgconfigDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(m4datadir)" "$(DESTDIR)$(pkgconfigdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/metadata.Plo
+ -rm -f ./$(DEPDIR)/stream_decoder.Plo
+ -rm -f ./$(DEPDIR)/stream_encoder.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-m4dataDATA install-pkgconfigDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/metadata.Plo
+ -rm -f ./$(DEPDIR)/stream_decoder.Plo
+ -rm -f ./$(DEPDIR)/stream_encoder.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-libLTLIBRARIES uninstall-m4dataDATA \
+ uninstall-pkgconfigDATA
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libLTLIBRARIES clean-libtool \
+ clean-noinstLTLIBRARIES cscopelist-am ctags ctags-am distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am \
+ install-libLTLIBRARIES install-m4dataDATA install-man \
+ install-pdf install-pdf-am install-pkgconfigDATA install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am uninstall-libLTLIBRARIES uninstall-m4dataDATA \
+ uninstall-pkgconfigDATA
+
+.PRECIOUS: Makefile
+
+
+.rc.o:
+ $(RC) $(AM_CPPFLAGS) $< $@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/libFLAC++/flac++.pc.in b/src/libFLAC++/flac++.pc.in
new file mode 100644
index 0000000..f09c251
--- /dev/null
+++ b/src/libFLAC++/flac++.pc.in
@@ -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++
+Cflags: -I${includedir}
diff --git a/src/libFLAC++/libFLAC++.m4 b/src/libFLAC++/libFLAC++.m4
new file mode 100644
index 0000000..e5e1345
--- /dev/null
+++ b/src/libFLAC++/libFLAC++.m4
@@ -0,0 +1,114 @@
+# 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_RUN_IFELSE([AC_LANG_PROGRAM([[
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <FLAC++/decoder.h>
+]],[[
+ 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 occurred. 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++/metadata.cpp b/src/libFLAC++/metadata.cpp
new file mode 100644
index 0000000..beab110
--- /dev/null
+++ b/src/libFLAC++/metadata.cpp
@@ -0,0 +1,1745 @@
+/* libFLAC++ - Free Lossless Audio Codec library
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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++ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "share/alloc.h"
+#include "FLAC++/metadata.h"
+#include "FLAC/assert.h"
+#include <cstdlib> // for malloc(), free()
+#include <cstring> // 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)
+ {
+ if (0 == object)
+ return 0;
+
+ 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;
+ }
+
+ } // namespace local
+
+ 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);
+ if(0 != padding)
+ return new Padding(*padding);
+ if(0 != application)
+ return new Application(*application);
+ if(0 != seektable)
+ return new SeekTable(*seektable);
+ if(0 != vorbiscomment)
+ return new VorbisComment(*vorbiscomment);
+ if(0 != cuesheet)
+ return new CueSheet(*cuesheet);
+ if(0 != picture)
+ return new Picture(*picture);
+ if(0 != unknown)
+ return new Unknown(*unknown);
+
+ 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 static_cast<bool>(object_->is_last);
+ }
+
+ FLAC__MetadataType Prototype::get_type() const
+ {
+ FLAC__ASSERT(is_valid());
+ return object_->type;
+ }
+
+ uint32_t 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()
+ { }
+
+ uint32_t StreamInfo::get_min_blocksize() const
+ {
+ FLAC__ASSERT(is_valid());
+ return object_->data.stream_info.min_blocksize;
+ }
+
+ uint32_t StreamInfo::get_max_blocksize() const
+ {
+ FLAC__ASSERT(is_valid());
+ return object_->data.stream_info.max_blocksize;
+ }
+
+ uint32_t StreamInfo::get_min_framesize() const
+ {
+ FLAC__ASSERT(is_valid());
+ return object_->data.stream_info.min_framesize;
+ }
+
+ uint32_t StreamInfo::get_max_framesize() const
+ {
+ FLAC__ASSERT(is_valid());
+ return object_->data.stream_info.max_framesize;
+ }
+
+ uint32_t StreamInfo::get_sample_rate() const
+ {
+ FLAC__ASSERT(is_valid());
+ return object_->data.stream_info.sample_rate;
+ }
+
+ uint32_t StreamInfo::get_channels() const
+ {
+ FLAC__ASSERT(is_valid());
+ return object_->data.stream_info.channels;
+ }
+
+ uint32_t 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(uint32_t 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(uint32_t 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(uint32_t 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(uint32_t 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(uint32_t 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(uint32_t 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(uint32_t 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);
+ std::memcpy(object_->data.stream_info.md5sum, value, 16);
+ }
+
+
+ //
+ // Padding
+ //
+
+ Padding::Padding():
+ Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING), /*copy=*/false)
+ { }
+
+ Padding::Padding(uint32_t length):
+ Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING), /*copy=*/false)
+ {
+ set_length(length);
+ }
+
+ Padding::~Padding()
+ { }
+
+ void Padding::set_length(uint32_t 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);
+ std::memcpy(object_->data.application.id, value, 4);
+ }
+
+ bool Application::set_data(const FLAC__byte *data, uint32_t length)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__metadata_object_application_set_data(object_, const_cast<FLAC__byte*>(data), length, true));
+ }
+
+ bool Application::set_data(FLAC__byte *data, uint32_t length, bool copy)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<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()
+ { }
+
+ uint32_t SeekTable::get_num_points() const
+ {
+ FLAC__ASSERT(is_valid());
+ return object_->data.seek_table.num_points;
+ }
+
+ ::FLAC__StreamMetadata_SeekPoint SeekTable::get_point(uint32_t indx) const
+ {
+ FLAC__ASSERT(is_valid());
+ FLAC__ASSERT(indx < object_->data.seek_table.num_points);
+ return object_->data.seek_table.points[indx];
+ }
+
+ bool SeekTable::resize_points(uint32_t new_num_points)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__metadata_object_seektable_resize_points(object_, new_num_points));
+ }
+
+ void SeekTable::set_point(uint32_t indx, const ::FLAC__StreamMetadata_SeekPoint &point)
+ {
+ FLAC__ASSERT(is_valid());
+ FLAC__ASSERT(indx < object_->data.seek_table.num_points);
+ ::FLAC__metadata_object_seektable_set_point(object_, indx, point);
+ }
+
+ bool SeekTable::insert_point(uint32_t indx, const ::FLAC__StreamMetadata_SeekPoint &point)
+ {
+ FLAC__ASSERT(is_valid());
+ FLAC__ASSERT(indx <= object_->data.seek_table.num_points);
+ return static_cast<bool>(::FLAC__metadata_object_seektable_insert_point(object_, indx, point));
+ }
+
+ bool SeekTable::delete_point(uint32_t indx)
+ {
+ FLAC__ASSERT(is_valid());
+ FLAC__ASSERT(indx < object_->data.seek_table.num_points);
+ return static_cast<bool>(::FLAC__metadata_object_seektable_delete_point(object_, indx));
+ }
+
+ bool SeekTable::is_legal() const
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__metadata_object_seektable_is_legal(object_));
+ }
+
+ bool SeekTable::template_append_placeholders(uint32_t num)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__metadata_object_seektable_template_append_placeholders(object_, num));
+ }
+
+ bool SeekTable::template_append_point(FLAC__uint64 sample_number)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__metadata_object_seektable_template_append_point(object_, sample_number));
+ }
+
+ bool SeekTable::template_append_points(FLAC__uint64 sample_numbers[], uint32_t num)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__metadata_object_seektable_template_append_points(object_, sample_numbers, num));
+ }
+
+ bool SeekTable::template_append_spaced_points(uint32_t num, FLAC__uint64 total_samples)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__metadata_object_seektable_template_append_spaced_points(object_, num, total_samples));
+ }
+
+ bool SeekTable::template_append_spaced_points_by_samples(uint32_t samples, FLAC__uint64 total_samples)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(object_, samples, total_samples));
+ }
+
+ bool SeekTable::template_sort(bool compact)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__metadata_object_seektable_template_sort(object_, compact));
+ }
+
+
+ //
+ // VorbisComment::Entry
+ //
+
+ VorbisComment::Entry::Entry() :
+ is_valid_(true),
+ entry_(),
+ field_name_(0),
+ field_name_length_(0),
+ field_value_(0),
+ field_value_length_(0)
+ {
+ zero();
+ }
+
+ VorbisComment::Entry::Entry(const char *field, uint32_t field_length) :
+ is_valid_(true),
+ entry_(),
+ field_name_(0),
+ field_name_length_(0),
+ field_value_(0),
+ field_value_length_(0)
+ {
+ zero();
+ construct(field, field_length);
+ }
+
+ VorbisComment::Entry::Entry(const char *field) :
+ is_valid_(true),
+ entry_(),
+ field_name_(0),
+ field_name_length_(0),
+ field_value_(0),
+ field_value_length_(0)
+ {
+ zero();
+ construct(field);
+ }
+
+ VorbisComment::Entry::Entry(const char *field_name, const char *field_value, uint32_t field_value_length) :
+ is_valid_(true),
+ entry_(),
+ field_name_(0),
+ field_name_length_(0),
+ field_value_(0),
+ field_value_length_(0)
+ {
+ zero();
+ construct(field_name, field_value, field_value_length);
+ }
+
+ VorbisComment::Entry::Entry(const char *field_name, const char *field_value) :
+ is_valid_(true),
+ entry_(),
+ field_name_(0),
+ field_name_length_(0),
+ field_value_(0),
+ field_value_length_(0)
+ {
+ zero();
+ construct(field_name, field_value);
+ }
+
+ VorbisComment::Entry::Entry(const Entry &entry) :
+ is_valid_(true),
+ entry_(),
+ field_name_(0),
+ field_name_length_(0),
+ field_value_(0),
+ field_value_length_(0)
+ {
+ FLAC__ASSERT(entry.is_valid());
+ zero();
+ construct(reinterpret_cast<const char *>(entry.entry_.entry), entry.entry_.length);
+ }
+
+ VorbisComment::Entry &VorbisComment::Entry::operator=(const Entry &entry)
+ {
+ FLAC__ASSERT(entry.is_valid());
+ clear();
+ construct(reinterpret_cast<const char *>(entry.entry_.entry), entry.entry_.length);
+ return *this;
+ }
+
+ VorbisComment::Entry::~Entry()
+ {
+ clear();
+ }
+
+ bool VorbisComment::Entry::is_valid() const
+ {
+ return is_valid_;
+ }
+
+ uint32_t VorbisComment::Entry::get_field_length() const
+ {
+ FLAC__ASSERT(is_valid());
+ return entry_.length;
+ }
+
+ uint32_t VorbisComment::Entry::get_field_name_length() const
+ {
+ FLAC__ASSERT(is_valid());
+ return field_name_length_;
+ }
+
+ uint32_t 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 reinterpret_cast<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, uint32_t field_length)
+ {
+ FLAC__ASSERT(is_valid());
+ FLAC__ASSERT(0 != field);
+
+ if(!::FLAC__format_vorbiscomment_entry_is_legal(reinterpret_cast<const ::FLAC__byte*>(field), field_length))
+ return is_valid_ = false;
+
+ clear_entry();
+
+ if(0 == (entry_.entry = static_cast<FLAC__byte*>(safe_malloc_add_2op_(field_length, /*+*/1)))) {
+ is_valid_ = false;
+ }
+ else {
+ entry_.length = field_length;
+ std::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, std::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_ = std::strlen(field_name_);
+ compose_field();
+ }
+
+ return is_valid_;
+ }
+
+ bool VorbisComment::Entry::set_field_value(const char *field_value, uint32_t field_value_length)
+ {
+ FLAC__ASSERT(is_valid());
+ FLAC__ASSERT(0 != field_value);
+
+ if(!::FLAC__format_vorbiscomment_entry_value_is_legal(reinterpret_cast<const FLAC__byte*>(field_value), field_value_length))
+ return is_valid_ = false;
+
+ clear_field_value();
+
+ if(0 == (field_value_ = static_cast<char *>(safe_malloc_add_2op_(field_value_length, /*+*/1)))) {
+ is_valid_ = false;
+ }
+ else {
+ field_value_length_ = field_value_length;
+ std::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, std::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) {
+ std::free(entry_.entry);
+ entry_.entry = 0;
+ entry_.length = 0;
+ }
+ }
+
+ void VorbisComment::Entry::clear_field_name()
+ {
+ if(0 != field_name_) {
+ std::free(field_name_);
+ field_name_ = 0;
+ field_name_length_ = 0;
+ }
+ }
+
+ void VorbisComment::Entry::clear_field_value()
+ {
+ if(0 != field_value_) {
+ std::free(field_value_);
+ field_value_ = 0;
+ field_value_length_ = 0;
+ }
+ }
+
+ void VorbisComment::Entry::construct(const char *field, uint32_t field_length)
+ {
+ if(set_field(field, field_length))
+ parse_field();
+ }
+
+ void VorbisComment::Entry::construct(const char *field)
+ {
+ construct(field, std::strlen(field));
+ }
+
+ void VorbisComment::Entry::construct(const char *field_name, const char *field_value, uint32_t 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, std::strlen(field_value));
+ }
+
+ void VorbisComment::Entry::compose_field()
+ {
+ clear_entry();
+
+ if(0 == (entry_.entry = static_cast<FLAC__byte*>(safe_malloc_add_4op_(field_name_length_, /*+*/1, /*+*/field_value_length_, /*+*/1)))) {
+ is_valid_ = false;
+ }
+ else {
+ std::memcpy(entry_.entry, field_name_, field_name_length_);
+ entry_.length += field_name_length_;
+ std::memcpy(entry_.entry + entry_.length, "=", 1);
+ entry_.length += 1;
+ if (field_value_length_ > 0)
+ std::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 = static_cast<const char *>(std::memchr(entry_.entry, '=', entry_.length));
+
+ if(0 == p)
+ p = reinterpret_cast<const char *>(entry_.entry) + entry_.length;
+
+ field_name_length_ = static_cast<uint32_t>(p - reinterpret_cast<const char *>(entry_.entry));
+ if(0 == (field_name_ = static_cast<char *>(safe_malloc_add_2op_(field_name_length_, /*+*/1)))) { // +1 for the trailing \0
+ is_valid_ = false;
+ return;
+ }
+ std::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_ = static_cast<char *>(safe_malloc_(0)))) {
+ is_valid_ = false;
+ return;
+ }
+ }
+ else {
+ field_value_length_ = entry_.length - field_name_length_ - 1;
+ if(0 == (field_value_ = static_cast<char *>(safe_malloc_add_2op_(field_value_length_, /*+*/1)))) { // +1 for the trailing \0
+ is_valid_ = false;
+ return;
+ }
+ std::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()
+ { }
+
+ uint32_t 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(uint32_t indx) const
+ {
+ FLAC__ASSERT(is_valid());
+ FLAC__ASSERT(indx < object_->data.vorbis_comment.num_comments);
+ return Entry(reinterpret_cast<const char *>(object_->data.vorbis_comment.comments[indx].entry), object_->data.vorbis_comment.comments[indx].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 = { static_cast<FLAC__uint32>(std::strlen(reinterpret_cast<const char *>(string))), const_cast<FLAC__byte*>(string) }; // we can cheat on const-ness because we make a copy below:
+ return static_cast<bool>(::FLAC__metadata_object_vorbiscomment_set_vendor_string(object_, vendor_string, /*copy=*/true));
+ }
+
+ bool VorbisComment::resize_comments(uint32_t new_num_comments)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__metadata_object_vorbiscomment_resize_comments(object_, new_num_comments));
+ }
+
+ bool VorbisComment::set_comment(uint32_t indx, const VorbisComment::Entry &entry)
+ {
+ FLAC__ASSERT(is_valid());
+ FLAC__ASSERT(indx < object_->data.vorbis_comment.num_comments);
+ return static_cast<bool>(::FLAC__metadata_object_vorbiscomment_set_comment(object_, indx, entry.get_entry(), /*copy=*/true));
+ }
+
+ bool VorbisComment::insert_comment(uint32_t indx, const VorbisComment::Entry &entry)
+ {
+ FLAC__ASSERT(is_valid());
+ FLAC__ASSERT(indx <= object_->data.vorbis_comment.num_comments);
+ return static_cast<bool>(::FLAC__metadata_object_vorbiscomment_insert_comment(object_, indx, entry.get_entry(), /*copy=*/true));
+ }
+
+ bool VorbisComment::append_comment(const VorbisComment::Entry &entry)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__metadata_object_vorbiscomment_append_comment(object_, entry.get_entry(), /*copy=*/true));
+ }
+
+ bool VorbisComment::replace_comment(const VorbisComment::Entry &entry, bool all)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__metadata_object_vorbiscomment_replace_comment(object_, entry.get_entry(), static_cast<FLAC__bool>(all), /*copy=*/true));
+ }
+
+ bool VorbisComment::delete_comment(uint32_t indx)
+ {
+ FLAC__ASSERT(is_valid());
+ FLAC__ASSERT(indx < object_->data.vorbis_comment.num_comments);
+ return static_cast<bool>(::FLAC__metadata_object_vorbiscomment_delete_comment(object_, indx));
+ }
+
+ int VorbisComment::find_entry_from(uint32_t offset, const char *field_name)
+ {
+ FLAC__ASSERT(is_valid());
+ return ::FLAC__metadata_object_vorbiscomment_find_entry_from(object_, offset, field_name);
+ }
+
+ int VorbisComment::remove_entry_matching(const char *field_name)
+ {
+ FLAC__ASSERT(is_valid());
+ return ::FLAC__metadata_object_vorbiscomment_remove_entry_matching(object_, field_name);
+ }
+
+ int VorbisComment::remove_entries_matching(const char *field_name)
+ {
+ FLAC__ASSERT(is_valid());
+ return ::FLAC__metadata_object_vorbiscomment_remove_entries_matching(object_, field_name);
+ }
+
+
+ //
+ // 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(uint32_t 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);
+ std::memcpy(object_->isrc, value, 12);
+ object_->isrc[12] = '\0';
+ }
+
+ void CueSheet::Track::set_type(uint32_t value)
+ {
+ FLAC__ASSERT(is_valid());
+ FLAC__ASSERT(value <= 1);
+ object_->type = value;
+ }
+
+ void CueSheet::Track::set_index(uint32_t i, const ::FLAC__StreamMetadata_CueSheet_Index &indx)
+ {
+ FLAC__ASSERT(is_valid());
+ FLAC__ASSERT(i < object_->num_indices);
+ object_->indices[i] = indx;
+ }
+
+
+ //
+ // 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;
+ }
+
+ uint32_t CueSheet::get_num_tracks() const
+ {
+ FLAC__ASSERT(is_valid());
+ return object_->data.cue_sheet.num_tracks;
+ }
+
+ CueSheet::Track CueSheet::get_track(uint32_t 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);
+ std::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(uint32_t track_num, uint32_t index_num, const ::FLAC__StreamMetadata_CueSheet_Index &indx)
+ {
+ 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] = indx;
+ }
+
+ bool CueSheet::resize_indices(uint32_t track_num, uint32_t new_num_indices)
+ {
+ FLAC__ASSERT(is_valid());
+ FLAC__ASSERT(track_num < object_->data.cue_sheet.num_tracks);
+ return static_cast<bool>(::FLAC__metadata_object_cuesheet_track_resize_indices(object_, track_num, new_num_indices));
+ }
+
+ bool CueSheet::insert_index(uint32_t track_num, uint32_t index_num, const ::FLAC__StreamMetadata_CueSheet_Index &indx)
+ {
+ 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 static_cast<bool>(::FLAC__metadata_object_cuesheet_track_insert_index(object_, track_num, index_num, indx));
+ }
+
+ bool CueSheet::insert_blank_index(uint32_t track_num, uint32_t 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 static_cast<bool>(::FLAC__metadata_object_cuesheet_track_insert_blank_index(object_, track_num, index_num));
+ }
+
+ bool CueSheet::delete_index(uint32_t track_num, uint32_t 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 static_cast<bool>(::FLAC__metadata_object_cuesheet_track_delete_index(object_, track_num, index_num));
+ }
+
+ bool CueSheet::resize_tracks(uint32_t new_num_tracks)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__metadata_object_cuesheet_resize_tracks(object_, new_num_tracks));
+ }
+
+ bool CueSheet::set_track(uint32_t 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 static_cast<bool>(::FLAC__metadata_object_cuesheet_set_track(object_, i, const_cast< ::FLAC__StreamMetadata_CueSheet_Track*>(track.get_track()), /*copy=*/true));
+ }
+
+ bool CueSheet::insert_track(uint32_t 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 static_cast<bool>(::FLAC__metadata_object_cuesheet_insert_track(object_, i, const_cast< ::FLAC__StreamMetadata_CueSheet_Track*>(track.get_track()), /*copy=*/true));
+ }
+
+ bool CueSheet::insert_blank_track(uint32_t i)
+ {
+ FLAC__ASSERT(is_valid());
+ FLAC__ASSERT(i <= object_->data.cue_sheet.num_tracks);
+ return static_cast<bool>(::FLAC__metadata_object_cuesheet_insert_blank_track(object_, i));
+ }
+
+ bool CueSheet::delete_track(uint32_t i)
+ {
+ FLAC__ASSERT(is_valid());
+ FLAC__ASSERT(i < object_->data.cue_sheet.num_tracks);
+ return static_cast<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 static_cast<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 static_cast<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 static_cast<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 static_cast<bool>(::FLAC__metadata_object_picture_set_data(object_, const_cast<FLAC__byte*>(data), data_length, /*copy=*/true));
+ }
+
+ bool Picture::is_legal(const char **violation)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__metadata_object_picture_is_legal(object_, violation));
+ }
+
+
+ //
+ // 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, uint32_t length)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__metadata_object_application_set_data(object_, const_cast<FLAC__byte*>(data), length, true));
+ }
+
+ bool Unknown::set_data(FLAC__byte *data, uint32_t length, bool copy)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<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, uint32_t max_width, uint32_t max_height, uint32_t max_depth, uint32_t 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, uint32_t max_width, uint32_t max_height, uint32_t max_depth, uint32_t 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 static_cast<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 static_cast<bool>(::FLAC__metadata_simple_iterator_is_writable(iterator_));
+ }
+
+ bool SimpleIterator::next()
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__metadata_simple_iterator_next(iterator_));
+ }
+
+ bool SimpleIterator::prev()
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__metadata_simple_iterator_prev(iterator_));
+ }
+
+ //@@@@ add to tests
+ bool SimpleIterator::is_last() const
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<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
+ uint32_t 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 static_cast<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 static_cast<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 static_cast<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 static_cast<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?
+ static_cast<bool>(::FLAC__metadata_chain_read_ogg(chain_, filename)) :
+ static_cast<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?
+ static_cast<bool>(::FLAC__metadata_chain_read_ogg_with_callbacks(chain_, handle, callbacks)) :
+ static_cast<bool>(::FLAC__metadata_chain_read_with_callbacks(chain_, handle, callbacks))
+ ;
+ }
+
+ bool Chain::check_if_tempfile_needed(bool use_padding)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<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 static_cast<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 static_cast<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 static_cast<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 static_cast<bool>(::FLAC__metadata_iterator_next(iterator_));
+ }
+
+ bool Iterator::prev()
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<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 = static_cast<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 static_cast<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 = static_cast<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 = static_cast<bool>(::FLAC__metadata_iterator_insert_block_after(iterator_, block->object_));
+ if(ret) {
+ block->set_reference(true);
+ delete block;
+ }
+ return ret;
+ }
+
+ } // namespace Metadata
+} // namespace FLAC
diff --git a/src/libFLAC++/stream_decoder.cpp b/src/libFLAC++/stream_decoder.cpp
new file mode 100644
index 0000000..6e351d9
--- /dev/null
+++ b/src/libFLAC++/stream_decoder.cpp
@@ -0,0 +1,394 @@
+/* libFLAC++ - Free Lossless Audio Codec library
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#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 static_cast<bool>(::FLAC__stream_decoder_set_ogg_serial_number(decoder_, value));
+ }
+
+ bool Stream::set_md5_checking(bool value)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__stream_decoder_set_md5_checking(decoder_, value));
+ }
+
+ bool Stream::set_metadata_respond(::FLAC__MetadataType type)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<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 static_cast<bool>(::FLAC__stream_decoder_set_metadata_respond_application(decoder_, id));
+ }
+
+ bool Stream::set_metadata_respond_all()
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__stream_decoder_set_metadata_respond_all(decoder_));
+ }
+
+ bool Stream::set_metadata_ignore(::FLAC__MetadataType type)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<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 static_cast<bool>(::FLAC__stream_decoder_set_metadata_ignore_application(decoder_, id));
+ }
+
+ bool Stream::set_metadata_ignore_all()
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<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 static_cast<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_);
+ }
+
+ uint32_t 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_);
+ }
+
+ uint32_t Stream::get_bits_per_sample() const
+ {
+ FLAC__ASSERT(is_valid());
+ return ::FLAC__stream_decoder_get_bits_per_sample(decoder_);
+ }
+
+ uint32_t Stream::get_sample_rate() const
+ {
+ FLAC__ASSERT(is_valid());
+ return ::FLAC__stream_decoder_get_sample_rate(decoder_);
+ }
+
+ uint32_t 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 static_cast<bool>(::FLAC__stream_decoder_finish(decoder_));
+ }
+
+ bool Stream::flush()
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__stream_decoder_flush(decoder_));
+ }
+
+ bool Stream::reset()
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__stream_decoder_reset(decoder_));
+ }
+
+ bool Stream::process_single()
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__stream_decoder_process_single(decoder_));
+ }
+
+ bool Stream::process_until_end_of_metadata()
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__stream_decoder_process_until_end_of_metadata(decoder_));
+ }
+
+ bool Stream::process_until_end_of_stream()
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__stream_decoder_process_until_end_of_stream(decoder_));
+ }
+
+ bool Stream::skip_single_frame()
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__stream_decoder_skip_single_frame(decoder_));
+ }
+
+ bool Stream::seek_absolute(FLAC__uint64 sample)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<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
+ }
+
+ } // namespace Decoder
+} // namespace FLAC
diff --git a/src/libFLAC++/stream_encoder.cpp b/src/libFLAC++/stream_encoder.cpp
new file mode 100644
index 0000000..8377129
--- /dev/null
+++ b/src/libFLAC++/stream_encoder.cpp
@@ -0,0 +1,519 @@
+/* libFLAC++ - Free Lossless Audio Codec library
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#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 static_cast<bool>(::FLAC__stream_encoder_set_ogg_serial_number(encoder_, value));
+ }
+
+ bool Stream::set_verify(bool value)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__stream_encoder_set_verify(encoder_, value));
+ }
+
+ bool Stream::set_streamable_subset(bool value)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__stream_encoder_set_streamable_subset(encoder_, value));
+ }
+
+ bool Stream::set_channels(uint32_t value)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__stream_encoder_set_channels(encoder_, value));
+ }
+
+ bool Stream::set_bits_per_sample(uint32_t value)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__stream_encoder_set_bits_per_sample(encoder_, value));
+ }
+
+ bool Stream::set_sample_rate(uint32_t value)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__stream_encoder_set_sample_rate(encoder_, value));
+ }
+
+ bool Stream::set_compression_level(uint32_t value)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__stream_encoder_set_compression_level(encoder_, value));
+ }
+
+ bool Stream::set_blocksize(uint32_t value)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__stream_encoder_set_blocksize(encoder_, value));
+ }
+
+ bool Stream::set_do_mid_side_stereo(bool value)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<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 static_cast<bool>(::FLAC__stream_encoder_set_loose_mid_side_stereo(encoder_, value));
+ }
+
+ bool Stream::set_apodization(const char *specification)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__stream_encoder_set_apodization(encoder_, specification));
+ }
+
+ bool Stream::set_max_lpc_order(uint32_t value)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__stream_encoder_set_max_lpc_order(encoder_, value));
+ }
+
+ bool Stream::set_qlp_coeff_precision(uint32_t value)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<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 static_cast<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 static_cast<bool>(::FLAC__stream_encoder_set_do_escape_coding(encoder_, value));
+ }
+
+ bool Stream::set_do_exhaustive_model_search(bool value)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__stream_encoder_set_do_exhaustive_model_search(encoder_, value));
+ }
+
+ bool Stream::set_min_residual_partition_order(uint32_t value)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__stream_encoder_set_min_residual_partition_order(encoder_, value));
+ }
+
+ bool Stream::set_max_residual_partition_order(uint32_t value)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__stream_encoder_set_max_residual_partition_order(encoder_, value));
+ }
+
+ bool Stream::set_rice_parameter_search_dist(uint32_t value)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<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 static_cast<bool>(::FLAC__stream_encoder_set_total_samples_estimate(encoder_, value));
+ }
+
+ bool Stream::set_metadata(::FLAC__StreamMetadata **metadata, uint32_t num_blocks)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__stream_encoder_set_metadata(encoder_, metadata, num_blocks));
+ }
+
+ bool Stream::set_metadata(FLAC::Metadata::Prototype **metadata, uint32_t num_blocks)
+ {
+ FLAC__ASSERT(is_valid());
+ // because C++ doesn't have VLA's (variable length arrays)
+ // this ugly workaround is needed
+ ::FLAC__StreamMetadata **m = new ::FLAC__StreamMetadata*[num_blocks];
+ for(uint32_t 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*>(static_cast<const ::FLAC__StreamMetadata*>(*metadata[i]));
+ }
+ // complete the hack
+ const bool ok = static_cast<bool>(::FLAC__stream_encoder_set_metadata(encoder_, m, num_blocks));
+ delete [] m;
+ return ok;
+ }
+
+ bool Stream::set_limit_min_bitrate(bool value)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__stream_encoder_set_limit_min_bitrate(encoder_, value));
+ }
+
+ 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, uint32_t *frame_number, uint32_t *channel, uint32_t *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 static_cast<bool>(::FLAC__stream_encoder_get_verify(encoder_));
+ }
+
+ bool Stream::get_streamable_subset() const
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__stream_encoder_get_streamable_subset(encoder_));
+ }
+
+ bool Stream::get_do_mid_side_stereo() const
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__stream_encoder_get_do_mid_side_stereo(encoder_));
+ }
+
+ bool Stream::get_loose_mid_side_stereo() const
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__stream_encoder_get_loose_mid_side_stereo(encoder_));
+ }
+
+ uint32_t Stream::get_channels() const
+ {
+ FLAC__ASSERT(is_valid());
+ return ::FLAC__stream_encoder_get_channels(encoder_);
+ }
+
+ uint32_t Stream::get_bits_per_sample() const
+ {
+ FLAC__ASSERT(is_valid());
+ return ::FLAC__stream_encoder_get_bits_per_sample(encoder_);
+ }
+
+ uint32_t Stream::get_sample_rate() const
+ {
+ FLAC__ASSERT(is_valid());
+ return ::FLAC__stream_encoder_get_sample_rate(encoder_);
+ }
+
+ uint32_t Stream::get_blocksize() const
+ {
+ FLAC__ASSERT(is_valid());
+ return ::FLAC__stream_encoder_get_blocksize(encoder_);
+ }
+
+ uint32_t Stream::get_max_lpc_order() const
+ {
+ FLAC__ASSERT(is_valid());
+ return ::FLAC__stream_encoder_get_max_lpc_order(encoder_);
+ }
+
+ uint32_t 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 static_cast<bool>(::FLAC__stream_encoder_get_do_qlp_coeff_prec_search(encoder_));
+ }
+
+ bool Stream::get_do_escape_coding() const
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__stream_encoder_get_do_escape_coding(encoder_));
+ }
+
+ bool Stream::get_do_exhaustive_model_search() const
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__stream_encoder_get_do_exhaustive_model_search(encoder_));
+ }
+
+ uint32_t Stream::get_min_residual_partition_order() const
+ {
+ FLAC__ASSERT(is_valid());
+ return ::FLAC__stream_encoder_get_min_residual_partition_order(encoder_);
+ }
+
+ uint32_t Stream::get_max_residual_partition_order() const
+ {
+ FLAC__ASSERT(is_valid());
+ return ::FLAC__stream_encoder_get_max_residual_partition_order(encoder_);
+ }
+
+ uint32_t 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_);
+ }
+
+ bool Stream::get_limit_min_bitrate() const
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__stream_encoder_get_limit_min_bitrate(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 static_cast<bool>(::FLAC__stream_encoder_finish(encoder_));
+ }
+
+ bool Stream::process(const FLAC__int32 * const buffer[], uint32_t samples)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<bool>(::FLAC__stream_encoder_process(encoder_, buffer, samples));
+ }
+
+ bool Stream::process_interleaved(const FLAC__int32 buffer[], uint32_t samples)
+ {
+ FLAC__ASSERT(is_valid());
+ return static_cast<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, uint32_t samples, uint32_t 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, uint32_t samples, uint32_t 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, uint32_t frames_written, uint32_t 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, uint32_t frames_written, uint32_t 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);
+ }
+
+ } // namespace Encoder
+} // namespace FLAC
diff --git a/src/libFLAC++/version.rc b/src/libFLAC++/version.rc
new file mode 100644
index 0000000..14efba0
--- /dev/null
+++ b/src/libFLAC++/version.rc
@@ -0,0 +1,40 @@
+#include <winver.h>
+#include "config.h"
+#include "FLAC++/export.h"
+
+#if (defined GIT_COMMIT_HASH && defined GIT_COMMIT_DATE)
+# ifdef GIT_COMMIT_TAG
+# define VERSIONSTRING GIT_COMMIT_TAG
+# else
+# define VERSIONSTRING "git-" GIT_COMMIT_HASH
+# endif
+#else
+# define VERSIONSTRING PACKAGE_VERSION
+#endif
+
+#define xstr(s) str(s)
+#define str(s) #s
+
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION FLACPP_API_VERSION_CURRENT,FLACPP_API_VERSION_REVISION,0,0
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+FILEFLAGS 0
+FILEOS VOS__WINDOWS32
+FILETYPE VFT_DLL
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "FileDescription", "libFLAC++ for Windows"
+ VALUE "ProductName", "Free Lossless Audio Codec"
+ VALUE "ProductVersion", VERSIONSTRING
+ VALUE "CompanyName", "Xiph.Org"
+ VALUE "LegalCopyright", "2000-2009 Josh Coalson, 2011-2023 Xiph.Org Foundation"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/src/libFLAC/CMakeLists.txt b/src/libFLAC/CMakeLists.txt
new file mode 100644
index 0000000..cf7368f
--- /dev/null
+++ b/src/libFLAC/CMakeLists.txt
@@ -0,0 +1,126 @@
+option(WITH_ASM "Use any assembly optimization routines" ON)
+
+check_include_file("cpuid.h" HAVE_CPUID_H)
+check_include_file("sys/param.h" HAVE_SYS_PARAM_H)
+
+set(CMAKE_REQUIRED_LIBRARIES m)
+check_function_exists(lround HAVE_LROUND)
+
+include(CheckCSourceCompiles)
+include(CheckCPUArch)
+include(CheckA64NEON)
+
+check_cpu_arch_x64(FLAC__CPU_X86_64)
+if(NOT FLAC__CPU_X86_64)
+ check_cpu_arch_x86(FLAC__CPU_IA32)
+endif()
+
+if(FLAC__CPU_X86_64 OR FLAC__CPU_IA32)
+ set(FLAC__ALIGN_MALLOC_DATA 1)
+ option(WITH_AVX "Enable AVX, AVX2 optimizations (with runtime detection, resulting binary does not require AVX2, so only necessary when a compiler doesn't know about AVX)" ON)
+ if(WITH_AVX AND MSVC)
+ set_source_files_properties(fixed_intrin_avx2.c lpc_intrin_avx2.c stream_encoder_intrin_avx2.c lpc_intrin_fma.c PROPERTIES COMPILE_FLAGS /arch:AVX2)
+ endif()
+else()
+ check_cpu_arch_arm64(FLAC__CPU_ARM64)
+ if(FLAC__CPU_ARM64)
+ check_a64neon(FLAC__HAS_A64NEONINTRIN)
+ endif()
+endif()
+
+if(NOT WITH_ASM)
+ add_definitions(-DFLAC__NO_ASM)
+endif()
+
+include_directories("include")
+
+add_library(FLAC
+ bitmath.c
+ bitreader.c
+ bitwriter.c
+ cpu.c
+ crc.c
+ fixed.c
+ fixed_intrin_sse2.c
+ fixed_intrin_ssse3.c
+ fixed_intrin_sse42.c
+ fixed_intrin_avx2.c
+ float.c
+ format.c
+ lpc.c
+ lpc_intrin_neon.c
+ lpc_intrin_sse2.c
+ lpc_intrin_sse41.c
+ lpc_intrin_avx2.c
+ lpc_intrin_fma.c
+ md5.c
+ memory.c
+ metadata_iterators.c
+ metadata_object.c
+ stream_decoder.c
+ stream_encoder.c
+ stream_encoder_intrin_sse2.c
+ stream_encoder_intrin_ssse3.c
+ stream_encoder_intrin_avx2.c
+ stream_encoder_framing.c
+ version.rc
+ window.c
+ $<$<BOOL:${WIN32}>:../../include/share/win_utf8_io.h>
+ $<$<BOOL:${WIN32}>:../share/win_utf8_io/win_utf8_io.c>
+ $<$<BOOL:${OGG_FOUND}>:ogg_decoder_aspect.c>
+ $<$<BOOL:${OGG_FOUND}>:ogg_encoder_aspect.c>
+ $<$<BOOL:${OGG_FOUND}>:ogg_helper.c>
+ $<$<BOOL:${OGG_FOUND}>:ogg_mapping.c>)
+set_property(TARGET FLAC PROPERTY PROJECT_LABEL "libFLAC")
+if(TARGET FLAC-asm)
+ target_sources(FLAC PRIVATE $<TARGET_OBJECTS:FLAC-asm>)
+endif()
+
+target_compile_definitions(FLAC
+ PRIVATE $<$<BOOL:${BUILD_SHARED_LIBS}>:FLAC_API_EXPORTS>
+ PUBLIC $<$<NOT:$<BOOL:${BUILD_SHARED_LIBS}>>:FLAC__NO_DLL>)
+if(NOT WIN32)
+ target_compile_definitions(FLAC PRIVATE $<$<BOOL:${BUILD_SHARED_LIBS}>:FLAC__USE_VISIBILITY_ATTR>)
+endif()
+target_include_directories(FLAC INTERFACE
+ "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>"
+ "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
+target_link_libraries(FLAC PUBLIC $<$<BOOL:${HAVE_LROUND}>:m>)
+if(TARGET Ogg::ogg)
+ target_link_libraries(FLAC PUBLIC Ogg::ogg)
+endif()
+if(BUILD_SHARED_LIBS)
+ set_target_properties(FLAC PROPERTIES
+ VERSION 12.1.0
+ SOVERSION 12)
+ if(NOT WIN32)
+ set_target_properties(FLAC PROPERTIES C_VISIBILITY_PRESET hidden)
+ endif()
+endif()
+
+check_c_compiler_flag("-fassociative-math -fno-signed-zeros -fno-trapping-math -freciprocal-math" HAVE_ASSOC_MATH)
+
+if(MSVC)
+ target_compile_options(FLAC BEFORE PRIVATE "/fp:fast")
+else()
+ if(HAVE_ASSOC_MATH)
+ target_compile_options(FLAC BEFORE PRIVATE -fassociative-math -fno-signed-zeros -fno-trapping-math -freciprocal-math)
+ endif()
+endif()
+
+add_library(FLAC::FLAC ALIAS FLAC)
+
+install(TARGETS FLAC EXPORT targets
+ ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}/"
+ LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/"
+ RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}/")
+
+if(INSTALL_PKGCONFIG_MODULES)
+ set(prefix "${CMAKE_INSTALL_PREFIX}")
+ set(exec_prefix "${CMAKE_INSTALL_PREFIX}")
+ set(libdir "${CMAKE_INSTALL_FULL_LIBDIR}")
+ set(includedir "${CMAKE_INSTALL_FULL_INCLUDEDIR}")
+ configure_file(flac.pc.in flac.pc @ONLY)
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/flac.pc"
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
+endif()
diff --git a/src/libFLAC/Makefile.am b/src/libFLAC/Makefile.am
new file mode 100644
index 0000000..618939d
--- /dev/null
+++ b/src/libFLAC/Makefile.am
@@ -0,0 +1,123 @@
+# libFLAC - Free Lossless Audio Codec library
+# Copyright (C) 2001-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# 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.
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+lib_LTLIBRARIES = libFLAC.la
+noinst_LTLIBRARIES = libFLAC-static.la
+if DEBUG
+DEBUGCFLAGS = -DFLAC__OVERFLOW_DETECT
+else
+if ASSOC_MATH_AVAILABLE
+ASSOCMATHCFLAGS = -fassociative-math -fno-signed-zeros -fno-trapping-math -freciprocal-math
+endif
+endif
+
+AM_CFLAGS = $(DEBUGCFLAGS) ${ASSOCMATHCFLAGS} @OGG_CFLAGS@
+
+libFLAC_la_LIBADD = @OGG_LIBS@ -lm
+
+SUBDIRS = include .
+
+m4datadir = $(datadir)/aclocal
+m4data_DATA = libFLAC.m4
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = flac.pc
+
+EXTRA_DIST = \
+ CMakeLists.txt \
+ flac.pc.in \
+ libFLAC.m4 \
+ version.rc \
+ deduplication/bitreader_read_rice_signed_block.c \
+ deduplication/lpc_compute_autocorrelation_intrin.c \
+ deduplication/lpc_compute_autocorrelation_intrin_sse2.c \
+ deduplication/lpc_compute_autocorrelation_intrin_neon.c
+
+if OS_IS_WINDOWS
+windows_unicode_compat = ../share/win_utf8_io/win_utf8_io.c
+if HAVE_WINDRES
+libFLAC_la_DEPENDENCIES = version.o
+windows_resource_link = -Wl,version.o
+endif
+endif
+
+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/libtool.html#Libtool-versioning' for numbering convention
+libFLAC_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined -version-info 13:0:1 $(windows_resource_link)
+
+libFLAC_sources = \
+ bitmath.c \
+ bitreader.c \
+ bitwriter.c \
+ cpu.c \
+ crc.c \
+ fixed.c \
+ fixed_intrin_sse2.c \
+ fixed_intrin_ssse3.c \
+ fixed_intrin_sse42.c \
+ fixed_intrin_avx2.c \
+ float.c \
+ format.c \
+ lpc.c \
+ lpc_intrin_sse2.c \
+ lpc_intrin_sse41.c \
+ lpc_intrin_avx2.c \
+ lpc_intrin_fma.c \
+ lpc_intrin_neon.c \
+ md5.c \
+ memory.c \
+ metadata_iterators.c \
+ metadata_object.c \
+ stream_decoder.c \
+ stream_encoder.c \
+ stream_encoder_intrin_sse2.c \
+ stream_encoder_intrin_ssse3.c \
+ stream_encoder_intrin_avx2.c \
+ stream_encoder_framing.c \
+ window.c \
+ $(windows_unicode_compat) \
+ $(extra_ogg_sources)
+
+libFLAC_la_SOURCES = $(libFLAC_sources)
+
+# needed for test_libFLAC
+libFLAC_static_la_SOURCES = $(libFLAC_sources)
+
+.rc.o:
+ $(RC) $(AM_CPPFLAGS) $< $@
diff --git a/src/libFLAC/Makefile.in b/src/libFLAC/Makefile.in
new file mode 100644
index 0000000..47af888
--- /dev/null
+++ b/src/libFLAC/Makefile.in
@@ -0,0 +1,1157 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in 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.
+
+@SET_MAKE@
+
+# libFLAC - Free Lossless Audio Codec library
+# Copyright (C) 2001-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# 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.
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@HAVE_WINDRES_FALSE@libFLAC_la_DEPENDENCIES =
+@OS_IS_WINDOWS_FALSE@libFLAC_la_DEPENDENCIES =
+subdir = src/libFLAC
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/add_cflags.m4 \
+ $(top_srcdir)/m4/add_cxxflags.m4 \
+ $(top_srcdir)/m4/ax_add_fortify_source.m4 \
+ $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_enable_debug.m4 \
+ $(top_srcdir)/m4/bswap.m4 $(top_srcdir)/m4/clang.m4 \
+ $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gcc_version.m4 \
+ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/ogg.m4 \
+ $(top_srcdir)/m4/really_gcc.m4 \
+ $(top_srcdir)/m4/stack_protect.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = flac.pc
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(m4datadir)" \
+ "$(DESTDIR)$(pkgconfigdir)"
+LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES)
+libFLAC_static_la_LIBADD =
+am__libFLAC_static_la_SOURCES_DIST = bitmath.c bitreader.c bitwriter.c \
+ cpu.c crc.c fixed.c fixed_intrin_sse2.c fixed_intrin_ssse3.c \
+ fixed_intrin_sse42.c fixed_intrin_avx2.c float.c format.c \
+ lpc.c lpc_intrin_sse2.c lpc_intrin_sse41.c lpc_intrin_avx2.c \
+ lpc_intrin_fma.c lpc_intrin_neon.c md5.c memory.c \
+ metadata_iterators.c metadata_object.c stream_decoder.c \
+ stream_encoder.c stream_encoder_intrin_sse2.c \
+ stream_encoder_intrin_ssse3.c stream_encoder_intrin_avx2.c \
+ stream_encoder_framing.c window.c \
+ ../share/win_utf8_io/win_utf8_io.c ogg_decoder_aspect.c \
+ ogg_encoder_aspect.c ogg_helper.c ogg_mapping.c
+am__dirstamp = $(am__leading_dot)dirstamp
+@OS_IS_WINDOWS_TRUE@am__objects_1 = \
+@OS_IS_WINDOWS_TRUE@ ../share/win_utf8_io/win_utf8_io.lo
+@FLaC__HAS_OGG_TRUE@am__objects_2 = ogg_decoder_aspect.lo \
+@FLaC__HAS_OGG_TRUE@ ogg_encoder_aspect.lo ogg_helper.lo \
+@FLaC__HAS_OGG_TRUE@ ogg_mapping.lo
+am__objects_3 = bitmath.lo bitreader.lo bitwriter.lo cpu.lo crc.lo \
+ fixed.lo fixed_intrin_sse2.lo fixed_intrin_ssse3.lo \
+ fixed_intrin_sse42.lo fixed_intrin_avx2.lo float.lo format.lo \
+ lpc.lo lpc_intrin_sse2.lo lpc_intrin_sse41.lo \
+ lpc_intrin_avx2.lo lpc_intrin_fma.lo lpc_intrin_neon.lo md5.lo \
+ memory.lo metadata_iterators.lo metadata_object.lo \
+ stream_decoder.lo stream_encoder.lo \
+ stream_encoder_intrin_sse2.lo stream_encoder_intrin_ssse3.lo \
+ stream_encoder_intrin_avx2.lo stream_encoder_framing.lo \
+ window.lo $(am__objects_1) $(am__objects_2)
+am_libFLAC_static_la_OBJECTS = $(am__objects_3)
+libFLAC_static_la_OBJECTS = $(am_libFLAC_static_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+am__libFLAC_la_SOURCES_DIST = bitmath.c bitreader.c bitwriter.c cpu.c \
+ crc.c fixed.c fixed_intrin_sse2.c fixed_intrin_ssse3.c \
+ fixed_intrin_sse42.c fixed_intrin_avx2.c float.c format.c \
+ lpc.c lpc_intrin_sse2.c lpc_intrin_sse41.c lpc_intrin_avx2.c \
+ lpc_intrin_fma.c lpc_intrin_neon.c md5.c memory.c \
+ metadata_iterators.c metadata_object.c stream_decoder.c \
+ stream_encoder.c stream_encoder_intrin_sse2.c \
+ stream_encoder_intrin_ssse3.c stream_encoder_intrin_avx2.c \
+ stream_encoder_framing.c window.c \
+ ../share/win_utf8_io/win_utf8_io.c ogg_decoder_aspect.c \
+ ogg_encoder_aspect.c ogg_helper.c ogg_mapping.c
+am_libFLAC_la_OBJECTS = $(am__objects_3)
+libFLAC_la_OBJECTS = $(am_libFLAC_la_OBJECTS)
+libFLAC_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libFLAC_la_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ../share/win_utf8_io/$(DEPDIR)/win_utf8_io.Plo \
+ ./$(DEPDIR)/bitmath.Plo ./$(DEPDIR)/bitreader.Plo \
+ ./$(DEPDIR)/bitwriter.Plo ./$(DEPDIR)/cpu.Plo \
+ ./$(DEPDIR)/crc.Plo ./$(DEPDIR)/fixed.Plo \
+ ./$(DEPDIR)/fixed_intrin_avx2.Plo \
+ ./$(DEPDIR)/fixed_intrin_sse2.Plo \
+ ./$(DEPDIR)/fixed_intrin_sse42.Plo \
+ ./$(DEPDIR)/fixed_intrin_ssse3.Plo ./$(DEPDIR)/float.Plo \
+ ./$(DEPDIR)/format.Plo ./$(DEPDIR)/lpc.Plo \
+ ./$(DEPDIR)/lpc_intrin_avx2.Plo ./$(DEPDIR)/lpc_intrin_fma.Plo \
+ ./$(DEPDIR)/lpc_intrin_neon.Plo \
+ ./$(DEPDIR)/lpc_intrin_sse2.Plo \
+ ./$(DEPDIR)/lpc_intrin_sse41.Plo ./$(DEPDIR)/md5.Plo \
+ ./$(DEPDIR)/memory.Plo ./$(DEPDIR)/metadata_iterators.Plo \
+ ./$(DEPDIR)/metadata_object.Plo \
+ ./$(DEPDIR)/ogg_decoder_aspect.Plo \
+ ./$(DEPDIR)/ogg_encoder_aspect.Plo ./$(DEPDIR)/ogg_helper.Plo \
+ ./$(DEPDIR)/ogg_mapping.Plo ./$(DEPDIR)/stream_decoder.Plo \
+ ./$(DEPDIR)/stream_encoder.Plo \
+ ./$(DEPDIR)/stream_encoder_framing.Plo \
+ ./$(DEPDIR)/stream_encoder_intrin_avx2.Plo \
+ ./$(DEPDIR)/stream_encoder_intrin_sse2.Plo \
+ ./$(DEPDIR)/stream_encoder_intrin_ssse3.Plo \
+ ./$(DEPDIR)/window.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libFLAC_static_la_SOURCES) $(libFLAC_la_SOURCES)
+DIST_SOURCES = $(am__libFLAC_static_la_SOURCES_DIST) \
+ $(am__libFLAC_la_SOURCES_DIST)
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+DATA = $(m4data_DATA) $(pkgconfig_DATA)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/flac.pc.in \
+ $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_64_BIT_WORDS = @ENABLE_64_BIT_WORDS@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLAC__HAS_OGG = @FLAC__HAS_OGG@
+FLAC__TEST_LEVEL = @FLAC__TEST_LEVEL@
+FLAC__TEST_WITH_VALGRIND = @FLAC__TEST_WITH_VALGRIND@
+GCC_MAJOR_VERSION = @GCC_MAJOR_VERSION@
+GCC_MINOR_VERSION = @GCC_MINOR_VERSION@
+GCC_VERSION = @GCC_VERSION@
+GIT_COMMIT_VERSION_HASH = @GIT_COMMIT_VERSION_HASH@
+GIT_FOUND = @GIT_FOUND@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_FUZZING_ENGINE = @LIB_FUZZING_ENGINE@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OBJ_FORMAT = @OBJ_FORMAT@
+OGG_CFLAGS = @OGG_CFLAGS@
+OGG_LIBS = @OGG_LIBS@
+OGG_PACKAGE = @OGG_PACKAGE@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+lib_LTLIBRARIES = libFLAC.la
+noinst_LTLIBRARIES = libFLAC-static.la
+@DEBUG_TRUE@DEBUGCFLAGS = -DFLAC__OVERFLOW_DETECT
+@ASSOC_MATH_AVAILABLE_TRUE@@DEBUG_FALSE@ASSOCMATHCFLAGS = -fassociative-math -fno-signed-zeros -fno-trapping-math -freciprocal-math
+AM_CFLAGS = $(DEBUGCFLAGS) ${ASSOCMATHCFLAGS} @OGG_CFLAGS@
+libFLAC_la_LIBADD = @OGG_LIBS@ -lm
+SUBDIRS = include .
+m4datadir = $(datadir)/aclocal
+m4data_DATA = libFLAC.m4
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = flac.pc
+EXTRA_DIST = \
+ CMakeLists.txt \
+ flac.pc.in \
+ libFLAC.m4 \
+ version.rc \
+ deduplication/bitreader_read_rice_signed_block.c \
+ deduplication/lpc_compute_autocorrelation_intrin.c \
+ deduplication/lpc_compute_autocorrelation_intrin_sse2.c \
+ deduplication/lpc_compute_autocorrelation_intrin_neon.c
+
+@OS_IS_WINDOWS_TRUE@windows_unicode_compat = ../share/win_utf8_io/win_utf8_io.c
+@HAVE_WINDRES_TRUE@@OS_IS_WINDOWS_TRUE@libFLAC_la_DEPENDENCIES = version.o
+@HAVE_WINDRES_TRUE@@OS_IS_WINDOWS_TRUE@windows_resource_link = -Wl,version.o
+@FLaC__HAS_OGG_TRUE@extra_ogg_sources = \
+@FLaC__HAS_OGG_TRUE@ ogg_decoder_aspect.c \
+@FLaC__HAS_OGG_TRUE@ ogg_encoder_aspect.c \
+@FLaC__HAS_OGG_TRUE@ ogg_helper.c \
+@FLaC__HAS_OGG_TRUE@ ogg_mapping.c
+
+
+# see 'http://www.gnu.org/software/libtool/manual/libtool.html#Libtool-versioning' for numbering convention
+libFLAC_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined -version-info 13:0:1 $(windows_resource_link)
+libFLAC_sources = \
+ bitmath.c \
+ bitreader.c \
+ bitwriter.c \
+ cpu.c \
+ crc.c \
+ fixed.c \
+ fixed_intrin_sse2.c \
+ fixed_intrin_ssse3.c \
+ fixed_intrin_sse42.c \
+ fixed_intrin_avx2.c \
+ float.c \
+ format.c \
+ lpc.c \
+ lpc_intrin_sse2.c \
+ lpc_intrin_sse41.c \
+ lpc_intrin_avx2.c \
+ lpc_intrin_fma.c \
+ lpc_intrin_neon.c \
+ md5.c \
+ memory.c \
+ metadata_iterators.c \
+ metadata_object.c \
+ stream_decoder.c \
+ stream_encoder.c \
+ stream_encoder_intrin_sse2.c \
+ stream_encoder_intrin_ssse3.c \
+ stream_encoder_intrin_avx2.c \
+ stream_encoder_framing.c \
+ window.c \
+ $(windows_unicode_compat) \
+ $(extra_ogg_sources)
+
+libFLAC_la_SOURCES = $(libFLAC_sources)
+
+# needed for test_libFLAC
+libFLAC_static_la_SOURCES = $(libFLAC_sources)
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj .rc
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/libFLAC/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/libFLAC/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+flac.pc: $(top_builddir)/config.status $(srcdir)/flac.pc.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+../share/win_utf8_io/$(am__dirstamp):
+ @$(MKDIR_P) ../share/win_utf8_io
+ @: > ../share/win_utf8_io/$(am__dirstamp)
+../share/win_utf8_io/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) ../share/win_utf8_io/$(DEPDIR)
+ @: > ../share/win_utf8_io/$(DEPDIR)/$(am__dirstamp)
+../share/win_utf8_io/win_utf8_io.lo: \
+ ../share/win_utf8_io/$(am__dirstamp) \
+ ../share/win_utf8_io/$(DEPDIR)/$(am__dirstamp)
+
+libFLAC-static.la: $(libFLAC_static_la_OBJECTS) $(libFLAC_static_la_DEPENDENCIES) $(EXTRA_libFLAC_static_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libFLAC_static_la_OBJECTS) $(libFLAC_static_la_LIBADD) $(LIBS)
+
+libFLAC.la: $(libFLAC_la_OBJECTS) $(libFLAC_la_DEPENDENCIES) $(EXTRA_libFLAC_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libFLAC_la_LINK) -rpath $(libdir) $(libFLAC_la_OBJECTS) $(libFLAC_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+ -rm -f ../share/win_utf8_io/*.$(OBJEXT)
+ -rm -f ../share/win_utf8_io/*.lo
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@../share/win_utf8_io/$(DEPDIR)/win_utf8_io.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bitmath.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bitreader.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bitwriter.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crc.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fixed.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fixed_intrin_avx2.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fixed_intrin_sse2.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fixed_intrin_sse42.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fixed_intrin_ssse3.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/float.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/format.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lpc.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lpc_intrin_avx2.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lpc_intrin_fma.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lpc_intrin_neon.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lpc_intrin_sse2.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lpc_intrin_sse41.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memory.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/metadata_iterators.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/metadata_object.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ogg_decoder_aspect.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ogg_encoder_aspect.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ogg_helper.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ogg_mapping.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream_decoder.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream_encoder.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream_encoder_framing.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream_encoder_intrin_avx2.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream_encoder_intrin_sse2.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream_encoder_intrin_ssse3.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/window.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+ -rm -rf ../share/win_utf8_io/.libs ../share/win_utf8_io/_libs
+install-m4dataDATA: $(m4data_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(m4data_DATA)'; test -n "$(m4datadir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(m4datadir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(m4datadir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(m4datadir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(m4datadir)" || exit $$?; \
+ done
+
+uninstall-m4dataDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(m4data_DATA)'; test -n "$(m4datadir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(m4datadir)'; $(am__uninstall_files_from_dir)
+install-pkgconfigDATA: $(pkgconfig_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \
+ done
+
+uninstall-pkgconfigDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir)
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(LTLIBRARIES) $(DATA)
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(m4datadir)" "$(DESTDIR)$(pkgconfigdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+ -rm -f ../share/win_utf8_io/$(DEPDIR)/$(am__dirstamp)
+ -rm -f ../share/win_utf8_io/$(am__dirstamp)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f ../share/win_utf8_io/$(DEPDIR)/win_utf8_io.Plo
+ -rm -f ./$(DEPDIR)/bitmath.Plo
+ -rm -f ./$(DEPDIR)/bitreader.Plo
+ -rm -f ./$(DEPDIR)/bitwriter.Plo
+ -rm -f ./$(DEPDIR)/cpu.Plo
+ -rm -f ./$(DEPDIR)/crc.Plo
+ -rm -f ./$(DEPDIR)/fixed.Plo
+ -rm -f ./$(DEPDIR)/fixed_intrin_avx2.Plo
+ -rm -f ./$(DEPDIR)/fixed_intrin_sse2.Plo
+ -rm -f ./$(DEPDIR)/fixed_intrin_sse42.Plo
+ -rm -f ./$(DEPDIR)/fixed_intrin_ssse3.Plo
+ -rm -f ./$(DEPDIR)/float.Plo
+ -rm -f ./$(DEPDIR)/format.Plo
+ -rm -f ./$(DEPDIR)/lpc.Plo
+ -rm -f ./$(DEPDIR)/lpc_intrin_avx2.Plo
+ -rm -f ./$(DEPDIR)/lpc_intrin_fma.Plo
+ -rm -f ./$(DEPDIR)/lpc_intrin_neon.Plo
+ -rm -f ./$(DEPDIR)/lpc_intrin_sse2.Plo
+ -rm -f ./$(DEPDIR)/lpc_intrin_sse41.Plo
+ -rm -f ./$(DEPDIR)/md5.Plo
+ -rm -f ./$(DEPDIR)/memory.Plo
+ -rm -f ./$(DEPDIR)/metadata_iterators.Plo
+ -rm -f ./$(DEPDIR)/metadata_object.Plo
+ -rm -f ./$(DEPDIR)/ogg_decoder_aspect.Plo
+ -rm -f ./$(DEPDIR)/ogg_encoder_aspect.Plo
+ -rm -f ./$(DEPDIR)/ogg_helper.Plo
+ -rm -f ./$(DEPDIR)/ogg_mapping.Plo
+ -rm -f ./$(DEPDIR)/stream_decoder.Plo
+ -rm -f ./$(DEPDIR)/stream_encoder.Plo
+ -rm -f ./$(DEPDIR)/stream_encoder_framing.Plo
+ -rm -f ./$(DEPDIR)/stream_encoder_intrin_avx2.Plo
+ -rm -f ./$(DEPDIR)/stream_encoder_intrin_sse2.Plo
+ -rm -f ./$(DEPDIR)/stream_encoder_intrin_ssse3.Plo
+ -rm -f ./$(DEPDIR)/window.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-m4dataDATA install-pkgconfigDATA
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f ../share/win_utf8_io/$(DEPDIR)/win_utf8_io.Plo
+ -rm -f ./$(DEPDIR)/bitmath.Plo
+ -rm -f ./$(DEPDIR)/bitreader.Plo
+ -rm -f ./$(DEPDIR)/bitwriter.Plo
+ -rm -f ./$(DEPDIR)/cpu.Plo
+ -rm -f ./$(DEPDIR)/crc.Plo
+ -rm -f ./$(DEPDIR)/fixed.Plo
+ -rm -f ./$(DEPDIR)/fixed_intrin_avx2.Plo
+ -rm -f ./$(DEPDIR)/fixed_intrin_sse2.Plo
+ -rm -f ./$(DEPDIR)/fixed_intrin_sse42.Plo
+ -rm -f ./$(DEPDIR)/fixed_intrin_ssse3.Plo
+ -rm -f ./$(DEPDIR)/float.Plo
+ -rm -f ./$(DEPDIR)/format.Plo
+ -rm -f ./$(DEPDIR)/lpc.Plo
+ -rm -f ./$(DEPDIR)/lpc_intrin_avx2.Plo
+ -rm -f ./$(DEPDIR)/lpc_intrin_fma.Plo
+ -rm -f ./$(DEPDIR)/lpc_intrin_neon.Plo
+ -rm -f ./$(DEPDIR)/lpc_intrin_sse2.Plo
+ -rm -f ./$(DEPDIR)/lpc_intrin_sse41.Plo
+ -rm -f ./$(DEPDIR)/md5.Plo
+ -rm -f ./$(DEPDIR)/memory.Plo
+ -rm -f ./$(DEPDIR)/metadata_iterators.Plo
+ -rm -f ./$(DEPDIR)/metadata_object.Plo
+ -rm -f ./$(DEPDIR)/ogg_decoder_aspect.Plo
+ -rm -f ./$(DEPDIR)/ogg_encoder_aspect.Plo
+ -rm -f ./$(DEPDIR)/ogg_helper.Plo
+ -rm -f ./$(DEPDIR)/ogg_mapping.Plo
+ -rm -f ./$(DEPDIR)/stream_decoder.Plo
+ -rm -f ./$(DEPDIR)/stream_encoder.Plo
+ -rm -f ./$(DEPDIR)/stream_encoder_framing.Plo
+ -rm -f ./$(DEPDIR)/stream_encoder_intrin_avx2.Plo
+ -rm -f ./$(DEPDIR)/stream_encoder_intrin_sse2.Plo
+ -rm -f ./$(DEPDIR)/stream_encoder_intrin_ssse3.Plo
+ -rm -f ./$(DEPDIR)/window.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-libLTLIBRARIES uninstall-m4dataDATA \
+ uninstall-pkgconfigDATA
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
+ am--depfiles check check-am clean clean-generic \
+ clean-libLTLIBRARIES clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-libLTLIBRARIES \
+ install-m4dataDATA install-man install-pdf install-pdf-am \
+ install-pkgconfigDATA install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs installdirs-am \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
+ uninstall-libLTLIBRARIES uninstall-m4dataDATA \
+ uninstall-pkgconfigDATA
+
+.PRECIOUS: Makefile
+
+
+.rc.o:
+ $(RC) $(AM_CPPFLAGS) $< $@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/libFLAC/bitmath.c b/src/libFLAC/bitmath.c
new file mode 100644
index 0000000..077486b
--- /dev/null
+++ b/src/libFLAC/bitmath.c
@@ -0,0 +1,73 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "private/bitmath.h"
+
+/* 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
+ */
+uint32_t FLAC__bitmath_silog2(FLAC__int64 v)
+{
+ if(v == 0)
+ return 0;
+
+ if(v == -1)
+ return 2;
+
+ v = (v < 0) ? (-(v+1)) : v;
+ return FLAC__bitmath_ilog2_wide(v)+2;
+}
diff --git a/src/libFLAC/bitreader.c b/src/libFLAC/bitreader.c
new file mode 100644
index 0000000..829b308
--- /dev/null
+++ b/src/libFLAC/bitreader.c
@@ -0,0 +1,1052 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include "private/bitmath.h"
+#include "private/bitreader.h"
+#include "private/crc.h"
+#include "private/cpu.h"
+#include "private/macros.h"
+#include "FLAC/assert.h"
+#include "share/compat.h"
+#include "share/endswap.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_MSBS2 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 */
+
+#if (ENABLE_64_BIT_WORDS == 0)
+
+typedef FLAC__uint32 brword;
+#define FLAC__BYTES_PER_WORD 4 /* sizeof brword */
+#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
+#define SWAP_BE_WORD_TO_HOST(x) ENDSWAP_32(x)
+#endif
+/* counts the # of zero MSBs in a word */
+#define COUNT_ZERO_MSBS(word) FLAC__clz_uint32(word)
+#define COUNT_ZERO_MSBS2(word) FLAC__clz2_uint32(word)
+
+#else
+
+typedef FLAC__uint64 brword;
+#define FLAC__BYTES_PER_WORD 8 /* sizeof brword */
+#define FLAC__BITS_PER_WORD 64
+#define FLAC__WORD_ALL_ONES ((FLAC__uint64)FLAC__U64L(0xffffffffffffffff))
+/* 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
+#define SWAP_BE_WORD_TO_HOST(x) ENDSWAP_64(x)
+#endif
+/* counts the # of zero MSBs in a word */
+#define COUNT_ZERO_MSBS(word) FLAC__clz_uint64(word)
+#define COUNT_ZERO_MSBS2(word) FLAC__clz2_uint64(word)
+
+#endif
+
+/*
+ * 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 uint32_t FLAC__BITREADER_DEFAULT_CAPACITY = 65536u / FLAC__BITS_PER_WORD; /* in words */
+
+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;
+ uint32_t capacity; /* in words */
+ uint32_t words; /* # of completed words in buffer */
+ uint32_t bytes; /* # of bytes in incomplete word at buffer[words] */
+ uint32_t consumed_words; /* #words ... */
+ uint32_t consumed_bits; /* ... + (#bits of head word) already consumed from the front of buffer */
+ uint32_t read_crc16; /* the running frame CRC */
+ uint32_t crc16_offset; /* the number of words in the current buffer that should not be CRC'd */
+ uint32_t crc16_align; /* the number of bits in the current consumed word that should not be CRC'd */
+ FLAC__bool read_limit_set; /* whether reads are limited */
+ uint32_t read_limit; /* the remaining size of what can be read */
+ uint32_t last_seen_framesync; /* the location of the last seen framesync, if it is in the buffer, in bits from front of buffer */
+ FLAC__BitReaderReadCallback read_callback;
+ void *client_data;
+};
+
+static inline void crc16_update_word_(FLAC__BitReader *br, brword word)
+{
+ register uint32_t crc = br->read_crc16;
+
+ for ( ; br->crc16_align < FLAC__BITS_PER_WORD ; br->crc16_align += 8) {
+ uint32_t shift = FLAC__BITS_PER_WORD - 8 - br->crc16_align ;
+ crc = FLAC__CRC16_UPDATE ((uint32_t) (shift < FLAC__BITS_PER_WORD ? (word >> shift) & 0xff : 0), crc);
+ }
+
+ br->read_crc16 = crc;
+ br->crc16_align = 0;
+}
+
+static inline void crc16_update_block_(FLAC__BitReader *br)
+{
+ if(br->consumed_words > br->crc16_offset && br->crc16_align)
+ crc16_update_word_(br, br->buffer[br->crc16_offset++]);
+
+ /* Prevent OOB read due to wrap-around. */
+ if (br->consumed_words > br->crc16_offset) {
+#if FLAC__BYTES_PER_WORD == 4
+ br->read_crc16 = FLAC__crc16_update_words32(br->buffer + br->crc16_offset, br->consumed_words - br->crc16_offset, br->read_crc16);
+#elif FLAC__BYTES_PER_WORD == 8
+ br->read_crc16 = FLAC__crc16_update_words64(br->buffer + br->crc16_offset, br->consumed_words - br->crc16_offset, br->read_crc16);
+#else
+ unsigned i;
+
+ for (i = br->crc16_offset; i < br->consumed_words; i++)
+ crc16_update_word_(br, br->buffer[i]);
+#endif
+ }
+
+ br->crc16_offset = 0;
+}
+
+static FLAC__bool bitreader_read_from_client_(FLAC__BitReader *br)
+{
+ uint32_t start, end;
+ size_t bytes;
+ FLAC__byte *target;
+#if WORDS_BIGENDIAN
+#else
+ brword preswap_backup;
+#endif
+
+ /* first shift the unconsumed buffer data toward the front as much as possible */
+ if(br->consumed_words > 0) {
+ /* invalidate last seen framesync */
+ br->last_seen_framesync = -1;
+
+ crc16_update_block_(br); /* CRC consumed words */
+
+ 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 laid 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
+ preswap_backup = br->buffer[br->words];
+ 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)){
+ /* Despite the read callback failing, the data in the target
+ * might be used later, when the buffer is rewound. Therefore
+ * we revert the swap that was just done */
+#if WORDS_BIGENDIAN
+#else
+ br->buffer[br->words] = preswap_backup;
+#endif
+ 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 + (uint32_t)bytes + (FLAC__BYTES_PER_WORD-1)) / FLAC__BYTES_PER_WORD;
+ 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 + (uint32_t)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 = 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__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 = malloc(sizeof(brword) * br->capacity);
+ if(br->buffer == 0)
+ return false;
+ br->read_callback = rcb;
+ br->client_data = cd;
+ br->read_limit_set = false;
+ br->read_limit = -1;
+ br->last_seen_framesync = -1;
+
+ 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;
+ br->read_limit_set = false;
+ br->read_limit = -1;
+ br->last_seen_framesync = -1;
+}
+
+FLAC__bool FLAC__bitreader_clear(FLAC__BitReader *br)
+{
+ br->words = br->bytes = 0;
+ br->consumed_words = br->consumed_bits = 0;
+ br->read_limit_set = false;
+ br->read_limit = -1;
+ br->last_seen_framesync = -1;
+ return true;
+}
+
+void FLAC__bitreader_set_framesync_location(FLAC__BitReader *br)
+{
+ br->last_seen_framesync = br->consumed_words * FLAC__BYTES_PER_WORD + br->consumed_bits / 8;
+}
+
+FLAC__bool FLAC__bitreader_rewind_to_after_last_seen_framesync(FLAC__BitReader *br)
+{
+ if(br->last_seen_framesync == (uint32_t)-1) {
+ br->consumed_words = br->consumed_bits = 0;
+ return false;
+ }
+ else {
+ br->consumed_words = (br->last_seen_framesync + 1) / FLAC__BYTES_PER_WORD;
+ br->consumed_bits = ((br->last_seen_framesync + 1) % FLAC__BYTES_PER_WORD) * 8;
+ return true;
+ }
+}
+
+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 = (uint32_t)seed;
+ br->crc16_offset = br->consumed_words;
+ 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);
+
+ /* CRC consumed words up to here */
+ crc16_update_block_(br);
+
+ 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((uint32_t)((tail >> (FLAC__BITS_PER_WORD-8-br->crc16_align)) & 0xff), br->read_crc16);
+ }
+ return br->read_crc16;
+}
+
+inline FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br)
+{
+ return ((br->consumed_bits & 7) == 0);
+}
+
+inline uint32_t FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br)
+{
+ return 8 - (br->consumed_bits & 7);
+}
+
+inline uint32_t 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;
+}
+
+void FLAC__bitreader_set_limit(FLAC__BitReader *br, uint32_t limit)
+{
+ br->read_limit = limit;
+ br->read_limit_set = true;
+}
+
+void FLAC__bitreader_remove_limit(FLAC__BitReader *br)
+{
+ br->read_limit_set = false;
+ br->read_limit = -1;
+}
+
+uint32_t FLAC__bitreader_limit_remaining(FLAC__BitReader *br)
+{
+ FLAC__ASSERT(br->read_limit_set);
+ return br->read_limit;
+}
+void FLAC__bitreader_limit_invalidate(FLAC__BitReader *br)
+{
+ br->read_limit = -1;
+}
+
+FLAC__bool FLAC__bitreader_read_raw_uint32(FLAC__BitReader *br, FLAC__uint32 *val, uint32_t 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;
+ }
+
+ if(br->read_limit_set && br->read_limit < (uint32_t)-1){
+ if(br->read_limit < bits) {
+ br->read_limit = -1;
+ return false;
+ }
+ else
+ br->read_limit -= bits;
+ }
+
+ 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 uint32_t n = FLAC__BITS_PER_WORD - br->consumed_bits;
+ const brword word = br->buffer[br->consumed_words];
+ const brword mask = br->consumed_bits < FLAC__BITS_PER_WORD ? FLAC__WORD_ALL_ONES >> br->consumed_bits : 0;
+ if(bits < n) {
+ uint32_t shift = n - bits;
+ *val = shift < FLAC__BITS_PER_WORD ? (FLAC__uint32)((word & mask) >> shift) : 0; /* The result has <= 32 non-zero bits */
+ br->consumed_bits += bits;
+ return true;
+ }
+ /* (FLAC__BITS_PER_WORD - br->consumed_bits <= bits) ==> (FLAC__WORD_ALL_ONES >> br->consumed_bits) has no more than 'bits' non-zero bits */
+ *val = (FLAC__uint32)(word & mask);
+ bits -= n;
+ 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 */
+ uint32_t shift = FLAC__BITS_PER_WORD - bits;
+ *val = bits < 32 ? *val << bits : 0;
+ *val |= shift < FLAC__BITS_PER_WORD ? (FLAC__uint32)(br->buffer[br->consumed_words] >> shift) : 0;
+ br->consumed_bits = bits;
+ }
+ return true;
+ }
+ else { /* br->consumed_bits == 0 */
+ const brword word = br->buffer[br->consumed_words];
+ if(bits < FLAC__BITS_PER_WORD) {
+ *val = (FLAC__uint32)(word >> (FLAC__BITS_PER_WORD-bits));
+ br->consumed_bits = bits;
+ return true;
+ }
+ /* at this point bits == FLAC__BITS_PER_WORD == 32; because of previous assertions, it can't be larger */
+ *val = (FLAC__uint32)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 = (FLAC__uint32)((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 = (FLAC__uint32)(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, uint32_t bits)
+{
+ FLAC__uint32 uval, mask;
+ /* OPT: inline raw uint32 code here, or make into a macro if possible in the .h file */
+ if (bits < 1 || ! FLAC__bitreader_read_raw_uint32(br, &uval, bits))
+ return false;
+ /* sign-extend *val assuming it is currently bits wide. */
+ /* From: https://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend */
+ mask = bits >= 33 ? 0 : 1lu << (bits - 1);
+ *val = (uval ^ mask) - mask;
+ return true;
+}
+
+FLAC__bool FLAC__bitreader_read_raw_uint64(FLAC__BitReader *br, FLAC__uint64 *val, uint32_t 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__bool FLAC__bitreader_read_raw_int64(FLAC__BitReader *br, FLAC__int64 *val, uint32_t bits)
+{
+ FLAC__uint64 uval, mask;
+ /* OPT: inline raw uint64 code here, or make into a macro if possible in the .h file */
+ if (bits < 1 || ! FLAC__bitreader_read_raw_uint64(br, &uval, bits))
+ return false;
+ /* sign-extend *val assuming it is currently bits wide. */
+ /* From: https://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend */
+ mask = bits >= 65 ? 0 : 1llu << (bits - 1);
+ *val = (uval ^ mask) - mask;
+ return true;
+}
+
+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, uint32_t 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 uint32_t n = br->consumed_bits & 7;
+ uint32_t m;
+ FLAC__uint32 x;
+
+ if(n != 0) {
+ m = flac_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, uint32_t nvals)
+{
+ FLAC__uint32 x;
+
+ FLAC__ASSERT(0 != br);
+ FLAC__ASSERT(0 != br->buffer);
+ FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(br));
+
+ if(br->read_limit_set && br->read_limit < (uint32_t)-1){
+ if(br->read_limit < nvals*8){
+ br->read_limit = -1;
+ return false;
+ }
+ }
+
+ /* 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;
+ if(br->read_limit_set)
+ br->read_limit -= FLAC__BITS_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, uint32_t nvals)
+{
+ FLAC__uint32 x;
+
+ FLAC__ASSERT(0 != br);
+ FLAC__ASSERT(0 != br->buffer);
+ FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(br));
+
+ if(br->read_limit_set && br->read_limit < (uint32_t)-1){
+ if(br->read_limit < nvals*8){
+ br->read_limit = -1;
+ return false;
+ }
+ }
+
+ /* 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;
+ if(br->read_limit_set)
+ br->read_limit -= FLAC__BITS_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__bool FLAC__bitreader_read_unary_unsigned(FLAC__BitReader *br, uint32_t *val)
+#if 0 /* slow but readable version */
+{
+ uint32_t 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
+{
+ uint32_t 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->consumed_bits < FLAC__BITS_PER_WORD ? br->buffer[br->consumed_words] << br->consumed_bits : 0;
+ 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) */
+ br->consumed_words++;
+ br->consumed_bits = 0;
+ }
+ return true;
+ }
+ else {
+ *val += FLAC__BITS_PER_WORD - br->consumed_bits;
+ 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*8 > br->consumed_bits) {
+ const uint32_t 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
+
+#if 0 /* unused */
+FLAC__bool FLAC__bitreader_read_rice_signed(FLAC__BitReader *br, int *val, uint32_t parameter)
+{
+ FLAC__uint32 lsbs = 0, msbs = 0;
+ uint32_t 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;
+}
+#endif
+
+/* this is by far the most heavily used reader call. it ain't pretty but it's fast */
+FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], uint32_t nvals, uint32_t parameter)
+#include "deduplication/bitreader_read_rice_signed_block.c"
+
+#ifdef FLAC__BMI2_SUPPORTED
+FLAC__SSE_TARGET("bmi2")
+FLAC__bool FLAC__bitreader_read_rice_signed_block_bmi2(FLAC__BitReader *br, int vals[], uint32_t nvals, uint32_t parameter)
+#include "deduplication/bitreader_read_rice_signed_block.c"
+#endif
+
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitreader_read_golomb_signed(FLAC__BitReader *br, int *val, uint32_t parameter)
+{
+ FLAC__uint32 lsbs = 0, msbs = 0;
+ uint32_t 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 {
+ uint32_t 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 uint32_t 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, uint32_t *val, uint32_t parameter)
+{
+ FLAC__uint32 lsbs, msbs = 0;
+ uint32_t 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 {
+ uint32_t 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, uint32_t *rawlen)
+{
+ FLAC__uint32 v = 0;
+ FLAC__uint32 x;
+ uint32_t 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, uint32_t *rawlen)
+{
+ FLAC__uint64 v = 0;
+ FLAC__uint32 x;
+ uint32_t 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;
+}
+
+/* These functions are declared inline in this file but are also callable as
+ * externs from elsewhere.
+ * According to the C99 spec, section 6.7.4, simply providing a function
+ * prototype in a header file without 'inline' and making the function inline
+ * in this file should be sufficient.
+ * Unfortunately, the Microsoft VS compiler doesn't pick them up externally. To
+ * fix that we add extern declarations here.
+ */
+extern FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br);
+extern uint32_t FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br);
+extern uint32_t FLAC__bitreader_get_input_bits_unconsumed(const FLAC__BitReader *br);
+extern FLAC__bool FLAC__bitreader_read_uint32_little_endian(FLAC__BitReader *br, FLAC__uint32 *val);
diff --git a/src/libFLAC/bitwriter.c b/src/libFLAC/bitwriter.c
new file mode 100644
index 0000000..1d7be80
--- /dev/null
+++ b/src/libFLAC/bitwriter.c
@@ -0,0 +1,955 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include "private/bitwriter.h"
+#include "private/crc.h"
+#include "private/format.h"
+#include "private/macros.h"
+#include "private/stream_encoder.h"
+#include "FLAC/assert.h"
+#include "share/alloc.h"
+#include "share/compat.h"
+#include "share/endswap.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 */
+
+#if (ENABLE_64_BIT_WORDS == 0)
+
+typedef FLAC__uint32 bwword;
+typedef FLAC__uint64 FLAC__bwtemp;
+#define FLAC__BYTES_PER_WORD 4 /* sizeof bwword */
+#define FLAC__BITS_PER_WORD 32
+#define FLAC__TEMP_BITS 64
+#define FLAC__HALF_TEMP_BITS 32
+/* 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
+#define SWAP_BE_WORD_TO_HOST(x) ENDSWAP_32(x)
+#endif
+
+#else
+
+typedef FLAC__uint64 bwword;
+typedef FLAC__uint64 FLAC__bwtemp;
+#define FLAC__BYTES_PER_WORD 8 /* sizeof bwword */
+#define FLAC__BITS_PER_WORD 64
+#define FLAC__TEMP_BITS 64
+#define FLAC__HALF_TEMP_BITS 32
+/* 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
+#define SWAP_BE_WORD_TO_HOST(x) ENDSWAP_64(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 uint32_t FLAC__BITWRITER_DEFAULT_CAPACITY = 32768u / sizeof(bwword); /* size in words */
+/* When growing, increment 4K at a time */
+static const uint32_t 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)
+
+struct FLAC__BitWriter {
+ bwword *buffer;
+ bwword accum; /* accumulator; bits are right-justified; when full, accum is appended to buffer */
+ uint32_t capacity; /* capacity of buffer in words */
+ uint32_t words; /* # of complete words in buffer */
+ uint32_t bits; /* # of used bits in accum */
+};
+
+/* * WATCHOUT: The current implementation only grows the buffer. */
+#ifndef __SUNPRO_C
+static
+#endif
+FLAC__bool bitwriter_grow_(FLAC__BitWriter *bw, uint32_t bits_to_add)
+{
+ uint32_t 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;
+
+ if(new_capacity * sizeof(bwword) > (1u << FLAC__STREAM_METADATA_LENGTH_LEN))
+ /* Requested new capacity is larger than the largest possible metadata block,
+ * which is also larger than the largest sane framesize. That means something
+ * went very wrong somewhere and previous checks failed.
+ * To prevent chrashing, give up */
+ return false;
+
+ /* 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 = safe_realloc_nofree_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 = 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 = 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;
+}
+
+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);
+}
+
+uint32_t 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;
+}
+
+inline FLAC__bool FLAC__bitwriter_write_zeroes(FLAC__BitWriter *bw, uint32_t bits)
+{
+ uint32_t 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 = flac_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;
+}
+
+static inline FLAC__bool FLAC__bitwriter_write_raw_uint32_nocheck(FLAC__BitWriter *bw, FLAC__uint32 val, uint32_t bits)
+{
+ register uint32_t 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);
+
+ if(bw == 0 || bw->buffer == 0)
+ return false;
+
+ if (bits > 32)
+ return false;
+
+ if(bits == 0)
+ return true;
+
+ FLAC__ASSERT((bits == 32) || (val>>bits == 0));
+
+ /* 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; /* unused top bits can contain garbage */
+ }
+ else { /* at this point bits == FLAC__BITS_PER_WORD == 32 and bw->bits == 0 */
+ bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST((bwword)val);
+ }
+
+ return true;
+}
+
+inline FLAC__bool FLAC__bitwriter_write_raw_uint32(FLAC__BitWriter *bw, FLAC__uint32 val, uint32_t bits)
+{
+ /* check that unused bits are unset */
+ if((bits < 32) && (val>>bits != 0))
+ return false;
+
+ return FLAC__bitwriter_write_raw_uint32_nocheck(bw, val, bits);
+}
+
+inline FLAC__bool FLAC__bitwriter_write_raw_int32(FLAC__BitWriter *bw, FLAC__int32 val, uint32_t bits)
+{
+ /* zero-out unused bits */
+ if(bits < 32)
+ val &= (~(0xffffffff << bits));
+
+ return FLAC__bitwriter_write_raw_uint32_nocheck(bw, (FLAC__uint32)val, bits);
+}
+
+inline FLAC__bool FLAC__bitwriter_write_raw_uint64(FLAC__BitWriter *bw, FLAC__uint64 val, uint32_t 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_nocheck(bw, (FLAC__uint32)val, 32);
+ }
+ else
+ return FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)val, bits);
+}
+
+inline FLAC__bool FLAC__bitwriter_write_raw_int64(FLAC__BitWriter *bw, FLAC__int64 val, uint32_t bits)
+{
+ FLAC__uint64 uval = val;
+ /* zero-out unused bits */
+ if(bits < 64)
+ uval &= (~(UINT64_MAX << bits));
+ return FLAC__bitwriter_write_raw_uint64(bw, uval, bits);
+}
+
+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_nocheck(bw, val & 0xff, 8))
+ return false;
+ if(!FLAC__bitwriter_write_raw_uint32_nocheck(bw, (val>>8) & 0xff, 8))
+ return false;
+ if(!FLAC__bitwriter_write_raw_uint32_nocheck(bw, (val>>16) & 0xff, 8))
+ return false;
+ if(!FLAC__bitwriter_write_raw_uint32_nocheck(bw, val>>24, 8))
+ return false;
+
+ return true;
+}
+
+inline FLAC__bool FLAC__bitwriter_write_byte_block(FLAC__BitWriter *bw, const FLAC__byte vals[], uint32_t nvals)
+{
+ uint32_t i;
+
+ /* grow capacity upfront to prevent constant reallocation during writes */
+ if(bw->capacity <= bw->words + nvals / (FLAC__BITS_PER_WORD / 8) + 1 && !bitwriter_grow_(bw, nvals * 8))
+ return false;
+
+ /* 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_nocheck(bw, (FLAC__uint32)(vals[i]), 8))
+ return false;
+ }
+
+ return true;
+}
+
+FLAC__bool FLAC__bitwriter_write_unary_unsigned(FLAC__BitWriter *bw, uint32_t val)
+{
+ if(val < 32)
+ return FLAC__bitwriter_write_raw_uint32_nocheck(bw, 1, ++val);
+ else
+ return
+ FLAC__bitwriter_write_zeroes(bw, val) &&
+ FLAC__bitwriter_write_raw_uint32_nocheck(bw, 1, 1);
+}
+
+#if 0 /* UNUSED */
+uint32_t FLAC__bitwriter_rice_bits(FLAC__int32 val, uint32_t parameter)
+{
+ FLAC__uint32 uval;
+
+ FLAC__ASSERT(parameter < 32);
+
+ /* fold signed to uint32_t; actual formula is: negative(v)? -2v-1 : 2v */
+ uval = val;
+ uval <<= 1;
+ uval ^= (val>>31);
+
+ return 1 + parameter + (uval >> parameter);
+}
+
+uint32_t FLAC__bitwriter_golomb_bits_signed(int val, uint32_t parameter)
+{
+ uint32_t bits, msbs, uval;
+ uint32_t k;
+
+ FLAC__ASSERT(parameter > 0);
+
+ /* fold signed to uint32_t */
+ if(val < 0)
+ uval = (uint32_t)(((-(++val)) << 1) + 1);
+ else
+ uval = (uint32_t)(val << 1);
+
+ k = FLAC__bitmath_ilog2(parameter);
+ if(parameter == 1u<<k) {
+ FLAC__ASSERT(k <= 30);
+
+ msbs = uval >> k;
+ bits = 1 + k + msbs;
+ }
+ else {
+ uint32_t 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;
+}
+
+uint32_t FLAC__bitwriter_golomb_bits_unsigned(uint32_t uval, uint32_t parameter)
+{
+ uint32_t bits, msbs;
+ uint32_t 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 {
+ uint32_t 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;
+}
+
+FLAC__bool FLAC__bitwriter_write_rice_signed(FLAC__BitWriter *bw, FLAC__int32 val, uint32_t parameter)
+{
+ uint32_t total_bits, interesting_bits, msbs;
+ FLAC__uint32 uval, pattern;
+
+ FLAC__ASSERT(0 != bw);
+ FLAC__ASSERT(0 != bw->buffer);
+ FLAC__ASSERT(parameter < 32);
+
+ /* fold signed to uint32_t; actual formula is: negative(v)? -2v-1 : 2v */
+ uval = val;
+ uval <<= 1;
+ uval ^= (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 */
+}
+#endif /* UNUSED */
+
+#if (ENABLE_64_BIT_WORDS == 0)
+
+#define WIDE_ACCUM_TO_BW { \
+ bw->accum = wide_accum >> FLAC__HALF_TEMP_BITS; \
+ bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum); \
+ wide_accum <<= FLAC__HALF_TEMP_BITS; \
+ bitpointer += FLAC__HALF_TEMP_BITS; \
+}
+
+#else
+
+#define WIDE_ACCUM_TO_BW { \
+ FLAC__ASSERT(bw->bits % FLAC__HALF_TEMP_BITS == 0); \
+ if(bw->bits == 0) { \
+ bw->accum = wide_accum >> FLAC__HALF_TEMP_BITS; \
+ wide_accum <<= FLAC__HALF_TEMP_BITS; \
+ bw->bits = FLAC__HALF_TEMP_BITS; \
+ } \
+ else { \
+ bw->accum <<= FLAC__HALF_TEMP_BITS; \
+ bw->accum += wide_accum >> FLAC__HALF_TEMP_BITS; \
+ bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum); \
+ wide_accum <<= FLAC__HALF_TEMP_BITS; \
+ bw->bits = 0; \
+ } \
+ bitpointer += FLAC__HALF_TEMP_BITS; \
+}
+
+#endif
+
+FLAC__bool FLAC__bitwriter_write_rice_signed_block(FLAC__BitWriter *bw, const FLAC__int32 *vals, uint32_t nvals, uint32_t parameter)
+{
+ const FLAC__uint32 mask1 = (FLAC__uint32)0xffffffff << parameter; /* we val|=mask1 to set the stop bit above it... */
+ const FLAC__uint32 mask2 = (FLAC__uint32)0xffffffff >> (31-parameter); /* ...then mask off the bits above the stop bit with val&=mask2 */
+ FLAC__uint32 uval;
+ const uint32_t lsbits = 1 + parameter;
+ uint32_t msbits, total_bits;
+ FLAC__bwtemp wide_accum = 0;
+ FLAC__uint32 bitpointer = FLAC__TEMP_BITS;
+
+ FLAC__ASSERT(0 != bw);
+ FLAC__ASSERT(0 != bw->buffer);
+ FLAC__ASSERT(parameter < 31);
+ /* 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 (ENABLE_64_BIT_WORDS == 0)
+ if(bw->bits > 0) {
+ bitpointer -= bw->bits;
+ wide_accum = (FLAC__bwtemp)(bw->accum) << bitpointer;
+ bw->bits = 0;
+ }
+#else
+ if(bw->bits > 0 && bw->bits < FLAC__HALF_TEMP_BITS) {
+ bitpointer -= bw->bits;
+ wide_accum = bw->accum << bitpointer;
+ bw->bits = 0;
+ }
+ else if(bw->bits > FLAC__HALF_TEMP_BITS) {
+ bitpointer -= (bw->bits - FLAC__HALF_TEMP_BITS);
+ wide_accum = bw->accum << bitpointer;
+ bw->accum >>= (bw->bits - FLAC__HALF_TEMP_BITS);
+ bw->bits = FLAC__HALF_TEMP_BITS;
+ }
+#endif
+
+ /* Reserve one FLAC__TEMP_BITS per symbol, so checks for space are only necessary when very large symbols are encountered
+ * this might be considered wasteful, but is only at most 8kB more than necessary for a blocksize of 4096 */
+ if(bw->capacity * FLAC__BITS_PER_WORD <= bw->words * FLAC__BITS_PER_WORD + nvals * FLAC__TEMP_BITS + bw->bits && !bitwriter_grow_(bw, nvals * FLAC__TEMP_BITS))
+ return false;
+
+ while(nvals) {
+ /* fold signed to uint32_t; actual formula is: negative(v)? -2v-1 : 2v */
+ uval = *vals;
+ uval <<= 1;
+ uval ^= (*vals>>31);
+
+ msbits = uval >> parameter;
+ total_bits = lsbits + msbits;
+
+ uval |= mask1; /* set stop bit */
+ uval &= mask2; /* mask off unused top bits */
+
+
+ if(total_bits <= bitpointer) {
+ /* There is room enough to store the symbol whole at once */
+ wide_accum |= (FLAC__bwtemp)(uval) << (bitpointer - total_bits);
+ bitpointer -= total_bits;
+ if(bitpointer <= FLAC__HALF_TEMP_BITS) {
+ /* A word is finished, copy the upper 32 bits of the wide_accum */
+ WIDE_ACCUM_TO_BW
+ }
+ }
+ else {
+ /* The symbol needs to be split. This code isn't used often */
+ /* First check for space in the bitwriter */
+ if(total_bits > FLAC__TEMP_BITS) {
+ FLAC__uint32 oversize_in_bits = total_bits - FLAC__TEMP_BITS;
+ FLAC__uint32 capacity_needed = bw->words * FLAC__BITS_PER_WORD + bw->bits + nvals * FLAC__TEMP_BITS + oversize_in_bits;
+ if(bw->capacity * FLAC__BITS_PER_WORD <= capacity_needed && !bitwriter_grow_(bw, nvals * FLAC__TEMP_BITS + oversize_in_bits))
+ return false;
+ }
+ if(msbits > bitpointer) {
+ /* We have a lot of 0 bits to write, first align with bitwriter word */
+ msbits -= bitpointer - FLAC__HALF_TEMP_BITS;
+ bitpointer = FLAC__HALF_TEMP_BITS;
+ WIDE_ACCUM_TO_BW
+ while(msbits > bitpointer) {
+ /* As the accumulator is already zero, we only need to
+ * assign zeroes to the bitbuffer */
+ WIDE_ACCUM_TO_BW
+ bitpointer -= FLAC__HALF_TEMP_BITS;
+ msbits -= FLAC__HALF_TEMP_BITS;
+ }
+ /* The remaining bits are zero, and the accumulator already is zero,
+ * so just subtract the number of bits from bitpointer. When storing,
+ * we can also just store 0 */
+ bitpointer -= msbits;
+ if(bitpointer <= FLAC__HALF_TEMP_BITS)
+ WIDE_ACCUM_TO_BW
+ }
+ else {
+ bitpointer -= msbits;
+ if(bitpointer <= FLAC__HALF_TEMP_BITS)
+ WIDE_ACCUM_TO_BW
+ }
+ /* The lsbs + stop bit always fit 32 bit, so this code mirrors the code above */
+ wide_accum |= (FLAC__bwtemp)(uval) << (bitpointer - lsbits);
+ bitpointer -= lsbits;
+ if(bitpointer <= FLAC__HALF_TEMP_BITS) {
+ /* A word is finished, copy the upper 32 bits of the wide_accum */
+ WIDE_ACCUM_TO_BW
+ }
+ }
+ vals++;
+ nvals--;
+ }
+ /* Now fixup remainder of wide_accum */
+#if (ENABLE_64_BIT_WORDS == 0)
+ if(bitpointer < FLAC__TEMP_BITS) {
+ bw->accum = wide_accum >> bitpointer;
+ bw->bits = FLAC__TEMP_BITS - bitpointer;
+ }
+#else
+ if(bitpointer < FLAC__TEMP_BITS) {
+ if(bw->bits == 0) {
+ bw->accum = wide_accum >> bitpointer;
+ bw->bits = FLAC__TEMP_BITS - bitpointer;
+ }
+ else if (bw->bits == FLAC__HALF_TEMP_BITS) {
+ bw->accum <<= FLAC__TEMP_BITS - bitpointer;
+ bw->accum |= (wide_accum >> bitpointer);
+ bw->bits = FLAC__HALF_TEMP_BITS + FLAC__TEMP_BITS - bitpointer;
+ }
+ else {
+ FLAC__ASSERT(0);
+ }
+ }
+#endif
+
+
+ return true;
+}
+
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitwriter_write_golomb_signed(FLAC__BitWriter *bw, int val, uint32_t parameter)
+{
+ uint32_t total_bits, msbs, uval;
+ uint32_t k;
+
+ FLAC__ASSERT(0 != bw);
+ FLAC__ASSERT(0 != bw->buffer);
+ FLAC__ASSERT(parameter > 0);
+
+ /* fold signed to uint32_t */
+ if(val < 0)
+ uval = (uint32_t)(((-(++val)) << 1) + 1);
+ else
+ uval = (uint32_t)(val << 1);
+
+ k = FLAC__bitmath_ilog2(parameter);
+ if(parameter == 1u<<k) {
+ uint32_t 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 {
+ uint32_t 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, uint32_t uval, uint32_t parameter)
+{
+ uint32_t total_bits, msbs;
+ uint32_t k;
+
+ FLAC__ASSERT(0 != bw);
+ FLAC__ASSERT(0 != bw->buffer);
+ FLAC__ASSERT(parameter > 0);
+
+ k = FLAC__bitmath_ilog2(parameter);
+ if(parameter == 1u<<k) {
+ uint32_t 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 {
+ uint32_t 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);
+
+ if((val & 0x80000000) != 0) /* this version only handles 31 bits */
+ return false;
+
+ if(val < 0x80) {
+ return FLAC__bitwriter_write_raw_uint32_nocheck(bw, val, 8);
+ }
+ else if(val < 0x800) {
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xC0 | (val>>6), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (val&0x3F), 8);
+ }
+ else if(val < 0x10000) {
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xE0 | (val>>12), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>6)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (val&0x3F), 8);
+ }
+ else if(val < 0x200000) {
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xF0 | (val>>18), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>12)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>6)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (val&0x3F), 8);
+ }
+ else if(val < 0x4000000) {
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xF8 | (val>>24), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>18)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>12)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>6)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (val&0x3F), 8);
+ }
+ else {
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xFC | (val>>30), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>24)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>18)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>12)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>6)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(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);
+
+ if((val & FLAC__U64L(0xFFFFFFF000000000)) != 0) /* this version only handles 36 bits */
+ return false;
+
+ if(val < 0x80) {
+ return FLAC__bitwriter_write_raw_uint32_nocheck(bw, (FLAC__uint32)val, 8);
+ }
+ else if(val < 0x800) {
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xC0 | (FLAC__uint32)(val>>6), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+ }
+ else if(val < 0x10000) {
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xE0 | (FLAC__uint32)(val>>12), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+ }
+ else if(val < 0x200000) {
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xF0 | (FLAC__uint32)(val>>18), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+ }
+ else if(val < 0x4000000) {
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xF8 | (FLAC__uint32)(val>>24), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+ }
+ else if(val < 0x80000000) {
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xFC | (FLAC__uint32)(val>>30), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>24)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+ }
+ else {
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xFE, 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>30)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>24)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32_nocheck(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;
+}
+
+/* These functions are declared inline in this file but are also callable as
+ * externs from elsewhere.
+ * According to the C99 spec, section 6.7.4, simply providing a function
+ * prototype in a header file without 'inline' and making the function inline
+ * in this file should be sufficient.
+ * Unfortunately, the Microsoft VS compiler doesn't pick them up externally. To
+ * fix that we add extern declarations here.
+ */
+extern FLAC__bool FLAC__bitwriter_write_zeroes(FLAC__BitWriter *bw, uint32_t bits);
+extern FLAC__bool FLAC__bitwriter_write_raw_uint32(FLAC__BitWriter *bw, FLAC__uint32 val, uint32_t bits);
+extern FLAC__bool FLAC__bitwriter_write_raw_int32(FLAC__BitWriter *bw, FLAC__int32 val, uint32_t bits);
+extern FLAC__bool FLAC__bitwriter_write_raw_uint64(FLAC__BitWriter *bw, FLAC__uint64 val, uint32_t bits);
+extern FLAC__bool FLAC__bitwriter_write_raw_int64(FLAC__BitWriter *bw, FLAC__int64 val, uint32_t bits);
+extern FLAC__bool FLAC__bitwriter_write_raw_uint32_little_endian(FLAC__BitWriter *bw, FLAC__uint32 val);
+extern FLAC__bool FLAC__bitwriter_write_byte_block(FLAC__BitWriter *bw, const FLAC__byte vals[], uint32_t nvals);
diff --git a/src/libFLAC/cpu.c b/src/libFLAC/cpu.c
new file mode 100644
index 0000000..d088e3c
--- /dev/null
+++ b/src/libFLAC/cpu.c
@@ -0,0 +1,255 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "private/cpu.h"
+#include "share/compat.h"
+#include <stdlib.h>
+#include <string.h>
+
+#if defined _MSC_VER
+#include <intrin.h> /* for __cpuid() and _xgetbv() */
+#elif defined __GNUC__ && defined HAVE_CPUID_H
+#include <cpuid.h> /* for __get_cpuid() and __get_cpuid_max() */
+#endif
+
+#ifndef NDEBUG
+#include <stdio.h>
+#define dfprintf fprintf
+#else
+/* This is bad practice, it should be a static void empty function */
+#define dfprintf(file, format, ...)
+#endif
+
+#if defined(HAVE_SYS_AUXV_H)
+#include <sys/auxv.h>
+#endif
+
+#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN && !defined FLAC__NO_ASM
+
+/* these are flags in EDX of CPUID AX=00000001 */
+static const uint32_t FLAC__CPUINFO_X86_CPUID_CMOV = 0x00008000;
+static const uint32_t FLAC__CPUINFO_X86_CPUID_MMX = 0x00800000;
+static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE = 0x02000000;
+static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE2 = 0x04000000;
+
+/* these are flags in ECX of CPUID AX=00000001 */
+static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE3 = 0x00000001;
+static const uint32_t FLAC__CPUINFO_X86_CPUID_SSSE3 = 0x00000200;
+static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE41 = 0x00080000;
+static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE42 = 0x00100000;
+static const uint32_t FLAC__CPUINFO_X86_CPUID_OSXSAVE = 0x08000000;
+static const uint32_t FLAC__CPUINFO_X86_CPUID_AVX = 0x10000000;
+static const uint32_t FLAC__CPUINFO_X86_CPUID_FMA = 0x00001000;
+
+/* these are flags in EBX of CPUID AX=00000007 */
+static const uint32_t FLAC__CPUINFO_X86_CPUID_AVX2 = 0x00000020;
+static const uint32_t FLAC__CPUINFO_X86_CPUID_BMI2 = 0x00000100;
+
+static uint32_t
+cpu_xgetbv_x86(void)
+{
+#if (defined _MSC_VER || defined __INTEL_COMPILER) && FLAC__AVX_SUPPORTED
+ return (uint32_t)_xgetbv(0);
+#elif defined __GNUC__
+ uint32_t lo, hi;
+ __asm__ volatile (".byte 0x0f, 0x01, 0xd0" : "=a"(lo), "=d"(hi) : "c" (0));
+ return lo;
+#else
+ return 0;
+#endif
+}
+
+static uint32_t
+cpu_have_cpuid(void)
+{
+#if defined FLAC__CPU_X86_64 || defined __i686__ || defined __SSE__ || (defined _M_IX86_FP && _M_IX86_FP > 0)
+ /* target CPU does have CPUID instruction */
+ return 1;
+#elif defined __GNUC__ && defined HAVE_CPUID_H
+ if (__get_cpuid_max(0, 0) != 0)
+ return 1;
+ else
+ return 0;
+#elif defined _MSC_VER
+ FLAC__uint32 flags1, flags2;
+ __asm {
+ pushfd
+ pushfd
+ pop eax
+ mov flags1, eax
+ xor eax, 0x200000
+ push eax
+ popfd
+ pushfd
+ pop eax
+ mov flags2, eax
+ popfd
+ }
+ if (((flags1^flags2) & 0x200000) != 0)
+ return 1;
+ else
+ return 0;
+#else
+ return 0;
+#endif
+}
+
+static void
+cpuinfo_x86(FLAC__uint32 level, FLAC__uint32 *eax, FLAC__uint32 *ebx, FLAC__uint32 *ecx, FLAC__uint32 *edx)
+{
+#if defined _MSC_VER
+ int cpuinfo[4];
+ int ext = level & 0x80000000;
+ __cpuid(cpuinfo, ext);
+ if ((uint32_t)cpuinfo[0] >= level) {
+#if FLAC__AVX_SUPPORTED
+ __cpuidex(cpuinfo, level, 0); /* for AVX2 detection */
+#else
+ __cpuid(cpuinfo, level); /* some old compilers don't support __cpuidex */
+#endif
+ *eax = cpuinfo[0]; *ebx = cpuinfo[1]; *ecx = cpuinfo[2]; *edx = cpuinfo[3];
+ return;
+ }
+#elif defined __GNUC__ && defined HAVE_CPUID_H
+ FLAC__uint32 ext = level & 0x80000000;
+ __cpuid(ext, *eax, *ebx, *ecx, *edx);
+ if (*eax >= level) {
+ __cpuid_count(level, 0, *eax, *ebx, *ecx, *edx);
+ return;
+ }
+#endif
+ *eax = *ebx = *ecx = *edx = 0;
+}
+
+#endif
+
+static void
+x86_cpu_info (FLAC__CPUInfo *info)
+{
+#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN && !defined FLAC__NO_ASM
+ FLAC__bool x86_osxsave = false;
+ FLAC__bool os_avx = false;
+ FLAC__uint32 flags_eax, flags_ebx, flags_ecx, flags_edx;
+
+ info->use_asm = true; /* we assume a minimum of 80386 */
+ if (!cpu_have_cpuid())
+ return;
+
+ cpuinfo_x86(0, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
+ info->x86.intel = (flags_ebx == 0x756E6547 && flags_edx == 0x49656E69 && flags_ecx == 0x6C65746E) ? true : false; /* GenuineIntel */
+ cpuinfo_x86(1, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
+
+ info->x86.cmov = (flags_edx & FLAC__CPUINFO_X86_CPUID_CMOV ) ? true : false;
+ info->x86.mmx = (flags_edx & FLAC__CPUINFO_X86_CPUID_MMX ) ? true : false;
+ info->x86.sse = (flags_edx & FLAC__CPUINFO_X86_CPUID_SSE ) ? true : false;
+ info->x86.sse2 = (flags_edx & FLAC__CPUINFO_X86_CPUID_SSE2 ) ? true : false;
+ info->x86.sse3 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSE3 ) ? true : false;
+ info->x86.ssse3 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSSE3) ? true : false;
+ info->x86.sse41 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSE41) ? true : false;
+ info->x86.sse42 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSE42) ? true : false;
+
+ if (FLAC__AVX_SUPPORTED) {
+ x86_osxsave = (flags_ecx & FLAC__CPUINFO_X86_CPUID_OSXSAVE) ? true : false;
+ info->x86.avx = (flags_ecx & FLAC__CPUINFO_X86_CPUID_AVX ) ? true : false;
+ info->x86.fma = (flags_ecx & FLAC__CPUINFO_X86_CPUID_FMA ) ? true : false;
+ cpuinfo_x86(7, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
+ info->x86.avx2 = (flags_ebx & FLAC__CPUINFO_X86_CPUID_AVX2 ) ? true : false;
+ info->x86.bmi2 = (flags_ebx & FLAC__CPUINFO_X86_CPUID_BMI2 ) ? true : false;
+ }
+
+#if defined FLAC__CPU_IA32
+ dfprintf(stderr, "CPU info (IA-32):\n");
+#else
+ dfprintf(stderr, "CPU info (x86-64):\n");
+#endif
+ dfprintf(stderr, " CMOV ....... %c\n", info->x86.cmov ? 'Y' : 'n');
+ dfprintf(stderr, " MMX ........ %c\n", info->x86.mmx ? 'Y' : 'n');
+ dfprintf(stderr, " SSE ........ %c\n", info->x86.sse ? 'Y' : 'n');
+ dfprintf(stderr, " SSE2 ....... %c\n", info->x86.sse2 ? 'Y' : 'n');
+ dfprintf(stderr, " SSE3 ....... %c\n", info->x86.sse3 ? 'Y' : 'n');
+ dfprintf(stderr, " SSSE3 ...... %c\n", info->x86.ssse3 ? 'Y' : 'n');
+ dfprintf(stderr, " SSE41 ...... %c\n", info->x86.sse41 ? 'Y' : 'n');
+ dfprintf(stderr, " SSE42 ...... %c\n", info->x86.sse42 ? 'Y' : 'n');
+
+ if (FLAC__AVX_SUPPORTED) {
+ dfprintf(stderr, " AVX ........ %c\n", info->x86.avx ? 'Y' : 'n');
+ dfprintf(stderr, " FMA ........ %c\n", info->x86.fma ? 'Y' : 'n');
+ dfprintf(stderr, " AVX2 ....... %c\n", info->x86.avx2 ? 'Y' : 'n');
+ dfprintf(stderr, " BMI2 ....... %c\n", info->x86.bmi2 ? 'Y' : 'n');
+ }
+
+ /*
+ * now have to check for OS support of AVX instructions
+ */
+ if (FLAC__AVX_SUPPORTED && info->x86.avx && x86_osxsave && (cpu_xgetbv_x86() & 0x6) == 0x6) {
+ os_avx = true;
+ }
+ if (os_avx) {
+ dfprintf(stderr, " AVX OS sup . %c\n", info->x86.avx ? 'Y' : 'n');
+ }
+ if (!os_avx) {
+ /* no OS AVX support */
+ info->x86.avx = false;
+ info->x86.avx2 = false;
+ info->x86.fma = false;
+ }
+#else
+ info->use_asm = false;
+#endif
+}
+
+void FLAC__cpu_info (FLAC__CPUInfo *info)
+{
+ memset(info, 0, sizeof(*info));
+
+#ifdef FLAC__CPU_IA32
+ info->type = FLAC__CPUINFO_TYPE_IA32;
+#elif defined FLAC__CPU_X86_64
+ info->type = FLAC__CPUINFO_TYPE_X86_64;
+#else
+ info->type = FLAC__CPUINFO_TYPE_UNKNOWN;
+#endif
+
+ switch (info->type) {
+ case FLAC__CPUINFO_TYPE_IA32: /* fallthrough */
+ case FLAC__CPUINFO_TYPE_X86_64:
+ x86_cpu_info (info);
+ break;
+ default:
+ info->use_asm = false;
+ break;
+ }
+}
diff --git a/src/libFLAC/crc.c b/src/libFLAC/crc.c
new file mode 100644
index 0000000..9e488e9
--- /dev/null
+++ b/src/libFLAC/crc.c
@@ -0,0 +1,436 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef 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__uint8 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 */
+
+FLAC__uint16 const FLAC__crc16_table[8][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 },
+
+ { 0x0000, 0x8603, 0x8c03, 0x0a00, 0x9803, 0x1e00, 0x1400, 0x9203,
+ 0xb003, 0x3600, 0x3c00, 0xba03, 0x2800, 0xae03, 0xa403, 0x2200,
+ 0xe003, 0x6600, 0x6c00, 0xea03, 0x7800, 0xfe03, 0xf403, 0x7200,
+ 0x5000, 0xd603, 0xdc03, 0x5a00, 0xc803, 0x4e00, 0x4400, 0xc203,
+ 0x4003, 0xc600, 0xcc00, 0x4a03, 0xd800, 0x5e03, 0x5403, 0xd200,
+ 0xf000, 0x7603, 0x7c03, 0xfa00, 0x6803, 0xee00, 0xe400, 0x6203,
+ 0xa000, 0x2603, 0x2c03, 0xaa00, 0x3803, 0xbe00, 0xb400, 0x3203,
+ 0x1003, 0x9600, 0x9c00, 0x1a03, 0x8800, 0x0e03, 0x0403, 0x8200,
+ 0x8006, 0x0605, 0x0c05, 0x8a06, 0x1805, 0x9e06, 0x9406, 0x1205,
+ 0x3005, 0xb606, 0xbc06, 0x3a05, 0xa806, 0x2e05, 0x2405, 0xa206,
+ 0x6005, 0xe606, 0xec06, 0x6a05, 0xf806, 0x7e05, 0x7405, 0xf206,
+ 0xd006, 0x5605, 0x5c05, 0xda06, 0x4805, 0xce06, 0xc406, 0x4205,
+ 0xc005, 0x4606, 0x4c06, 0xca05, 0x5806, 0xde05, 0xd405, 0x5206,
+ 0x7006, 0xf605, 0xfc05, 0x7a06, 0xe805, 0x6e06, 0x6406, 0xe205,
+ 0x2006, 0xa605, 0xac05, 0x2a06, 0xb805, 0x3e06, 0x3406, 0xb205,
+ 0x9005, 0x1606, 0x1c06, 0x9a05, 0x0806, 0x8e05, 0x8405, 0x0206,
+ 0x8009, 0x060a, 0x0c0a, 0x8a09, 0x180a, 0x9e09, 0x9409, 0x120a,
+ 0x300a, 0xb609, 0xbc09, 0x3a0a, 0xa809, 0x2e0a, 0x240a, 0xa209,
+ 0x600a, 0xe609, 0xec09, 0x6a0a, 0xf809, 0x7e0a, 0x740a, 0xf209,
+ 0xd009, 0x560a, 0x5c0a, 0xda09, 0x480a, 0xce09, 0xc409, 0x420a,
+ 0xc00a, 0x4609, 0x4c09, 0xca0a, 0x5809, 0xde0a, 0xd40a, 0x5209,
+ 0x7009, 0xf60a, 0xfc0a, 0x7a09, 0xe80a, 0x6e09, 0x6409, 0xe20a,
+ 0x2009, 0xa60a, 0xac0a, 0x2a09, 0xb80a, 0x3e09, 0x3409, 0xb20a,
+ 0x900a, 0x1609, 0x1c09, 0x9a0a, 0x0809, 0x8e0a, 0x840a, 0x0209,
+ 0x000f, 0x860c, 0x8c0c, 0x0a0f, 0x980c, 0x1e0f, 0x140f, 0x920c,
+ 0xb00c, 0x360f, 0x3c0f, 0xba0c, 0x280f, 0xae0c, 0xa40c, 0x220f,
+ 0xe00c, 0x660f, 0x6c0f, 0xea0c, 0x780f, 0xfe0c, 0xf40c, 0x720f,
+ 0x500f, 0xd60c, 0xdc0c, 0x5a0f, 0xc80c, 0x4e0f, 0x440f, 0xc20c,
+ 0x400c, 0xc60f, 0xcc0f, 0x4a0c, 0xd80f, 0x5e0c, 0x540c, 0xd20f,
+ 0xf00f, 0x760c, 0x7c0c, 0xfa0f, 0x680c, 0xee0f, 0xe40f, 0x620c,
+ 0xa00f, 0x260c, 0x2c0c, 0xaa0f, 0x380c, 0xbe0f, 0xb40f, 0x320c,
+ 0x100c, 0x960f, 0x9c0f, 0x1a0c, 0x880f, 0x0e0c, 0x040c, 0x820f },
+
+ { 0x0000, 0x8017, 0x802b, 0x003c, 0x8053, 0x0044, 0x0078, 0x806f,
+ 0x80a3, 0x00b4, 0x0088, 0x809f, 0x00f0, 0x80e7, 0x80db, 0x00cc,
+ 0x8143, 0x0154, 0x0168, 0x817f, 0x0110, 0x8107, 0x813b, 0x012c,
+ 0x01e0, 0x81f7, 0x81cb, 0x01dc, 0x81b3, 0x01a4, 0x0198, 0x818f,
+ 0x8283, 0x0294, 0x02a8, 0x82bf, 0x02d0, 0x82c7, 0x82fb, 0x02ec,
+ 0x0220, 0x8237, 0x820b, 0x021c, 0x8273, 0x0264, 0x0258, 0x824f,
+ 0x03c0, 0x83d7, 0x83eb, 0x03fc, 0x8393, 0x0384, 0x03b8, 0x83af,
+ 0x8363, 0x0374, 0x0348, 0x835f, 0x0330, 0x8327, 0x831b, 0x030c,
+ 0x8503, 0x0514, 0x0528, 0x853f, 0x0550, 0x8547, 0x857b, 0x056c,
+ 0x05a0, 0x85b7, 0x858b, 0x059c, 0x85f3, 0x05e4, 0x05d8, 0x85cf,
+ 0x0440, 0x8457, 0x846b, 0x047c, 0x8413, 0x0404, 0x0438, 0x842f,
+ 0x84e3, 0x04f4, 0x04c8, 0x84df, 0x04b0, 0x84a7, 0x849b, 0x048c,
+ 0x0780, 0x8797, 0x87ab, 0x07bc, 0x87d3, 0x07c4, 0x07f8, 0x87ef,
+ 0x8723, 0x0734, 0x0708, 0x871f, 0x0770, 0x8767, 0x875b, 0x074c,
+ 0x86c3, 0x06d4, 0x06e8, 0x86ff, 0x0690, 0x8687, 0x86bb, 0x06ac,
+ 0x0660, 0x8677, 0x864b, 0x065c, 0x8633, 0x0624, 0x0618, 0x860f,
+ 0x8a03, 0x0a14, 0x0a28, 0x8a3f, 0x0a50, 0x8a47, 0x8a7b, 0x0a6c,
+ 0x0aa0, 0x8ab7, 0x8a8b, 0x0a9c, 0x8af3, 0x0ae4, 0x0ad8, 0x8acf,
+ 0x0b40, 0x8b57, 0x8b6b, 0x0b7c, 0x8b13, 0x0b04, 0x0b38, 0x8b2f,
+ 0x8be3, 0x0bf4, 0x0bc8, 0x8bdf, 0x0bb0, 0x8ba7, 0x8b9b, 0x0b8c,
+ 0x0880, 0x8897, 0x88ab, 0x08bc, 0x88d3, 0x08c4, 0x08f8, 0x88ef,
+ 0x8823, 0x0834, 0x0808, 0x881f, 0x0870, 0x8867, 0x885b, 0x084c,
+ 0x89c3, 0x09d4, 0x09e8, 0x89ff, 0x0990, 0x8987, 0x89bb, 0x09ac,
+ 0x0960, 0x8977, 0x894b, 0x095c, 0x8933, 0x0924, 0x0918, 0x890f,
+ 0x0f00, 0x8f17, 0x8f2b, 0x0f3c, 0x8f53, 0x0f44, 0x0f78, 0x8f6f,
+ 0x8fa3, 0x0fb4, 0x0f88, 0x8f9f, 0x0ff0, 0x8fe7, 0x8fdb, 0x0fcc,
+ 0x8e43, 0x0e54, 0x0e68, 0x8e7f, 0x0e10, 0x8e07, 0x8e3b, 0x0e2c,
+ 0x0ee0, 0x8ef7, 0x8ecb, 0x0edc, 0x8eb3, 0x0ea4, 0x0e98, 0x8e8f,
+ 0x8d83, 0x0d94, 0x0da8, 0x8dbf, 0x0dd0, 0x8dc7, 0x8dfb, 0x0dec,
+ 0x0d20, 0x8d37, 0x8d0b, 0x0d1c, 0x8d73, 0x0d64, 0x0d58, 0x8d4f,
+ 0x0cc0, 0x8cd7, 0x8ceb, 0x0cfc, 0x8c93, 0x0c84, 0x0cb8, 0x8caf,
+ 0x8c63, 0x0c74, 0x0c48, 0x8c5f, 0x0c30, 0x8c27, 0x8c1b, 0x0c0c },
+
+ { 0x0000, 0x9403, 0xa803, 0x3c00, 0xd003, 0x4400, 0x7800, 0xec03,
+ 0x2003, 0xb400, 0x8800, 0x1c03, 0xf000, 0x6403, 0x5803, 0xcc00,
+ 0x4006, 0xd405, 0xe805, 0x7c06, 0x9005, 0x0406, 0x3806, 0xac05,
+ 0x6005, 0xf406, 0xc806, 0x5c05, 0xb006, 0x2405, 0x1805, 0x8c06,
+ 0x800c, 0x140f, 0x280f, 0xbc0c, 0x500f, 0xc40c, 0xf80c, 0x6c0f,
+ 0xa00f, 0x340c, 0x080c, 0x9c0f, 0x700c, 0xe40f, 0xd80f, 0x4c0c,
+ 0xc00a, 0x5409, 0x6809, 0xfc0a, 0x1009, 0x840a, 0xb80a, 0x2c09,
+ 0xe009, 0x740a, 0x480a, 0xdc09, 0x300a, 0xa409, 0x9809, 0x0c0a,
+ 0x801d, 0x141e, 0x281e, 0xbc1d, 0x501e, 0xc41d, 0xf81d, 0x6c1e,
+ 0xa01e, 0x341d, 0x081d, 0x9c1e, 0x701d, 0xe41e, 0xd81e, 0x4c1d,
+ 0xc01b, 0x5418, 0x6818, 0xfc1b, 0x1018, 0x841b, 0xb81b, 0x2c18,
+ 0xe018, 0x741b, 0x481b, 0xdc18, 0x301b, 0xa418, 0x9818, 0x0c1b,
+ 0x0011, 0x9412, 0xa812, 0x3c11, 0xd012, 0x4411, 0x7811, 0xec12,
+ 0x2012, 0xb411, 0x8811, 0x1c12, 0xf011, 0x6412, 0x5812, 0xcc11,
+ 0x4017, 0xd414, 0xe814, 0x7c17, 0x9014, 0x0417, 0x3817, 0xac14,
+ 0x6014, 0xf417, 0xc817, 0x5c14, 0xb017, 0x2414, 0x1814, 0x8c17,
+ 0x803f, 0x143c, 0x283c, 0xbc3f, 0x503c, 0xc43f, 0xf83f, 0x6c3c,
+ 0xa03c, 0x343f, 0x083f, 0x9c3c, 0x703f, 0xe43c, 0xd83c, 0x4c3f,
+ 0xc039, 0x543a, 0x683a, 0xfc39, 0x103a, 0x8439, 0xb839, 0x2c3a,
+ 0xe03a, 0x7439, 0x4839, 0xdc3a, 0x3039, 0xa43a, 0x983a, 0x0c39,
+ 0x0033, 0x9430, 0xa830, 0x3c33, 0xd030, 0x4433, 0x7833, 0xec30,
+ 0x2030, 0xb433, 0x8833, 0x1c30, 0xf033, 0x6430, 0x5830, 0xcc33,
+ 0x4035, 0xd436, 0xe836, 0x7c35, 0x9036, 0x0435, 0x3835, 0xac36,
+ 0x6036, 0xf435, 0xc835, 0x5c36, 0xb035, 0x2436, 0x1836, 0x8c35,
+ 0x0022, 0x9421, 0xa821, 0x3c22, 0xd021, 0x4422, 0x7822, 0xec21,
+ 0x2021, 0xb422, 0x8822, 0x1c21, 0xf022, 0x6421, 0x5821, 0xcc22,
+ 0x4024, 0xd427, 0xe827, 0x7c24, 0x9027, 0x0424, 0x3824, 0xac27,
+ 0x6027, 0xf424, 0xc824, 0x5c27, 0xb024, 0x2427, 0x1827, 0x8c24,
+ 0x802e, 0x142d, 0x282d, 0xbc2e, 0x502d, 0xc42e, 0xf82e, 0x6c2d,
+ 0xa02d, 0x342e, 0x082e, 0x9c2d, 0x702e, 0xe42d, 0xd82d, 0x4c2e,
+ 0xc028, 0x542b, 0x682b, 0xfc28, 0x102b, 0x8428, 0xb828, 0x2c2b,
+ 0xe02b, 0x7428, 0x4828, 0xdc2b, 0x3028, 0xa42b, 0x982b, 0x0c28 },
+
+ { 0x0000, 0x807b, 0x80f3, 0x0088, 0x81e3, 0x0198, 0x0110, 0x816b,
+ 0x83c3, 0x03b8, 0x0330, 0x834b, 0x0220, 0x825b, 0x82d3, 0x02a8,
+ 0x8783, 0x07f8, 0x0770, 0x870b, 0x0660, 0x861b, 0x8693, 0x06e8,
+ 0x0440, 0x843b, 0x84b3, 0x04c8, 0x85a3, 0x05d8, 0x0550, 0x852b,
+ 0x8f03, 0x0f78, 0x0ff0, 0x8f8b, 0x0ee0, 0x8e9b, 0x8e13, 0x0e68,
+ 0x0cc0, 0x8cbb, 0x8c33, 0x0c48, 0x8d23, 0x0d58, 0x0dd0, 0x8dab,
+ 0x0880, 0x88fb, 0x8873, 0x0808, 0x8963, 0x0918, 0x0990, 0x89eb,
+ 0x8b43, 0x0b38, 0x0bb0, 0x8bcb, 0x0aa0, 0x8adb, 0x8a53, 0x0a28,
+ 0x9e03, 0x1e78, 0x1ef0, 0x9e8b, 0x1fe0, 0x9f9b, 0x9f13, 0x1f68,
+ 0x1dc0, 0x9dbb, 0x9d33, 0x1d48, 0x9c23, 0x1c58, 0x1cd0, 0x9cab,
+ 0x1980, 0x99fb, 0x9973, 0x1908, 0x9863, 0x1818, 0x1890, 0x98eb,
+ 0x9a43, 0x1a38, 0x1ab0, 0x9acb, 0x1ba0, 0x9bdb, 0x9b53, 0x1b28,
+ 0x1100, 0x917b, 0x91f3, 0x1188, 0x90e3, 0x1098, 0x1010, 0x906b,
+ 0x92c3, 0x12b8, 0x1230, 0x924b, 0x1320, 0x935b, 0x93d3, 0x13a8,
+ 0x9683, 0x16f8, 0x1670, 0x960b, 0x1760, 0x971b, 0x9793, 0x17e8,
+ 0x1540, 0x953b, 0x95b3, 0x15c8, 0x94a3, 0x14d8, 0x1450, 0x942b,
+ 0xbc03, 0x3c78, 0x3cf0, 0xbc8b, 0x3de0, 0xbd9b, 0xbd13, 0x3d68,
+ 0x3fc0, 0xbfbb, 0xbf33, 0x3f48, 0xbe23, 0x3e58, 0x3ed0, 0xbeab,
+ 0x3b80, 0xbbfb, 0xbb73, 0x3b08, 0xba63, 0x3a18, 0x3a90, 0xbaeb,
+ 0xb843, 0x3838, 0x38b0, 0xb8cb, 0x39a0, 0xb9db, 0xb953, 0x3928,
+ 0x3300, 0xb37b, 0xb3f3, 0x3388, 0xb2e3, 0x3298, 0x3210, 0xb26b,
+ 0xb0c3, 0x30b8, 0x3030, 0xb04b, 0x3120, 0xb15b, 0xb1d3, 0x31a8,
+ 0xb483, 0x34f8, 0x3470, 0xb40b, 0x3560, 0xb51b, 0xb593, 0x35e8,
+ 0x3740, 0xb73b, 0xb7b3, 0x37c8, 0xb6a3, 0x36d8, 0x3650, 0xb62b,
+ 0x2200, 0xa27b, 0xa2f3, 0x2288, 0xa3e3, 0x2398, 0x2310, 0xa36b,
+ 0xa1c3, 0x21b8, 0x2130, 0xa14b, 0x2020, 0xa05b, 0xa0d3, 0x20a8,
+ 0xa583, 0x25f8, 0x2570, 0xa50b, 0x2460, 0xa41b, 0xa493, 0x24e8,
+ 0x2640, 0xa63b, 0xa6b3, 0x26c8, 0xa7a3, 0x27d8, 0x2750, 0xa72b,
+ 0xad03, 0x2d78, 0x2df0, 0xad8b, 0x2ce0, 0xac9b, 0xac13, 0x2c68,
+ 0x2ec0, 0xaebb, 0xae33, 0x2e48, 0xaf23, 0x2f58, 0x2fd0, 0xafab,
+ 0x2a80, 0xaafb, 0xaa73, 0x2a08, 0xab63, 0x2b18, 0x2b90, 0xabeb,
+ 0xa943, 0x2938, 0x29b0, 0xa9cb, 0x28a0, 0xa8db, 0xa853, 0x2828 },
+
+ { 0x0000, 0xf803, 0x7003, 0x8800, 0xe006, 0x1805, 0x9005, 0x6806,
+ 0x4009, 0xb80a, 0x300a, 0xc809, 0xa00f, 0x580c, 0xd00c, 0x280f,
+ 0x8012, 0x7811, 0xf011, 0x0812, 0x6014, 0x9817, 0x1017, 0xe814,
+ 0xc01b, 0x3818, 0xb018, 0x481b, 0x201d, 0xd81e, 0x501e, 0xa81d,
+ 0x8021, 0x7822, 0xf022, 0x0821, 0x6027, 0x9824, 0x1024, 0xe827,
+ 0xc028, 0x382b, 0xb02b, 0x4828, 0x202e, 0xd82d, 0x502d, 0xa82e,
+ 0x0033, 0xf830, 0x7030, 0x8833, 0xe035, 0x1836, 0x9036, 0x6835,
+ 0x403a, 0xb839, 0x3039, 0xc83a, 0xa03c, 0x583f, 0xd03f, 0x283c,
+ 0x8047, 0x7844, 0xf044, 0x0847, 0x6041, 0x9842, 0x1042, 0xe841,
+ 0xc04e, 0x384d, 0xb04d, 0x484e, 0x2048, 0xd84b, 0x504b, 0xa848,
+ 0x0055, 0xf856, 0x7056, 0x8855, 0xe053, 0x1850, 0x9050, 0x6853,
+ 0x405c, 0xb85f, 0x305f, 0xc85c, 0xa05a, 0x5859, 0xd059, 0x285a,
+ 0x0066, 0xf865, 0x7065, 0x8866, 0xe060, 0x1863, 0x9063, 0x6860,
+ 0x406f, 0xb86c, 0x306c, 0xc86f, 0xa069, 0x586a, 0xd06a, 0x2869,
+ 0x8074, 0x7877, 0xf077, 0x0874, 0x6072, 0x9871, 0x1071, 0xe872,
+ 0xc07d, 0x387e, 0xb07e, 0x487d, 0x207b, 0xd878, 0x5078, 0xa87b,
+ 0x808b, 0x7888, 0xf088, 0x088b, 0x608d, 0x988e, 0x108e, 0xe88d,
+ 0xc082, 0x3881, 0xb081, 0x4882, 0x2084, 0xd887, 0x5087, 0xa884,
+ 0x0099, 0xf89a, 0x709a, 0x8899, 0xe09f, 0x189c, 0x909c, 0x689f,
+ 0x4090, 0xb893, 0x3093, 0xc890, 0xa096, 0x5895, 0xd095, 0x2896,
+ 0x00aa, 0xf8a9, 0x70a9, 0x88aa, 0xe0ac, 0x18af, 0x90af, 0x68ac,
+ 0x40a3, 0xb8a0, 0x30a0, 0xc8a3, 0xa0a5, 0x58a6, 0xd0a6, 0x28a5,
+ 0x80b8, 0x78bb, 0xf0bb, 0x08b8, 0x60be, 0x98bd, 0x10bd, 0xe8be,
+ 0xc0b1, 0x38b2, 0xb0b2, 0x48b1, 0x20b7, 0xd8b4, 0x50b4, 0xa8b7,
+ 0x00cc, 0xf8cf, 0x70cf, 0x88cc, 0xe0ca, 0x18c9, 0x90c9, 0x68ca,
+ 0x40c5, 0xb8c6, 0x30c6, 0xc8c5, 0xa0c3, 0x58c0, 0xd0c0, 0x28c3,
+ 0x80de, 0x78dd, 0xf0dd, 0x08de, 0x60d8, 0x98db, 0x10db, 0xe8d8,
+ 0xc0d7, 0x38d4, 0xb0d4, 0x48d7, 0x20d1, 0xd8d2, 0x50d2, 0xa8d1,
+ 0x80ed, 0x78ee, 0xf0ee, 0x08ed, 0x60eb, 0x98e8, 0x10e8, 0xe8eb,
+ 0xc0e4, 0x38e7, 0xb0e7, 0x48e4, 0x20e2, 0xd8e1, 0x50e1, 0xa8e2,
+ 0x00ff, 0xf8fc, 0x70fc, 0x88ff, 0xe0f9, 0x18fa, 0x90fa, 0x68f9,
+ 0x40f6, 0xb8f5, 0x30f5, 0xc8f6, 0xa0f0, 0x58f3, 0xd0f3, 0x28f0 },
+
+ { 0x0000, 0x8113, 0x8223, 0x0330, 0x8443, 0x0550, 0x0660, 0x8773,
+ 0x8883, 0x0990, 0x0aa0, 0x8bb3, 0x0cc0, 0x8dd3, 0x8ee3, 0x0ff0,
+ 0x9103, 0x1010, 0x1320, 0x9233, 0x1540, 0x9453, 0x9763, 0x1670,
+ 0x1980, 0x9893, 0x9ba3, 0x1ab0, 0x9dc3, 0x1cd0, 0x1fe0, 0x9ef3,
+ 0xa203, 0x2310, 0x2020, 0xa133, 0x2640, 0xa753, 0xa463, 0x2570,
+ 0x2a80, 0xab93, 0xa8a3, 0x29b0, 0xaec3, 0x2fd0, 0x2ce0, 0xadf3,
+ 0x3300, 0xb213, 0xb123, 0x3030, 0xb743, 0x3650, 0x3560, 0xb473,
+ 0xbb83, 0x3a90, 0x39a0, 0xb8b3, 0x3fc0, 0xbed3, 0xbde3, 0x3cf0,
+ 0xc403, 0x4510, 0x4620, 0xc733, 0x4040, 0xc153, 0xc263, 0x4370,
+ 0x4c80, 0xcd93, 0xcea3, 0x4fb0, 0xc8c3, 0x49d0, 0x4ae0, 0xcbf3,
+ 0x5500, 0xd413, 0xd723, 0x5630, 0xd143, 0x5050, 0x5360, 0xd273,
+ 0xdd83, 0x5c90, 0x5fa0, 0xdeb3, 0x59c0, 0xd8d3, 0xdbe3, 0x5af0,
+ 0x6600, 0xe713, 0xe423, 0x6530, 0xe243, 0x6350, 0x6060, 0xe173,
+ 0xee83, 0x6f90, 0x6ca0, 0xedb3, 0x6ac0, 0xebd3, 0xe8e3, 0x69f0,
+ 0xf703, 0x7610, 0x7520, 0xf433, 0x7340, 0xf253, 0xf163, 0x7070,
+ 0x7f80, 0xfe93, 0xfda3, 0x7cb0, 0xfbc3, 0x7ad0, 0x79e0, 0xf8f3,
+ 0x0803, 0x8910, 0x8a20, 0x0b33, 0x8c40, 0x0d53, 0x0e63, 0x8f70,
+ 0x8080, 0x0193, 0x02a3, 0x83b0, 0x04c3, 0x85d0, 0x86e0, 0x07f3,
+ 0x9900, 0x1813, 0x1b23, 0x9a30, 0x1d43, 0x9c50, 0x9f60, 0x1e73,
+ 0x1183, 0x9090, 0x93a0, 0x12b3, 0x95c0, 0x14d3, 0x17e3, 0x96f0,
+ 0xaa00, 0x2b13, 0x2823, 0xa930, 0x2e43, 0xaf50, 0xac60, 0x2d73,
+ 0x2283, 0xa390, 0xa0a0, 0x21b3, 0xa6c0, 0x27d3, 0x24e3, 0xa5f0,
+ 0x3b03, 0xba10, 0xb920, 0x3833, 0xbf40, 0x3e53, 0x3d63, 0xbc70,
+ 0xb380, 0x3293, 0x31a3, 0xb0b0, 0x37c3, 0xb6d0, 0xb5e0, 0x34f3,
+ 0xcc00, 0x4d13, 0x4e23, 0xcf30, 0x4843, 0xc950, 0xca60, 0x4b73,
+ 0x4483, 0xc590, 0xc6a0, 0x47b3, 0xc0c0, 0x41d3, 0x42e3, 0xc3f0,
+ 0x5d03, 0xdc10, 0xdf20, 0x5e33, 0xd940, 0x5853, 0x5b63, 0xda70,
+ 0xd580, 0x5493, 0x57a3, 0xd6b0, 0x51c3, 0xd0d0, 0xd3e0, 0x52f3,
+ 0x6e03, 0xef10, 0xec20, 0x6d33, 0xea40, 0x6b53, 0x6863, 0xe970,
+ 0xe680, 0x6793, 0x64a3, 0xe5b0, 0x62c3, 0xe3d0, 0xe0e0, 0x61f3,
+ 0xff00, 0x7e13, 0x7d23, 0xfc30, 0x7b43, 0xfa50, 0xf960, 0x7873,
+ 0x7783, 0xf690, 0xf5a0, 0x74b3, 0xf3c0, 0x72d3, 0x71e3, 0xf0f0 },
+
+ { 0x0000, 0x1006, 0x200c, 0x300a, 0x4018, 0x501e, 0x6014, 0x7012,
+ 0x8030, 0x9036, 0xa03c, 0xb03a, 0xc028, 0xd02e, 0xe024, 0xf022,
+ 0x8065, 0x9063, 0xa069, 0xb06f, 0xc07d, 0xd07b, 0xe071, 0xf077,
+ 0x0055, 0x1053, 0x2059, 0x305f, 0x404d, 0x504b, 0x6041, 0x7047,
+ 0x80cf, 0x90c9, 0xa0c3, 0xb0c5, 0xc0d7, 0xd0d1, 0xe0db, 0xf0dd,
+ 0x00ff, 0x10f9, 0x20f3, 0x30f5, 0x40e7, 0x50e1, 0x60eb, 0x70ed,
+ 0x00aa, 0x10ac, 0x20a6, 0x30a0, 0x40b2, 0x50b4, 0x60be, 0x70b8,
+ 0x809a, 0x909c, 0xa096, 0xb090, 0xc082, 0xd084, 0xe08e, 0xf088,
+ 0x819b, 0x919d, 0xa197, 0xb191, 0xc183, 0xd185, 0xe18f, 0xf189,
+ 0x01ab, 0x11ad, 0x21a7, 0x31a1, 0x41b3, 0x51b5, 0x61bf, 0x71b9,
+ 0x01fe, 0x11f8, 0x21f2, 0x31f4, 0x41e6, 0x51e0, 0x61ea, 0x71ec,
+ 0x81ce, 0x91c8, 0xa1c2, 0xb1c4, 0xc1d6, 0xd1d0, 0xe1da, 0xf1dc,
+ 0x0154, 0x1152, 0x2158, 0x315e, 0x414c, 0x514a, 0x6140, 0x7146,
+ 0x8164, 0x9162, 0xa168, 0xb16e, 0xc17c, 0xd17a, 0xe170, 0xf176,
+ 0x8131, 0x9137, 0xa13d, 0xb13b, 0xc129, 0xd12f, 0xe125, 0xf123,
+ 0x0101, 0x1107, 0x210d, 0x310b, 0x4119, 0x511f, 0x6115, 0x7113,
+ 0x8333, 0x9335, 0xa33f, 0xb339, 0xc32b, 0xd32d, 0xe327, 0xf321,
+ 0x0303, 0x1305, 0x230f, 0x3309, 0x431b, 0x531d, 0x6317, 0x7311,
+ 0x0356, 0x1350, 0x235a, 0x335c, 0x434e, 0x5348, 0x6342, 0x7344,
+ 0x8366, 0x9360, 0xa36a, 0xb36c, 0xc37e, 0xd378, 0xe372, 0xf374,
+ 0x03fc, 0x13fa, 0x23f0, 0x33f6, 0x43e4, 0x53e2, 0x63e8, 0x73ee,
+ 0x83cc, 0x93ca, 0xa3c0, 0xb3c6, 0xc3d4, 0xd3d2, 0xe3d8, 0xf3de,
+ 0x8399, 0x939f, 0xa395, 0xb393, 0xc381, 0xd387, 0xe38d, 0xf38b,
+ 0x03a9, 0x13af, 0x23a5, 0x33a3, 0x43b1, 0x53b7, 0x63bd, 0x73bb,
+ 0x02a8, 0x12ae, 0x22a4, 0x32a2, 0x42b0, 0x52b6, 0x62bc, 0x72ba,
+ 0x8298, 0x929e, 0xa294, 0xb292, 0xc280, 0xd286, 0xe28c, 0xf28a,
+ 0x82cd, 0x92cb, 0xa2c1, 0xb2c7, 0xc2d5, 0xd2d3, 0xe2d9, 0xf2df,
+ 0x02fd, 0x12fb, 0x22f1, 0x32f7, 0x42e5, 0x52e3, 0x62e9, 0x72ef,
+ 0x8267, 0x9261, 0xa26b, 0xb26d, 0xc27f, 0xd279, 0xe273, 0xf275,
+ 0x0257, 0x1251, 0x225b, 0x325d, 0x424f, 0x5249, 0x6243, 0x7245,
+ 0x0202, 0x1204, 0x220e, 0x3208, 0x421a, 0x521c, 0x6216, 0x7210,
+ 0x8232, 0x9234, 0xa23e, 0xb238, 0xc22a, 0xd22c, 0xe226, 0xf220 }
+};
+
+#if 0
+void FLAC__crc16_init_table(void)
+{
+ int i, j;
+ FLAC__uint16 polynomial, crc;
+ polynomial = 0x8005;
+
+ for(i = 0; i <= 0xFF; i++){
+ crc = i << 8;
+
+ for(j = 0; j < 8; j++)
+ crc = (crc << 1) ^ (crc & (1 << 15) ? polynomial : 0);
+
+ FLAC__crc16_table[0][i] = crc;
+ }
+
+ for(i = 0; i <= 0xFF; i++)
+ for(j = 1; j < 8; j++)
+ FLAC__crc16_table[j][i] = FLAC__crc16_table[0][FLAC__crc16_table[j - 1][i] >> 8] ^ (FLAC__crc16_table[j - 1][i] << 8);
+}
+#endif
+
+FLAC__uint8 FLAC__crc8(const FLAC__byte *data, uint32_t len)
+{
+ FLAC__uint8 crc = 0;
+
+ while(len--)
+ crc = FLAC__crc8_table[crc ^ *data++];
+
+ return crc;
+}
+
+FLAC__uint16 FLAC__crc16(const FLAC__byte *data, uint32_t len)
+{
+ FLAC__uint16 crc = 0;
+
+ while(len >= 8){
+ crc ^= data[0] << 8 | data[1];
+
+ crc = FLAC__crc16_table[7][crc >> 8] ^ FLAC__crc16_table[6][crc & 0xFF] ^
+ FLAC__crc16_table[5][data[2] ] ^ FLAC__crc16_table[4][data[3] ] ^
+ FLAC__crc16_table[3][data[4] ] ^ FLAC__crc16_table[2][data[5] ] ^
+ FLAC__crc16_table[1][data[6] ] ^ FLAC__crc16_table[0][data[7] ];
+
+ data += 8;
+ len -= 8;
+ }
+
+ while(len--)
+ crc = (crc<<8) ^ FLAC__crc16_table[0][(crc>>8) ^ *data++];
+
+ return crc;
+}
+
+FLAC__uint16 FLAC__crc16_update_words32(const FLAC__uint32 *words, uint32_t len, FLAC__uint16 crc)
+{
+ while (len >= 2) {
+ crc ^= words[0] >> 16;
+
+ crc = FLAC__crc16_table[7][crc >> 8 ] ^ FLAC__crc16_table[6][crc & 0xFF ] ^
+ FLAC__crc16_table[5][(words[0] >> 8) & 0xFF] ^ FLAC__crc16_table[4][ words[0] & 0xFF] ^
+ FLAC__crc16_table[3][ words[1] >> 24 ] ^ FLAC__crc16_table[2][(words[1] >> 16) & 0xFF] ^
+ FLAC__crc16_table[1][(words[1] >> 8) & 0xFF] ^ FLAC__crc16_table[0][ words[1] & 0xFF];
+
+ words += 2;
+ len -= 2;
+ }
+
+ if (len) {
+ crc ^= words[0] >> 16;
+
+ crc = FLAC__crc16_table[3][crc >> 8 ] ^ FLAC__crc16_table[2][crc & 0xFF ] ^
+ FLAC__crc16_table[1][(words[0] >> 8) & 0xFF] ^ FLAC__crc16_table[0][words[0] & 0xFF];
+ }
+
+ return crc;
+}
+
+FLAC__uint16 FLAC__crc16_update_words64(const FLAC__uint64 *words, uint32_t len, FLAC__uint16 crc)
+{
+ while (len--) {
+ crc ^= words[0] >> 48;
+
+ crc = FLAC__crc16_table[7][crc >> 8 ] ^ FLAC__crc16_table[6][crc & 0xFF ] ^
+ FLAC__crc16_table[5][(words[0] >> 40) & 0xFF] ^ FLAC__crc16_table[4][(words[0] >> 32) & 0xFF] ^
+ FLAC__crc16_table[3][(words[0] >> 24) & 0xFF] ^ FLAC__crc16_table[2][(words[0] >> 16) & 0xFF] ^
+ FLAC__crc16_table[1][(words[0] >> 8) & 0xFF] ^ FLAC__crc16_table[0][ words[0] & 0xFF];
+
+ words++;
+ }
+
+ return crc;
+}
diff --git a/src/libFLAC/deduplication/bitreader_read_rice_signed_block.c b/src/libFLAC/deduplication/bitreader_read_rice_signed_block.c
new file mode 100644
index 0000000..75ed47f
--- /dev/null
+++ b/src/libFLAC/deduplication/bitreader_read_rice_signed_block.c
@@ -0,0 +1,143 @@
+{
+ /* try and get br->consumed_words and br->consumed_bits into register;
+ * must remember to flush them back to *br before calling other
+ * bitreader functions that use them, and before returning */
+ uint32_t cwords, words, lsbs, msbs, x, y, limit;
+ uint32_t ucbits; /* keep track of the number of unconsumed bits in word */
+ brword b;
+ int *val, *end;
+
+ 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 */
+
+ limit = UINT32_MAX >> parameter; /* Maximal msbs that can occur with residual bounded to int32_t */
+
+ val = vals;
+ end = vals + nvals;
+
+ if(parameter == 0) {
+ while(val < end) {
+ /* read the unary MSBs and end bit */
+ if(!FLAC__bitreader_read_unary_unsigned(br, &msbs))
+ return false;
+ /* Checking limit here would be overzealous: coding UINT32_MAX
+ * with parameter == 0 would take 4GiB */
+ *val++ = (int)(msbs >> 1) ^ -(int)(msbs & 1);
+ }
+
+ return true;
+ }
+
+ FLAC__ASSERT(parameter > 0);
+
+ cwords = br->consumed_words;
+ words = br->words;
+
+ /* if we've not consumed up to a partial tail word... */
+ if(cwords >= words) {
+ x = 0;
+ goto process_tail;
+ }
+
+ ucbits = FLAC__BITS_PER_WORD - br->consumed_bits;
+ b = br->buffer[cwords] << br->consumed_bits; /* keep unconsumed bits aligned to left */
+
+ while(val < end) {
+ /* read the unary MSBs and end bit */
+ x = y = COUNT_ZERO_MSBS2(b);
+ if(x == FLAC__BITS_PER_WORD) {
+ x = ucbits;
+ do {
+ /* didn't find stop bit yet, have to keep going... */
+ cwords++;
+ if (cwords >= words)
+ goto incomplete_msbs;
+ b = br->buffer[cwords];
+ y = COUNT_ZERO_MSBS2(b);
+ x += y;
+ } while(y == FLAC__BITS_PER_WORD);
+ }
+ b <<= y;
+ b <<= 1; /* account for stop bit */
+ ucbits = (ucbits - x - 1) % FLAC__BITS_PER_WORD;
+ msbs = x;
+
+ if(x > limit)
+ return false;
+
+ /* read the binary LSBs */
+ x = (FLAC__uint32)(b >> (FLAC__BITS_PER_WORD - parameter)); /* parameter < 32, so we can cast to 32-bit uint32_t */
+ if(parameter <= ucbits) {
+ ucbits -= parameter;
+ b <<= parameter;
+ } else {
+ /* there are still bits left to read, they will all be in the next word */
+ cwords++;
+ if (cwords >= words)
+ goto incomplete_lsbs;
+ b = br->buffer[cwords];
+ ucbits += FLAC__BITS_PER_WORD - parameter;
+ x |= (FLAC__uint32)(b >> ucbits);
+ b <<= FLAC__BITS_PER_WORD - ucbits;
+ }
+ lsbs = x;
+
+ /* compose the value */
+ x = (msbs << parameter) | lsbs;
+ *val++ = (int)(x >> 1) ^ -(int)(x & 1);
+
+ continue;
+
+ /* at this point we've eaten up all the whole words */
+process_tail:
+ do {
+ if(0) {
+incomplete_msbs:
+ br->consumed_bits = 0;
+ br->consumed_words = cwords;
+ }
+
+ /* read the unary MSBs and end bit */
+ if(!FLAC__bitreader_read_unary_unsigned(br, &msbs))
+ return false;
+ msbs += x;
+ x = ucbits = 0;
+
+ if(0) {
+incomplete_lsbs:
+ br->consumed_bits = 0;
+ br->consumed_words = cwords;
+ }
+
+ /* read the binary LSBs */
+ if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, parameter - ucbits))
+ return false;
+ lsbs = x | lsbs;
+
+ /* compose the value */
+ x = (msbs << parameter) | lsbs;
+ *val++ = (int)(x >> 1) ^ -(int)(x & 1);
+ x = 0;
+
+ cwords = br->consumed_words;
+ words = br->words;
+ ucbits = FLAC__BITS_PER_WORD - br->consumed_bits;
+ b = cwords < br->capacity ? br->buffer[cwords] << br->consumed_bits : 0;
+ } while(cwords >= words && val < end);
+ }
+
+ if(ucbits == 0 && cwords < words) {
+ /* don't leave the head word with no unconsumed bits */
+ cwords++;
+ ucbits = FLAC__BITS_PER_WORD;
+ }
+
+ br->consumed_bits = FLAC__BITS_PER_WORD - ucbits;
+ br->consumed_words = cwords;
+
+ return true;
+}
diff --git a/src/libFLAC/deduplication/lpc_compute_autocorrelation_intrin.c b/src/libFLAC/deduplication/lpc_compute_autocorrelation_intrin.c
new file mode 100644
index 0000000..76419db
--- /dev/null
+++ b/src/libFLAC/deduplication/lpc_compute_autocorrelation_intrin.c
@@ -0,0 +1,14 @@
+ int i, j;
+ (void) lag;
+ FLAC__ASSERT(lag <= MAX_LAG);
+
+ for(i = 0; i < MAX_LAG; i++)
+ autoc[i] = 0.0;
+
+ for(i = 0; i < MAX_LAG; i++)
+ for(j = 0; j <= i; j++)
+ autoc[j] += (double)data[i] * (double)data[i-j];
+
+ for(i = MAX_LAG; i < (int)data_len; i++)
+ for(j = 0; j < MAX_LAG; j++)
+ autoc[j] += (double)data[i] * (double)data[i-j];
diff --git a/src/libFLAC/deduplication/lpc_compute_autocorrelation_intrin_neon.c b/src/libFLAC/deduplication/lpc_compute_autocorrelation_intrin_neon.c
new file mode 100644
index 0000000..4df3aee
--- /dev/null
+++ b/src/libFLAC/deduplication/lpc_compute_autocorrelation_intrin_neon.c
@@ -0,0 +1,70 @@
+ int i;
+ float64x2_t sum0 = vdupq_n_f64(0.0f);
+ float64x2_t sum1 = vdupq_n_f64(0.0f);
+ float64x2_t sum2 = vdupq_n_f64(0.0f);
+ float64x2_t sum3 = vdupq_n_f64(0.0f);
+ float64x2_t d0 = vdupq_n_f64(0.0f);
+ float64x2_t d1 = vdupq_n_f64(0.0f);
+ float64x2_t d2 = vdupq_n_f64(0.0f);
+ float64x2_t d3 = vdupq_n_f64(0.0f);
+#if MAX_LAG > 8
+ float64x2_t sum4 = vdupq_n_f64(0.0f);
+ float64x2_t d4 = vdupq_n_f64(0.0f);
+#endif
+#if MAX_LAG > 10
+ float64x2_t sum5 = vdupq_n_f64(0.0f);
+ float64x2_t sum6 = vdupq_n_f64(0.0f);
+ float64x2_t d5 = vdupq_n_f64(0.0f);
+ float64x2_t d6 = vdupq_n_f64(0.0f);
+#endif
+ float64x2_t d;
+
+ (void)lag;
+ FLAC__ASSERT(lag <= MAX_LAG);
+
+ // Loop backwards through samples from data_len to 0
+ for (i = data_len - 1; i >= 0; i--)
+ {
+ d = vdupq_n_f64(data[i]); // Create vector with 2 entries data[i]
+
+ // The next 6 lines of code right-shift the elements through the 7 vectors d0..d6.
+ // The 7th line adds the newly loaded element to d0. This works like a stack, where
+ // data[i] is pushed onto the stack every time and the 9th element falls off
+#if MAX_LAG > 10
+ d6 = vextq_f64(d5,d6,1);
+ d5 = vextq_f64(d4,d5,1);
+#endif
+#if MAX_LAG > 8
+ d4 = vextq_f64(d3,d4,1);
+#endif
+ d3 = vextq_f64(d2,d3,1);
+ d2 = vextq_f64(d1,d2,1);
+ d1 = vextq_f64(d0,d1,1);
+ d0 = vextq_f64(d,d0,1);
+
+ // Fused multiply-add sum += d * d0..d6
+ sum0 = vfmaq_f64(sum0, d, d0);
+ sum1 = vfmaq_f64(sum1, d, d1);
+ sum2 = vfmaq_f64(sum2, d, d2);
+ sum3 = vfmaq_f64(sum3, d, d3);
+#if MAX_LAG > 8
+ sum4 = vfmaq_f64(sum4, d, d4);
+#endif
+#if MAX_LAG > 10
+ sum5 = vfmaq_f64(sum5, d, d5);
+ sum6 = vfmaq_f64(sum6, d, d6);
+#endif
+ }
+
+ // Store sum0..sum6 in autoc[0..14]
+ vst1q_f64(autoc, sum0);
+ vst1q_f64(autoc + 2, sum1);
+ vst1q_f64(autoc + 4, sum2);
+ vst1q_f64(autoc + 6, sum3);
+#if MAX_LAG > 8
+ vst1q_f64(autoc + 8, sum4);
+#endif
+#if MAX_LAG > 10
+ vst1q_f64(autoc + 10, sum5);
+ vst1q_f64(autoc + 12, sum6);
+#endif
diff --git a/src/libFLAC/deduplication/lpc_compute_autocorrelation_intrin_sse2.c b/src/libFLAC/deduplication/lpc_compute_autocorrelation_intrin_sse2.c
new file mode 100644
index 0000000..607b42f
--- /dev/null
+++ b/src/libFLAC/deduplication/lpc_compute_autocorrelation_intrin_sse2.c
@@ -0,0 +1,81 @@
+/* This code is imported several times in lpc_intrin_sse2.c with different
+ * values for MAX_LAG. Comments are for MAX_LAG == 14 */
+ int i;
+ __m128d sum0, sum1, sum2, sum3;
+ __m128d d0, d1, d2, d3;
+#if MAX_LAG > 8
+ __m128d d4;
+ __m128d sum4;
+#endif
+#if MAX_LAG > 10
+ __m128d d5, d6;
+ __m128d sum5, sum6;
+#endif
+
+ (void) lag;
+ FLAC__ASSERT(lag <= MAX_LAG);
+
+ /* Initialize all sum vectors with zero */
+ sum0 = _mm_setzero_pd();
+ sum1 = _mm_setzero_pd();
+ sum2 = _mm_setzero_pd();
+ sum3 = _mm_setzero_pd();
+ d0 = _mm_setzero_pd();
+ d1 = _mm_setzero_pd();
+ d2 = _mm_setzero_pd();
+ d3 = _mm_setzero_pd();
+#if MAX_LAG > 8
+ sum4 = _mm_setzero_pd();
+ d4 = _mm_setzero_pd();
+#endif
+#if MAX_LAG > 10
+ sum5 = _mm_setzero_pd();
+ sum6 = _mm_setzero_pd();
+ d5 = _mm_setzero_pd();
+ d6 = _mm_setzero_pd();
+#endif
+
+ /* Loop backwards through samples from data_len to limit */
+ for(i = data_len-1; i >= 0; i--) {
+ __m128d d = _mm_set1_pd(data[i]);
+
+ /* The next lines of code work like a queue. For more
+ * information see the lag8 version of this function */
+#if MAX_LAG > 10
+ d6 = _mm_shuffle_pd(d5, d6, _MM_SHUFFLE(0,0,0,1));
+ d5 = _mm_shuffle_pd(d4, d5, _MM_SHUFFLE(0,0,0,1));
+#endif
+#if MAX_LAG > 8
+ d4 = _mm_shuffle_pd(d3, d4, _MM_SHUFFLE(0,0,0,1));
+#endif
+ d3 = _mm_shuffle_pd(d2, d3, _MM_SHUFFLE(0,0,0,1));
+ d2 = _mm_shuffle_pd(d1, d2, _MM_SHUFFLE(0,0,0,1));
+ d1 = _mm_shuffle_pd(d0, d1, _MM_SHUFFLE(0,0,0,1));
+ d0 = _mm_shuffle_pd(d, d0, _MM_SHUFFLE(0,0,0,1));
+
+ /* sumn += d*dn */
+ sum0 = _mm_add_pd(sum0, _mm_mul_pd(d, d0));
+ sum1 = _mm_add_pd(sum1, _mm_mul_pd(d, d1));
+ sum2 = _mm_add_pd(sum2, _mm_mul_pd(d, d2));
+ sum3 = _mm_add_pd(sum3, _mm_mul_pd(d, d3));
+#if MAX_LAG > 8
+ sum4 = _mm_add_pd(sum4, _mm_mul_pd(d, d4));
+#endif
+#if MAX_LAG > 10
+ sum5 = _mm_add_pd(sum5, _mm_mul_pd(d, d5));
+ sum6 = _mm_add_pd(sum6, _mm_mul_pd(d, d6));
+#endif
+ }
+
+ /* Store sum0..sum6 in autoc[0..14] */
+ _mm_storeu_pd(autoc, sum0);
+ _mm_storeu_pd(autoc+2, sum1);
+ _mm_storeu_pd(autoc+4, sum2);
+ _mm_storeu_pd(autoc+6 ,sum3);
+#if MAX_LAG > 8
+ _mm_storeu_pd(autoc+8, sum4);
+#endif
+#if MAX_LAG > 10
+ _mm_storeu_pd(autoc+10,sum5);
+ _mm_storeu_pd(autoc+12,sum6);
+#endif
diff --git a/src/libFLAC/fixed.c b/src/libFLAC/fixed.c
new file mode 100644
index 0000000..5c42570
--- /dev/null
+++ b/src/libFLAC/fixed.c
@@ -0,0 +1,667 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <math.h>
+#include <string.h>
+#include "share/compat.h"
+#include "private/bitmath.h"
+#include "private/fixed.h"
+#include "private/macros.h"
+#include "FLAC/assert.h"
+
+#ifdef local_abs
+#undef local_abs
+#endif
+#define local_abs(x) ((uint32_t)((x)<0? -(x) : (x)))
+
+#ifdef local_abs64
+#undef local_abs64
+#endif
+#define local_abs64(x) ((uint64_t)((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;
+ uint32_t 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, (uint32_t)(-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;
+ uint32_t 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, (uint32_t)(-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
+uint32_t FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
+#else
+uint32_t FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
+#endif
+{
+ FLAC__uint32 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0;
+ uint32_t order;
+#if 0
+ /* This code has been around a long time, and was written when compilers weren't able
+ * to vectorize code. These days, compilers are better in optimizing the next block
+ * which is also much more readable
+ */
+ 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;
+ uint32_t i;
+ /* total_error_* are 64-bits to avoid overflow when encoding
+ * erratic signals when the bits-per-sample and blocksize are
+ * large.
+ */
+ 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;
+ }
+#else
+ int i;
+ for(i = 0; i < (int)data_len; i++) {
+ total_error_0 += local_abs(data[i]);
+ total_error_1 += local_abs(data[i] - data[i-1]);
+ total_error_2 += local_abs(data[i] - 2 * data[i-1] + data[i-2]);
+ total_error_3 += local_abs(data[i] - 3 * data[i-1] + 3 * data[i-2] - data[i-3]);
+ total_error_4 += local_abs(data[i] - 4 * data[i-1] + 6 * data[i-2] - 4 * data[i-3] + data[i-4]);
+ }
+#endif
+
+
+ /* prefer lower order */
+ if(total_error_0 <= flac_min(flac_min(flac_min(total_error_1, total_error_2), total_error_3), total_error_4))
+ order = 0;
+ else if(total_error_1 <= flac_min(flac_min(total_error_2, total_error_3), total_error_4))
+ order = 1;
+ else if(total_error_2 <= flac_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] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[1] = (float)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[2] = (float)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[3] = (float)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[4] = (float)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (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
+uint32_t FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
+#else
+uint32_t FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
+#endif
+{
+ FLAC__uint64 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0;
+ uint32_t order;
+ int i;
+
+ for(i = 0; i < (int)data_len; i++) {
+ total_error_0 += local_abs(data[i]);
+ total_error_1 += local_abs(data[i] - data[i-1]);
+ total_error_2 += local_abs(data[i] - 2 * data[i-1] + data[i-2]);
+ total_error_3 += local_abs(data[i] - 3 * data[i-1] + 3 * data[i-2] - data[i-3]);
+ total_error_4 += local_abs(data[i] - 4 * data[i-1] + 6 * data[i-2] - 4 * data[i-3] + data[i-4]);
+ }
+
+ /* prefer lower order */
+ if(total_error_0 <= flac_min(flac_min(flac_min(total_error_1, total_error_2), total_error_3), total_error_4))
+ order = 0;
+ else if(total_error_1 <= flac_min(flac_min(total_error_2, total_error_3), total_error_4))
+ order = 1;
+ else if(total_error_2 <= flac_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] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[1] = (float)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[2] = (float)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[3] = (float)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[4] = (float)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0);
+#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;
+}
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#define CHECK_ORDER_IS_VALID(macro_order) \
+if(order_##macro_order##_is_valid && total_error_##macro_order < smallest_error) { \
+ order = macro_order; \
+ smallest_error = total_error_##macro_order ; \
+ residual_bits_per_sample[ macro_order ] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0); \
+} \
+else \
+ residual_bits_per_sample[ macro_order ] = 34.0f;
+#else
+#define CHECK_ORDER_IS_VALID(macro_order) \
+if(order_##macro_order##_is_valid && total_error_##macro_order < smallest_error) { \
+ order = macro_order; \
+ smallest_error = total_error_##macro_order ; \
+ residual_bits_per_sample[ macro_order ] = (total_error_##macro_order > 0) ? local__compute_rbps_wide_integerized(total_error_##macro_order, data_len) : 0; \
+} \
+else \
+ residual_bits_per_sample[ macro_order ] = 34 * FLAC__FP_ONE;
+#endif
+
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+uint32_t FLAC__fixed_compute_best_predictor_limit_residual(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
+#else
+uint32_t FLAC__fixed_compute_best_predictor_limit_residual(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
+#endif
+{
+ FLAC__uint64 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0, smallest_error = UINT64_MAX;
+ FLAC__uint64 error_0, error_1, error_2, error_3, error_4;
+ FLAC__bool order_0_is_valid = true, order_1_is_valid = true, order_2_is_valid = true, order_3_is_valid = true, order_4_is_valid = true;
+ uint32_t order = 0;
+ int i;
+
+ for(i = -4; i < (int)data_len; i++) {
+ error_0 = local_abs64((FLAC__int64)data[i]);
+ error_1 = (i > -4) ? local_abs64((FLAC__int64)data[i] - data[i-1]) : 0 ;
+ error_2 = (i > -3) ? local_abs64((FLAC__int64)data[i] - 2 * (FLAC__int64)data[i-1] + data[i-2]) : 0;
+ error_3 = (i > -2) ? local_abs64((FLAC__int64)data[i] - 3 * (FLAC__int64)data[i-1] + 3 * (FLAC__int64)data[i-2] - data[i-3]) : 0;
+ error_4 = (i > -1) ? local_abs64((FLAC__int64)data[i] - 4 * (FLAC__int64)data[i-1] + 6 * (FLAC__int64)data[i-2] - 4 * (FLAC__int64)data[i-3] + data[i-4]) : 0;
+
+ total_error_0 += error_0;
+ total_error_1 += error_1;
+ total_error_2 += error_2;
+ total_error_3 += error_3;
+ total_error_4 += error_4;
+
+ /* residual must not be INT32_MIN because abs(INT32_MIN) is undefined */
+ if(error_0 > INT32_MAX)
+ order_0_is_valid = false;
+ if(error_1 > INT32_MAX)
+ order_1_is_valid = false;
+ if(error_2 > INT32_MAX)
+ order_2_is_valid = false;
+ if(error_3 > INT32_MAX)
+ order_3_is_valid = false;
+ if(error_4 > INT32_MAX)
+ order_4_is_valid = false;
+ }
+
+ CHECK_ORDER_IS_VALID(0);
+ CHECK_ORDER_IS_VALID(1);
+ CHECK_ORDER_IS_VALID(2);
+ CHECK_ORDER_IS_VALID(3);
+ CHECK_ORDER_IS_VALID(4);
+
+ return order;
+}
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+uint32_t FLAC__fixed_compute_best_predictor_limit_residual_33bit(const FLAC__int64 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
+#else
+uint32_t FLAC__fixed_compute_best_predictor_limit_residual_33bit(const FLAC__int64 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
+#endif
+{
+ FLAC__uint64 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0, smallest_error = UINT64_MAX;
+ FLAC__uint64 error_0, error_1, error_2, error_3, error_4;
+ FLAC__bool order_0_is_valid = true, order_1_is_valid = true, order_2_is_valid = true, order_3_is_valid = true, order_4_is_valid = true;
+ uint32_t order = 0;
+ int i;
+
+ for(i = -4; i < (int)data_len; i++) {
+ error_0 = local_abs64(data[i]);
+ error_1 = (i > -4) ? local_abs64(data[i] - data[i-1]) : 0 ;
+ error_2 = (i > -3) ? local_abs64(data[i] - 2 * data[i-1] + data[i-2]) : 0;
+ error_3 = (i > -2) ? local_abs64(data[i] - 3 * data[i-1] + 3 * data[i-2] - data[i-3]) : 0;
+ error_4 = (i > -1) ? local_abs64(data[i] - 4 * data[i-1] + 6 * data[i-2] - 4 * data[i-3] + data[i-4]) : 0;
+
+ total_error_0 += error_0;
+ total_error_1 += error_1;
+ total_error_2 += error_2;
+ total_error_3 += error_3;
+ total_error_4 += error_4;
+
+ /* residual must not be INT32_MIN because abs(INT32_MIN) is undefined */
+ if(error_0 > INT32_MAX)
+ order_0_is_valid = false;
+ if(error_1 > INT32_MAX)
+ order_1_is_valid = false;
+ if(error_2 > INT32_MAX)
+ order_2_is_valid = false;
+ if(error_3 > INT32_MAX)
+ order_3_is_valid = false;
+ if(error_4 > INT32_MAX)
+ order_4_is_valid = false;
+ }
+
+ CHECK_ORDER_IS_VALID(0);
+ CHECK_ORDER_IS_VALID(1);
+ CHECK_ORDER_IS_VALID(2);
+ CHECK_ORDER_IS_VALID(3);
+ CHECK_ORDER_IS_VALID(4);
+
+ return order;
+}
+
+void FLAC__fixed_compute_residual(const FLAC__int32 data[], uint32_t data_len, uint32_t 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++)
+ residual[i] = data[i] - 2*data[i-1] + data[i-2];
+ break;
+ case 3:
+ for(i = 0; i < idata_len; i++)
+ residual[i] = data[i] - 3*data[i-1] + 3*data[i-2] - data[i-3];
+ break;
+ case 4:
+ for(i = 0; i < idata_len; i++)
+ residual[i] = data[i] - 4*data[i-1] + 6*data[i-2] - 4*data[i-3] + data[i-4];
+ break;
+ default:
+ FLAC__ASSERT(0);
+ }
+}
+
+void FLAC__fixed_compute_residual_wide(const FLAC__int32 data[], uint32_t data_len, uint32_t 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] = (FLAC__int64)data[i] - data[i-1];
+ break;
+ case 2:
+ for(i = 0; i < idata_len; i++)
+ residual[i] = (FLAC__int64)data[i] - 2*(FLAC__int64)data[i-1] + data[i-2];
+ break;
+ case 3:
+ for(i = 0; i < idata_len; i++)
+ residual[i] = (FLAC__int64)data[i] - 3*(FLAC__int64)data[i-1] + 3*(FLAC__int64)data[i-2] - data[i-3];
+ break;
+ case 4:
+ for(i = 0; i < idata_len; i++)
+ residual[i] = (FLAC__int64)data[i] - 4*(FLAC__int64)data[i-1] + 6*(FLAC__int64)data[i-2] - 4*(FLAC__int64)data[i-3] + data[i-4];
+ break;
+ default:
+ FLAC__ASSERT(0);
+ }
+}
+
+void FLAC__fixed_compute_residual_wide_33bit(const FLAC__int64 data[], uint32_t data_len, uint32_t order, FLAC__int32 residual[])
+{
+ const int idata_len = (int)data_len;
+ int i;
+
+ switch(order) {
+ case 0:
+ for(i = 0; i < idata_len; i++)
+ residual[i] = data[i];
+ 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++)
+ residual[i] = data[i] - 2*data[i-1] + data[i-2];
+ break;
+ case 3:
+ for(i = 0; i < idata_len; i++)
+ residual[i] = data[i] - 3*data[i-1] + 3*data[i-2] - data[i-3];
+ break;
+ case 4:
+ for(i = 0; i < idata_len; i++)
+ residual[i] = data[i] - 4*data[i-1] + 6*data[i-2] - 4*data[i-3] + data[i-4];
+ break;
+ default:
+ FLAC__ASSERT(0);
+ }
+}
+
+#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && !defined(FUZZING_BUILD_MODE_FLAC_SANITIZE_SIGNED_INTEGER_OVERFLOW)
+/* The attribute below is to silence the undefined sanitizer of oss-fuzz.
+ * Because fuzzing feeds bogus predictors and residual samples to the
+ * decoder, having overflows in this section is unavoidable. Also,
+ * because the calculated values are audio path only, there is no
+ * potential for security problems */
+__attribute__((no_sanitize("signed-integer-overflow")))
+#endif
+void FLAC__fixed_restore_signal(const FLAC__int32 residual[], uint32_t data_len, uint32_t 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++)
+ data[i] = residual[i] + 2*data[i-1] - data[i-2];
+ break;
+ case 3:
+ for(i = 0; i < idata_len; i++)
+ data[i] = residual[i] + 3*data[i-1] - 3*data[i-2] + data[i-3];
+ break;
+ case 4:
+ for(i = 0; i < idata_len; i++)
+ data[i] = residual[i] + 4*data[i-1] - 6*data[i-2] + 4*data[i-3] - data[i-4];
+ break;
+ default:
+ FLAC__ASSERT(0);
+ }
+}
+
+void FLAC__fixed_restore_signal_wide(const FLAC__int32 residual[], uint32_t data_len, uint32_t 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] = (FLAC__int64)residual[i] + (FLAC__int64)data[i-1];
+ break;
+ case 2:
+ for(i = 0; i < idata_len; i++)
+ data[i] = (FLAC__int64)residual[i] + 2*(FLAC__int64)data[i-1] - (FLAC__int64)data[i-2];
+ break;
+ case 3:
+ for(i = 0; i < idata_len; i++)
+ data[i] = (FLAC__int64)residual[i] + 3*(FLAC__int64)data[i-1] - 3*(FLAC__int64)data[i-2] + (FLAC__int64)data[i-3];
+ break;
+ case 4:
+ for(i = 0; i < idata_len; i++)
+ data[i] = (FLAC__int64)residual[i] + 4*(FLAC__int64)data[i-1] - 6*(FLAC__int64)data[i-2] + 4*(FLAC__int64)data[i-3] - (FLAC__int64)data[i-4];
+ break;
+ default:
+ FLAC__ASSERT(0);
+ }
+}
+
+#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && !defined(FUZZING_BUILD_MODE_FLAC_SANITIZE_SIGNED_INTEGER_OVERFLOW)
+/* The attribute below is to silence the undefined sanitizer of oss-fuzz.
+ * Because fuzzing feeds bogus predictors and residual samples to the
+ * decoder, having overflows in this section is unavoidable. Also,
+ * because the calculated values are audio path only, there is no
+ * potential for security problems */
+__attribute__((no_sanitize("signed-integer-overflow")))
+#endif
+void FLAC__fixed_restore_signal_wide_33bit(const FLAC__int32 residual[], uint32_t data_len, uint32_t order, FLAC__int64 data[])
+{
+ int i, idata_len = (int)data_len;
+
+ switch(order) {
+ case 0:
+ for(i = 0; i < idata_len; i++)
+ data[i] = residual[i];
+ break;
+ case 1:
+ for(i = 0; i < idata_len; i++)
+ data[i] = (FLAC__int64)residual[i] + data[i-1];
+ break;
+ case 2:
+ for(i = 0; i < idata_len; i++)
+ data[i] = (FLAC__int64)residual[i] + 2*data[i-1] - data[i-2];
+ break;
+ case 3:
+ for(i = 0; i < idata_len; i++)
+ data[i] = (FLAC__int64)residual[i] + 3*data[i-1] - 3*data[i-2] + data[i-3];
+ break;
+ case 4:
+ for(i = 0; i < idata_len; i++)
+ data[i] = (FLAC__int64)residual[i] + 4*data[i-1] - 6*data[i-2] + 4*data[i-3] - data[i-4];
+ break;
+ default:
+ FLAC__ASSERT(0);
+ }
+}
diff --git a/src/libFLAC/fixed_intrin_avx2.c b/src/libFLAC/fixed_intrin_avx2.c
new file mode 100644
index 0000000..85fc4a6
--- /dev/null
+++ b/src/libFLAC/fixed_intrin_avx2.c
@@ -0,0 +1,343 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "private/cpu.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#ifndef FLAC__NO_ASM
+#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
+#include "private/fixed.h"
+#ifdef FLAC__AVX2_SUPPORTED
+
+#include <immintrin.h>
+#include <math.h>
+#include "private/macros.h"
+#include "share/compat.h"
+#include "FLAC/assert.h"
+
+#ifdef local_abs
+#undef local_abs
+#endif
+#define local_abs(x) ((uint32_t)((x)<0? -(x) : (x)))
+
+FLAC__SSE_TARGET("avx2")
+uint32_t FLAC__fixed_compute_best_predictor_wide_intrin_avx2(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1])
+{
+ FLAC__uint64 total_error_0, total_error_1, total_error_2, total_error_3, total_error_4;
+ FLAC__int32 i, data_len_int;
+ uint32_t order;
+ __m256i total_err0, total_err1, total_err2, total_err3, total_err4;
+ __m256i prev_err0, prev_err1, prev_err2, prev_err3;
+ __m256i tempA, tempB, bitmask;
+ FLAC__int64 data_scalar[4];
+ FLAC__int64 prev_err0_scalar[4];
+ FLAC__int64 prev_err1_scalar[4];
+ FLAC__int64 prev_err2_scalar[4];
+ FLAC__int64 prev_err3_scalar[4];
+ total_err0 = _mm256_setzero_si256();
+ total_err1 = _mm256_setzero_si256();
+ total_err2 = _mm256_setzero_si256();
+ total_err3 = _mm256_setzero_si256();
+ total_err4 = _mm256_setzero_si256();
+ data_len_int = data_len;
+
+ for(i = 0; i < 4; i++){
+ prev_err0_scalar[i] = data[-1+i*(data_len_int/4)];
+ prev_err1_scalar[i] = data[-1+i*(data_len_int/4)] - data[-2+i*(data_len_int/4)];
+ prev_err2_scalar[i] = prev_err1_scalar[i] - (data[-2+i*(data_len_int/4)] - data[-3+i*(data_len_int/4)]);
+ prev_err3_scalar[i] = prev_err2_scalar[i] - (data[-2+i*(data_len_int/4)] - 2*data[-3+i*(data_len_int/4)] + data[-4+i*(data_len_int/4)]);
+ }
+ prev_err0 = _mm256_loadu_si256((const __m256i*)(void*)prev_err0_scalar);
+ prev_err1 = _mm256_loadu_si256((const __m256i*)(void*)prev_err1_scalar);
+ prev_err2 = _mm256_loadu_si256((const __m256i*)(void*)prev_err2_scalar);
+ prev_err3 = _mm256_loadu_si256((const __m256i*)(void*)prev_err3_scalar);
+ for(i = 0; i < data_len_int / 4; i++){
+ data_scalar[0] = data[i];
+ data_scalar[1] = data[i+data_len/4];
+ data_scalar[2] = data[i+2*data_len/4];
+ data_scalar[3] = data[i+3*data_len/4];
+ tempA = _mm256_loadu_si256((const __m256i*)(void*)data_scalar);
+ /* Next three intrinsics calculate tempB as abs of tempA */
+ bitmask = _mm256_cmpgt_epi64(_mm256_set1_epi64x(0), tempA);
+ tempB = _mm256_xor_si256(tempA, bitmask);
+ tempB = _mm256_sub_epi64(tempB, bitmask);
+ total_err0 = _mm256_add_epi64(total_err0,tempB);
+ tempB = _mm256_sub_epi64(tempA,prev_err0);
+ prev_err0 = tempA;
+ /* Next three intrinsics calculate tempA as abs of tempB */
+ bitmask = _mm256_cmpgt_epi64(_mm256_set1_epi64x(0), tempB);
+ tempA = _mm256_xor_si256(tempB, bitmask);
+ tempA = _mm256_sub_epi64(tempA, bitmask);
+ total_err1 = _mm256_add_epi64(total_err1,tempA);
+ tempA = _mm256_sub_epi64(tempB,prev_err1);
+ prev_err1 = tempB;
+ /* Next three intrinsics calculate tempB as abs of tempA */
+ bitmask = _mm256_cmpgt_epi64(_mm256_set1_epi64x(0), tempA);
+ tempB = _mm256_xor_si256(tempA, bitmask);
+ tempB = _mm256_sub_epi64(tempB, bitmask);
+ total_err2 = _mm256_add_epi64(total_err2,tempB);
+ tempB = _mm256_sub_epi64(tempA,prev_err2);
+ prev_err2 = tempA;
+ /* Next three intrinsics calculate tempA as abs of tempB */
+ bitmask = _mm256_cmpgt_epi64(_mm256_set1_epi64x(0), tempB);
+ tempA = _mm256_xor_si256(tempB, bitmask);
+ tempA = _mm256_sub_epi64(tempA, bitmask);
+ total_err3 = _mm256_add_epi64(total_err3,tempA);
+ tempA = _mm256_sub_epi64(tempB,prev_err3);
+ prev_err3 = tempB;
+ /* Next three intrinsics calculate tempB as abs of tempA */
+ bitmask = _mm256_cmpgt_epi64(_mm256_set1_epi64x(0), tempA);
+ tempB = _mm256_xor_si256(tempA, bitmask);
+ tempB = _mm256_sub_epi64(tempB, bitmask);
+ total_err4 = _mm256_add_epi64(total_err4,tempB);
+ }
+ _mm256_storeu_si256((__m256i*)(void*)data_scalar,total_err0);
+ total_error_0 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3];
+ _mm256_storeu_si256((__m256i*)(void*)data_scalar,total_err1);
+ total_error_1 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3];
+ _mm256_storeu_si256((__m256i*)(void*)data_scalar,total_err2);
+ total_error_2 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3];
+ _mm256_storeu_si256((__m256i*)(void*)data_scalar,total_err3);
+ total_error_3 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3];
+ _mm256_storeu_si256((__m256i*)(void*)data_scalar,total_err4);
+ total_error_4 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3];
+
+ /* Ignore the remainder, we're ignore the first few samples too */
+
+ /* prefer lower order */
+ if(total_error_0 <= flac_min(flac_min(flac_min(total_error_1, total_error_2), total_error_3), total_error_4))
+ order = 0;
+ else if(total_error_1 <= flac_min(flac_min(total_error_2, total_error_3), total_error_4))
+ order = 1;
+ else if(total_error_2 <= flac_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);
+
+ residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[1] = (float)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[2] = (float)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[3] = (float)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[4] = (float)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0);
+
+ return order;
+}
+
+#ifdef local_abs64
+#undef local_abs64
+#endif
+#define local_abs64(x) ((uint64_t)((x)<0? -(x) : (x)))
+
+#define CHECK_ORDER_IS_VALID(macro_order) \
+if(shadow_error_##macro_order <= INT32_MAX) { \
+ if(total_error_##macro_order < smallest_error) { \
+ order = macro_order; \
+ smallest_error = total_error_##macro_order ; \
+ } \
+ residual_bits_per_sample[ macro_order ] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0); \
+} \
+else \
+ residual_bits_per_sample[ macro_order ] = 34.0f;
+
+FLAC__SSE_TARGET("avx2")
+uint32_t FLAC__fixed_compute_best_predictor_limit_residual_intrin_avx2(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1])
+{
+ FLAC__uint64 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0, smallest_error = UINT64_MAX;
+ FLAC__uint64 shadow_error_0 = 0, shadow_error_1 = 0, shadow_error_2 = 0, shadow_error_3 = 0, shadow_error_4 = 0;
+ FLAC__uint64 error_0, error_1, error_2, error_3, error_4;
+ FLAC__int32 i, data_len_int;
+ uint32_t order = 0;
+ __m256i total_err0, total_err1, total_err2, total_err3, total_err4;
+ __m256i shadow_err0, shadow_err1, shadow_err2, shadow_err3, shadow_err4;
+ __m256i prev_err0, prev_err1, prev_err2, prev_err3;
+ __m256i tempA, tempB, bitmask;
+ FLAC__int64 data_scalar[4];
+ FLAC__int64 prev_err0_scalar[4];
+ FLAC__int64 prev_err1_scalar[4];
+ FLAC__int64 prev_err2_scalar[4];
+ FLAC__int64 prev_err3_scalar[4];
+ total_err0 = _mm256_setzero_si256();
+ total_err1 = _mm256_setzero_si256();
+ total_err2 = _mm256_setzero_si256();
+ total_err3 = _mm256_setzero_si256();
+ total_err4 = _mm256_setzero_si256();
+ shadow_err0 = _mm256_setzero_si256();
+ shadow_err1 = _mm256_setzero_si256();
+ shadow_err2 = _mm256_setzero_si256();
+ shadow_err3 = _mm256_setzero_si256();
+ shadow_err4 = _mm256_setzero_si256();
+ data_len_int = data_len;
+
+ /* First take care of preceding samples */
+ for(i = -4; i < 0; i++) {
+ error_0 = local_abs64((FLAC__int64)data[i]);
+ error_1 = (i > -4) ? local_abs64((FLAC__int64)data[i] - data[i-1]) : 0 ;
+ error_2 = (i > -3) ? local_abs64((FLAC__int64)data[i] - 2 * (FLAC__int64)data[i-1] + data[i-2]) : 0;
+ error_3 = (i > -2) ? local_abs64((FLAC__int64)data[i] - 3 * (FLAC__int64)data[i-1] + 3 * (FLAC__int64)data[i-2] - data[i-3]) : 0;
+
+ total_error_0 += error_0;
+ total_error_1 += error_1;
+ total_error_2 += error_2;
+ total_error_3 += error_3;
+
+ shadow_error_0 |= error_0;
+ shadow_error_1 |= error_1;
+ shadow_error_2 |= error_2;
+ shadow_error_3 |= error_3;
+ }
+
+ for(i = 0; i < 4; i++){
+ prev_err0_scalar[i] = data[-1+i*(data_len_int/4)];
+ prev_err1_scalar[i] = (FLAC__int64)(data[-1+i*(data_len_int/4)]) - data[-2+i*(data_len_int/4)];
+ prev_err2_scalar[i] = prev_err1_scalar[i] - ((FLAC__int64)(data[-2+i*(data_len_int/4)]) - data[-3+i*(data_len_int/4)]);
+ prev_err3_scalar[i] = prev_err2_scalar[i] - ((FLAC__int64)(data[-2+i*(data_len_int/4)]) - 2*(FLAC__int64)(data[-3+i*(data_len_int/4)]) + data[-4+i*(data_len_int/4)]);
+ }
+ prev_err0 = _mm256_loadu_si256((const __m256i*)(void*)prev_err0_scalar);
+ prev_err1 = _mm256_loadu_si256((const __m256i*)(void*)prev_err1_scalar);
+ prev_err2 = _mm256_loadu_si256((const __m256i*)(void*)prev_err2_scalar);
+ prev_err3 = _mm256_loadu_si256((const __m256i*)(void*)prev_err3_scalar);
+ for(i = 0; i < data_len_int / 4; i++){
+ data_scalar[0] = data[i];
+ data_scalar[1] = data[i+data_len/4];
+ data_scalar[2] = data[i+2*data_len/4];
+ data_scalar[3] = data[i+3*data_len/4];
+ tempA = _mm256_loadu_si256((const __m256i*)(void*)data_scalar);
+ /* Next three intrinsics calculate tempB as abs of tempA */
+ bitmask = _mm256_cmpgt_epi64(_mm256_set1_epi64x(0), tempA);
+ tempB = _mm256_xor_si256(tempA, bitmask);
+ tempB = _mm256_sub_epi64(tempB, bitmask);
+ total_err0 = _mm256_add_epi64(total_err0,tempB);
+ shadow_err0 = _mm256_or_si256(shadow_err0,tempB);
+ tempB = _mm256_sub_epi64(tempA,prev_err0);
+ prev_err0 = tempA;
+ /* Next three intrinsics calculate tempA as abs of tempB */
+ bitmask = _mm256_cmpgt_epi64(_mm256_set1_epi64x(0), tempB);
+ tempA = _mm256_xor_si256(tempB, bitmask);
+ tempA = _mm256_sub_epi64(tempA, bitmask);
+ total_err1 = _mm256_add_epi64(total_err1,tempA);
+ shadow_err1 = _mm256_or_si256(shadow_err1,tempA);
+ tempA = _mm256_sub_epi64(tempB,prev_err1);
+ prev_err1 = tempB;
+ /* Next three intrinsics calculate tempB as abs of tempA */
+ bitmask = _mm256_cmpgt_epi64(_mm256_set1_epi64x(0), tempA);
+ tempB = _mm256_xor_si256(tempA, bitmask);
+ tempB = _mm256_sub_epi64(tempB, bitmask);
+ total_err2 = _mm256_add_epi64(total_err2,tempB);
+ shadow_err2 = _mm256_or_si256(shadow_err2,tempB);
+ tempB = _mm256_sub_epi64(tempA,prev_err2);
+ prev_err2 = tempA;
+ /* Next three intrinsics calculate tempA as abs of tempB */
+ bitmask = _mm256_cmpgt_epi64(_mm256_set1_epi64x(0), tempB);
+ tempA = _mm256_xor_si256(tempB, bitmask);
+ tempA = _mm256_sub_epi64(tempA, bitmask);
+ total_err3 = _mm256_add_epi64(total_err3,tempA);
+ shadow_err3 = _mm256_or_si256(shadow_err3,tempA);
+ tempA = _mm256_sub_epi64(tempB,prev_err3);
+ prev_err3 = tempB;
+ /* Next three intrinsics calculate tempB as abs of tempA */
+ bitmask = _mm256_cmpgt_epi64(_mm256_set1_epi64x(0), tempA);
+ tempB = _mm256_xor_si256(tempA, bitmask);
+ tempB = _mm256_sub_epi64(tempB, bitmask);
+ total_err4 = _mm256_add_epi64(total_err4,tempB);
+ shadow_err4 = _mm256_or_si256(shadow_err4,tempB);
+ }
+ _mm256_storeu_si256((__m256i*)(void*)data_scalar,total_err0);
+ total_error_0 += data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3];
+ _mm256_storeu_si256((__m256i*)(void*)data_scalar,total_err1);
+ total_error_1 += data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3];
+ _mm256_storeu_si256((__m256i*)(void*)data_scalar,total_err2);
+ total_error_2 += data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3];
+ _mm256_storeu_si256((__m256i*)(void*)data_scalar,total_err3);
+ total_error_3 += data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3];
+ _mm256_storeu_si256((__m256i*)(void*)data_scalar,total_err4);
+ total_error_4 += data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3];
+ _mm256_storeu_si256((__m256i*)(void*)data_scalar,shadow_err0);
+ shadow_error_0 |= data_scalar[0] | data_scalar[1] | data_scalar[2] | data_scalar[3];
+ _mm256_storeu_si256((__m256i*)(void*)data_scalar,shadow_err1);
+ shadow_error_1 |= data_scalar[0] | data_scalar[1] | data_scalar[2] | data_scalar[3];
+ _mm256_storeu_si256((__m256i*)(void*)data_scalar,shadow_err2);
+ shadow_error_2 |= data_scalar[0] | data_scalar[1] | data_scalar[2] | data_scalar[3];
+ _mm256_storeu_si256((__m256i*)(void*)data_scalar,shadow_err3);
+ shadow_error_3 |= data_scalar[0] | data_scalar[1] | data_scalar[2] | data_scalar[3];
+ _mm256_storeu_si256((__m256i*)(void*)data_scalar,shadow_err4);
+ shadow_error_4 |= data_scalar[0] | data_scalar[1] | data_scalar[2] | data_scalar[3];
+
+ /* Take care of remaining sample */
+ for(i = (data_len/4)*4; i < data_len_int; i++) {
+ error_0 = local_abs64((FLAC__int64)data[i]);
+ error_1 = local_abs64((FLAC__int64)data[i] - data[i-1]);
+ error_2 = local_abs64((FLAC__int64)data[i] - 2 * (FLAC__int64)data[i-1] + data[i-2]);
+ error_3 = local_abs64((FLAC__int64)data[i] - 3 * (FLAC__int64)data[i-1] + 3 * (FLAC__int64)data[i-2] - data[i-3]);
+ error_4 = local_abs64((FLAC__int64)data[i] - 4 * (FLAC__int64)data[i-1] + 6 * (FLAC__int64)data[i-2] - 4 * (FLAC__int64)data[i-3] + data[i-4]);
+
+ total_error_0 += error_0;
+ total_error_1 += error_1;
+ total_error_2 += error_2;
+ total_error_3 += error_3;
+ total_error_4 += error_4;
+
+ shadow_error_0 |= error_0;
+ shadow_error_1 |= error_1;
+ shadow_error_2 |= error_2;
+ shadow_error_3 |= error_3;
+ shadow_error_4 |= error_4;
+ }
+
+
+ CHECK_ORDER_IS_VALID(0);
+ CHECK_ORDER_IS_VALID(1);
+ CHECK_ORDER_IS_VALID(2);
+ CHECK_ORDER_IS_VALID(3);
+ CHECK_ORDER_IS_VALID(4);
+
+ return order;
+}
+
+#endif /* FLAC__AVX2_SUPPORTED */
+#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
+#endif /* FLAC__NO_ASM */
+#endif /* FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/src/libFLAC/fixed_intrin_sse2.c b/src/libFLAC/fixed_intrin_sse2.c
new file mode 100644
index 0000000..b92c13c
--- /dev/null
+++ b/src/libFLAC/fixed_intrin_sse2.c
@@ -0,0 +1,194 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "private/cpu.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#ifndef FLAC__NO_ASM
+#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN
+#include "private/fixed.h"
+#ifdef FLAC__SSE2_SUPPORTED
+
+#include <emmintrin.h> /* SSE2 */
+#include <math.h>
+#include "private/macros.h"
+#include "share/compat.h"
+#include "FLAC/assert.h"
+
+#ifdef FLAC__CPU_IA32
+#define m128i_to_i64(dest, src) _mm_storel_epi64((__m128i*)&dest, src)
+#else
+#define m128i_to_i64(dest, src) dest = _mm_cvtsi128_si64(src)
+#endif
+
+#ifdef local_abs
+#undef local_abs
+#endif
+#define local_abs(x) ((uint32_t)((x)<0? -(x) : (x)))
+
+FLAC__SSE_TARGET("sse2")
+uint32_t FLAC__fixed_compute_best_predictor_intrin_sse2(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1])
+{
+ FLAC__uint32 total_error_0, total_error_1, total_error_2, total_error_3, total_error_4;
+ FLAC__int32 i, data_len_int;
+ uint32_t order;
+ __m128i total_err0, total_err1, total_err2, total_err3, total_err4;
+ __m128i prev_err0, prev_err1, prev_err2, prev_err3;
+ __m128i tempA, tempB, bitmask;
+ FLAC__int32 data_scalar[4];
+ FLAC__int32 prev_err0_scalar[4];
+ FLAC__int32 prev_err1_scalar[4];
+ FLAC__int32 prev_err2_scalar[4];
+ FLAC__int32 prev_err3_scalar[4];
+ total_err0 = _mm_setzero_si128();
+ total_err1 = _mm_setzero_si128();
+ total_err2 = _mm_setzero_si128();
+ total_err3 = _mm_setzero_si128();
+ total_err4 = _mm_setzero_si128();
+ data_len_int = data_len;
+
+ for(i = 0; i < 4; i++){
+ prev_err0_scalar[i] = data[-1+i*(data_len_int/4)];
+ prev_err1_scalar[i] = data[-1+i*(data_len_int/4)] - data[-2+i*(data_len_int/4)];
+ prev_err2_scalar[i] = prev_err1_scalar[i] - (data[-2+i*(data_len_int/4)] - data[-3+i*(data_len_int/4)]);
+ prev_err3_scalar[i] = prev_err2_scalar[i] - (data[-2+i*(data_len_int/4)] - 2*data[-3+i*(data_len_int/4)] + data[-4+i*(data_len_int/4)]);
+ }
+ prev_err0 = _mm_loadu_si128((const __m128i*)prev_err0_scalar);
+ prev_err1 = _mm_loadu_si128((const __m128i*)prev_err1_scalar);
+ prev_err2 = _mm_loadu_si128((const __m128i*)prev_err2_scalar);
+ prev_err3 = _mm_loadu_si128((const __m128i*)prev_err3_scalar);
+ for(i = 0; i < data_len_int / 4; i++){
+ data_scalar[0] = data[i];
+ data_scalar[1] = data[i+data_len/4];
+ data_scalar[2] = data[i+2*(data_len/4)];
+ data_scalar[3] = data[i+3*(data_len/4)];
+ tempA = _mm_loadu_si128((const __m128i*)data_scalar);
+ /* Next three intrinsics calculate tempB as abs of tempA */
+ bitmask = _mm_srai_epi32(tempA, 31);
+ tempB = _mm_xor_si128(tempA, bitmask);
+ tempB = _mm_sub_epi32(tempB, bitmask);
+ total_err0 = _mm_add_epi32(total_err0,tempB);
+ tempB = _mm_sub_epi32(tempA,prev_err0);
+ prev_err0 = tempA;
+ /* Next three intrinsics calculate tempA as abs of tempB */
+ bitmask = _mm_srai_epi32(tempB, 31);
+ tempA = _mm_xor_si128(tempB, bitmask);
+ tempA = _mm_sub_epi32(tempA, bitmask);
+ total_err1 = _mm_add_epi32(total_err1,tempA);
+ tempA = _mm_sub_epi32(tempB,prev_err1);
+ prev_err1 = tempB;
+ /* Next three intrinsics calculate tempB as abs of tempA */
+ bitmask = _mm_srai_epi32(tempA, 31);
+ tempB = _mm_xor_si128(tempA, bitmask);
+ tempB = _mm_sub_epi32(tempB, bitmask);
+ total_err2 = _mm_add_epi32(total_err2,tempB);
+ tempB = _mm_sub_epi32(tempA,prev_err2);
+ prev_err2 = tempA;
+ /* Next three intrinsics calculate tempA as abs of tempB */
+ bitmask = _mm_srai_epi32(tempB, 31);
+ tempA = _mm_xor_si128(tempB, bitmask);
+ tempA = _mm_sub_epi32(tempA, bitmask);
+ total_err3 = _mm_add_epi32(total_err3,tempA);
+ tempA = _mm_sub_epi32(tempB,prev_err3);
+ prev_err3 = tempB;
+ /* Next three intrinsics calculate tempB as abs of tempA */
+ bitmask = _mm_srai_epi32(tempA, 31);
+ tempB = _mm_xor_si128(tempA, bitmask);
+ tempB = _mm_sub_epi32(tempB, bitmask);
+ total_err4 = _mm_add_epi32(total_err4,tempB);
+ }
+ _mm_storeu_si128((__m128i*)data_scalar,total_err0);
+ total_error_0 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3];
+ _mm_storeu_si128((__m128i*)data_scalar,total_err1);
+ total_error_1 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3];
+ _mm_storeu_si128((__m128i*)data_scalar,total_err2);
+ total_error_2 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3];
+ _mm_storeu_si128((__m128i*)data_scalar,total_err3);
+ total_error_3 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3];
+ _mm_storeu_si128((__m128i*)data_scalar,total_err4);
+ total_error_4 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3];
+
+ /* Now the remainder of samples needs to be processed */
+ i *= 4;
+ if(data_len % 4 > 0){
+ FLAC__int32 last_error_0 = data[i-1];
+ FLAC__int32 last_error_1 = data[i-1] - data[i-2];
+ FLAC__int32 last_error_2 = last_error_1 - (data[i-2] - data[i-3]);
+ FLAC__int32 last_error_3 = last_error_2 - (data[i-2] - 2*data[i-3] + data[i-4]);
+ FLAC__int32 error, save;
+ for(; i < data_len_int; 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;
+ }
+ }
+
+ /* prefer lower order */
+ if(total_error_0 <= flac_min(flac_min(flac_min(total_error_1, total_error_2), total_error_3), total_error_4))
+ order = 0;
+ else if(total_error_1 <= flac_min(flac_min(total_error_2, total_error_3), total_error_4))
+ order = 1;
+ else if(total_error_2 <= flac_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);
+
+ residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[1] = (float)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[2] = (float)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[3] = (float)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[4] = (float)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0);
+
+ return order;
+}
+
+#endif /* FLAC__SSE2_SUPPORTED */
+#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
+#endif /* FLAC__NO_ASM */
+#endif /* FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/src/libFLAC/fixed_intrin_sse42.c b/src/libFLAC/fixed_intrin_sse42.c
new file mode 100644
index 0000000..0556eaa
--- /dev/null
+++ b/src/libFLAC/fixed_intrin_sse42.c
@@ -0,0 +1,223 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "private/cpu.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#ifndef FLAC__NO_ASM
+#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
+#include "private/fixed.h"
+#ifdef FLAC__SSE4_2_SUPPORTED
+
+#include <nmmintrin.h> /* SSE4.2 */
+#include <math.h>
+#include "private/macros.h"
+#include "share/compat.h"
+#include "FLAC/assert.h"
+
+#ifdef local_abs64
+#undef local_abs64
+#endif
+#define local_abs64(x) ((uint64_t)((x)<0? -(x) : (x)))
+
+#define CHECK_ORDER_IS_VALID(macro_order) \
+if(shadow_error_##macro_order <= INT32_MAX) { \
+ if(total_error_##macro_order < smallest_error) { \
+ order = macro_order; \
+ smallest_error = total_error_##macro_order ; \
+ } \
+ residual_bits_per_sample[ macro_order ] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0); \
+} \
+else \
+ residual_bits_per_sample[ macro_order ] = 34.0f;
+
+FLAC__SSE_TARGET("sse4.2")
+uint32_t FLAC__fixed_compute_best_predictor_limit_residual_intrin_sse42(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1])
+{
+ FLAC__uint64 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0, smallest_error = UINT64_MAX;
+ FLAC__uint64 shadow_error_0 = 0, shadow_error_1 = 0, shadow_error_2 = 0, shadow_error_3 = 0, shadow_error_4 = 0;
+ FLAC__uint64 error_0, error_1, error_2, error_3, error_4;
+ FLAC__int32 i, data_len_int;
+ uint32_t order = 0;
+ __m128i total_err0, total_err1, total_err2, total_err3, total_err4;
+ __m128i shadow_err0, shadow_err1, shadow_err2, shadow_err3, shadow_err4;
+ __m128i prev_err0, prev_err1, prev_err2, prev_err3;
+ __m128i tempA, tempB, bitmask;
+ FLAC__int64 data_scalar[2];
+ FLAC__int64 prev_err0_scalar[2];
+ FLAC__int64 prev_err1_scalar[2];
+ FLAC__int64 prev_err2_scalar[2];
+ FLAC__int64 prev_err3_scalar[2];
+ total_err0 = _mm_setzero_si128();
+ total_err1 = _mm_setzero_si128();
+ total_err2 = _mm_setzero_si128();
+ total_err3 = _mm_setzero_si128();
+ total_err4 = _mm_setzero_si128();
+ shadow_err0 = _mm_setzero_si128();
+ shadow_err1 = _mm_setzero_si128();
+ shadow_err2 = _mm_setzero_si128();
+ shadow_err3 = _mm_setzero_si128();
+ shadow_err4 = _mm_setzero_si128();
+ data_len_int = data_len;
+
+ /* First take care of preceding samples */
+ for(i = -4; i < 0; i++) {
+ error_0 = local_abs64((FLAC__int64)data[i]);
+ error_1 = (i > -4) ? local_abs64((FLAC__int64)data[i] - data[i-1]) : 0 ;
+ error_2 = (i > -3) ? local_abs64((FLAC__int64)data[i] - 2 * (FLAC__int64)data[i-1] + data[i-2]) : 0;
+ error_3 = (i > -2) ? local_abs64((FLAC__int64)data[i] - 3 * (FLAC__int64)data[i-1] + 3 * (FLAC__int64)data[i-2] - data[i-3]) : 0;
+
+ total_error_0 += error_0;
+ total_error_1 += error_1;
+ total_error_2 += error_2;
+ total_error_3 += error_3;
+
+ shadow_error_0 |= error_0;
+ shadow_error_1 |= error_1;
+ shadow_error_2 |= error_2;
+ shadow_error_3 |= error_3;
+ }
+
+ for(i = 0; i < 2; i++){
+ prev_err0_scalar[i] = data[-1+i*(data_len_int/2)];
+ prev_err1_scalar[i] = (FLAC__int64)(data[-1+i*(data_len_int/2)]) - data[-2+i*(data_len_int/2)];
+ prev_err2_scalar[i] = prev_err1_scalar[i] - ((FLAC__int64)(data[-2+i*(data_len_int/2)]) - data[-3+i*(data_len_int/2)]);
+ prev_err3_scalar[i] = prev_err2_scalar[i] - ((FLAC__int64)(data[-2+i*(data_len_int/2)]) - 2*(FLAC__int64)(data[-3+i*(data_len_int/2)]) + data[-4+i*(data_len_int/2)]);
+ }
+ prev_err0 = _mm_loadu_si128((const __m128i*)prev_err0_scalar);
+ prev_err1 = _mm_loadu_si128((const __m128i*)prev_err1_scalar);
+ prev_err2 = _mm_loadu_si128((const __m128i*)prev_err2_scalar);
+ prev_err3 = _mm_loadu_si128((const __m128i*)prev_err3_scalar);
+ for(i = 0; i < data_len_int / 2; i++){
+ data_scalar[0] = data[i];
+ data_scalar[1] = data[i+data_len/2];
+ tempA = _mm_loadu_si128((const __m128i*)data_scalar);
+ /* Next three intrinsics calculate tempB as abs of tempA */
+ bitmask = _mm_cmpgt_epi64(_mm_set1_epi64x(0), tempA);
+ tempB = _mm_xor_si128(tempA, bitmask);
+ tempB = _mm_sub_epi64(tempB, bitmask);
+ total_err0 = _mm_add_epi64(total_err0,tempB);
+ shadow_err0 = _mm_or_si128(shadow_err0,tempB);
+ tempB = _mm_sub_epi64(tempA,prev_err0);
+ prev_err0 = tempA;
+ /* Next three intrinsics calculate tempA as abs of tempB */
+ bitmask = _mm_cmpgt_epi64(_mm_set1_epi64x(0), tempB);
+ tempA = _mm_xor_si128(tempB, bitmask);
+ tempA = _mm_sub_epi64(tempA, bitmask);
+ total_err1 = _mm_add_epi64(total_err1,tempA);
+ shadow_err1 = _mm_or_si128(shadow_err1,tempA);
+ tempA = _mm_sub_epi64(tempB,prev_err1);
+ prev_err1 = tempB;
+ /* Next three intrinsics calculate tempB as abs of tempA */
+ bitmask = _mm_cmpgt_epi64(_mm_set1_epi64x(0), tempA);
+ tempB = _mm_xor_si128(tempA, bitmask);
+ tempB = _mm_sub_epi64(tempB, bitmask);
+ total_err2 = _mm_add_epi64(total_err2,tempB);
+ shadow_err2 = _mm_or_si128(shadow_err2,tempB);
+ tempB = _mm_sub_epi64(tempA,prev_err2);
+ prev_err2 = tempA;
+ /* Next three intrinsics calculate tempA as abs of tempB */
+ bitmask = _mm_cmpgt_epi64(_mm_set1_epi64x(0), tempB);
+ tempA = _mm_xor_si128(tempB, bitmask);
+ tempA = _mm_sub_epi64(tempA, bitmask);
+ total_err3 = _mm_add_epi64(total_err3,tempA);
+ shadow_err3 = _mm_or_si128(shadow_err3,tempA);
+ tempA = _mm_sub_epi64(tempB,prev_err3);
+ prev_err3 = tempB;
+ /* Next three intrinsics calculate tempB as abs of tempA */
+ bitmask = _mm_cmpgt_epi64(_mm_set1_epi64x(0), tempA);
+ tempB = _mm_xor_si128(tempA, bitmask);
+ tempB = _mm_sub_epi64(tempB, bitmask);
+ total_err4 = _mm_add_epi64(total_err4,tempB);
+ shadow_err4 = _mm_or_si128(shadow_err4,tempB);
+ }
+ _mm_storeu_si128((__m128i*)data_scalar,total_err0);
+ total_error_0 += data_scalar[0] + data_scalar[1];
+ _mm_storeu_si128((__m128i*)data_scalar,total_err1);
+ total_error_1 += data_scalar[0] + data_scalar[1];
+ _mm_storeu_si128((__m128i*)data_scalar,total_err2);
+ total_error_2 += data_scalar[0] + data_scalar[1];
+ _mm_storeu_si128((__m128i*)data_scalar,total_err3);
+ total_error_3 += data_scalar[0] + data_scalar[1];
+ _mm_storeu_si128((__m128i*)data_scalar,total_err4);
+ total_error_4 += data_scalar[0] + data_scalar[1];
+ _mm_storeu_si128((__m128i*)data_scalar,shadow_err0);
+ shadow_error_0 |= data_scalar[0] | data_scalar[1];
+ _mm_storeu_si128((__m128i*)data_scalar,shadow_err1);
+ shadow_error_1 |= data_scalar[0] | data_scalar[1];
+ _mm_storeu_si128((__m128i*)data_scalar,shadow_err2);
+ shadow_error_2 |= data_scalar[0] | data_scalar[1];
+ _mm_storeu_si128((__m128i*)data_scalar,shadow_err3);
+ shadow_error_3 |= data_scalar[0] | data_scalar[1];
+ _mm_storeu_si128((__m128i*)data_scalar,shadow_err4);
+ shadow_error_4 |= data_scalar[0] | data_scalar[1];
+
+ /* Take care of remaining sample */
+ if(data_len_int % 2 > 0) {
+ i += data_len/2;
+ error_0 = local_abs64((FLAC__int64)data[i]);
+ error_1 = local_abs64((FLAC__int64)data[i] - data[i-1]);
+ error_2 = local_abs64((FLAC__int64)data[i] - 2 * (FLAC__int64)data[i-1] + data[i-2]);
+ error_3 = local_abs64((FLAC__int64)data[i] - 3 * (FLAC__int64)data[i-1] + 3 * (FLAC__int64)data[i-2] - data[i-3]);
+ error_4 = local_abs64((FLAC__int64)data[i] - 4 * (FLAC__int64)data[i-1] + 6 * (FLAC__int64)data[i-2] - 4 * (FLAC__int64)data[i-3] + data[i-4]);
+
+ total_error_0 += error_0;
+ total_error_1 += error_1;
+ total_error_2 += error_2;
+ total_error_3 += error_3;
+ total_error_4 += error_4;
+
+ shadow_error_0 |= error_0;
+ shadow_error_1 |= error_1;
+ shadow_error_2 |= error_2;
+ shadow_error_3 |= error_3;
+ shadow_error_4 |= error_4;
+ }
+
+
+ CHECK_ORDER_IS_VALID(0);
+ CHECK_ORDER_IS_VALID(1);
+ CHECK_ORDER_IS_VALID(2);
+ CHECK_ORDER_IS_VALID(3);
+ CHECK_ORDER_IS_VALID(4);
+
+ return order;
+}
+
+#endif /* FLAC__SSE4_2_SUPPORTED */
+#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
+#endif /* FLAC__NO_ASM */
+#endif /* FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/src/libFLAC/fixed_intrin_ssse3.c b/src/libFLAC/fixed_intrin_ssse3.c
new file mode 100644
index 0000000..551693b
--- /dev/null
+++ b/src/libFLAC/fixed_intrin_ssse3.c
@@ -0,0 +1,179 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "private/cpu.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#ifndef FLAC__NO_ASM
+#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
+#include "private/fixed.h"
+#ifdef FLAC__SSSE3_SUPPORTED
+
+#include <tmmintrin.h> /* SSSE3 */
+#include <math.h>
+#include "private/macros.h"
+#include "share/compat.h"
+#include "FLAC/assert.h"
+
+#ifdef FLAC__CPU_IA32
+#define m128i_to_i64(dest, src) _mm_storel_epi64((__m128i*)&dest, src)
+#else
+#define m128i_to_i64(dest, src) dest = _mm_cvtsi128_si64(src)
+#endif
+
+#ifdef local_abs
+#undef local_abs
+#endif
+#define local_abs(x) ((uint32_t)((x)<0? -(x) : (x)))
+
+FLAC__SSE_TARGET("ssse3")
+uint32_t FLAC__fixed_compute_best_predictor_intrin_ssse3(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1])
+{
+ FLAC__uint32 total_error_0, total_error_1, total_error_2, total_error_3, total_error_4;
+ FLAC__int32 i, data_len_int;
+ uint32_t order;
+ __m128i total_err0, total_err1, total_err2, total_err3, total_err4;
+ __m128i prev_err0, prev_err1, prev_err2, prev_err3;
+ __m128i tempA, tempB;
+ FLAC__int32 data_scalar[4];
+ FLAC__int32 prev_err0_scalar[4];
+ FLAC__int32 prev_err1_scalar[4];
+ FLAC__int32 prev_err2_scalar[4];
+ FLAC__int32 prev_err3_scalar[4];
+ total_err0 = _mm_setzero_si128();
+ total_err1 = _mm_setzero_si128();
+ total_err2 = _mm_setzero_si128();
+ total_err3 = _mm_setzero_si128();
+ total_err4 = _mm_setzero_si128();
+ data_len_int = data_len;
+
+ for(i = 0; i < 4; i++){
+ prev_err0_scalar[i] = data[-1+i*(data_len_int/4)];
+ prev_err1_scalar[i] = data[-1+i*(data_len_int/4)] - data[-2+i*(data_len_int/4)];
+ prev_err2_scalar[i] = prev_err1_scalar[i] - (data[-2+i*(data_len_int/4)] - data[-3+i*(data_len_int/4)]);
+ prev_err3_scalar[i] = prev_err2_scalar[i] - (data[-2+i*(data_len_int/4)] - 2*data[-3+i*(data_len_int/4)] + data[-4+i*(data_len_int/4)]);
+ }
+ prev_err0 = _mm_loadu_si128((const __m128i*)prev_err0_scalar);
+ prev_err1 = _mm_loadu_si128((const __m128i*)prev_err1_scalar);
+ prev_err2 = _mm_loadu_si128((const __m128i*)prev_err2_scalar);
+ prev_err3 = _mm_loadu_si128((const __m128i*)prev_err3_scalar);
+ for(i = 0; i < data_len_int / 4; i++){
+ data_scalar[0] = data[i];
+ data_scalar[1] = data[i+data_len/4];
+ data_scalar[2] = data[i+2*(data_len/4)];
+ data_scalar[3] = data[i+3*(data_len/4)];
+ tempA = _mm_loadu_si128((const __m128i*)data_scalar);
+ tempB = _mm_abs_epi32(tempA);
+ total_err0 = _mm_add_epi32(total_err0,tempB);
+ tempB = _mm_sub_epi32(tempA,prev_err0);
+ prev_err0 = tempA;
+ tempA = _mm_abs_epi32(tempB);
+ total_err1 = _mm_add_epi32(total_err1,tempA);
+ tempA = _mm_sub_epi32(tempB,prev_err1);
+ prev_err1 = tempB;
+ tempB = _mm_abs_epi32(tempA);
+ total_err2 = _mm_add_epi32(total_err2,tempB);
+ tempB = _mm_sub_epi32(tempA,prev_err2);
+ prev_err2 = tempA;
+ tempA = _mm_abs_epi32(tempB);
+ total_err3 = _mm_add_epi32(total_err3,tempA);
+ tempA = _mm_sub_epi32(tempB,prev_err3);
+ prev_err3 = tempB;
+ tempB = _mm_abs_epi32(tempA);
+ total_err4 = _mm_add_epi32(total_err4,tempB);
+ }
+ _mm_storeu_si128((__m128i*)data_scalar,total_err0);
+ total_error_0 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3];
+ _mm_storeu_si128((__m128i*)data_scalar,total_err1);
+ total_error_1 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3];
+ _mm_storeu_si128((__m128i*)data_scalar,total_err2);
+ total_error_2 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3];
+ _mm_storeu_si128((__m128i*)data_scalar,total_err3);
+ total_error_3 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3];
+ _mm_storeu_si128((__m128i*)data_scalar,total_err4);
+ total_error_4 = data_scalar[0] + data_scalar[1] + data_scalar[2] + data_scalar[3];
+
+ /* Now the remainder of samples needs to be processed */
+ i *= 4;
+ if(data_len % 4 > 0){
+ FLAC__int32 last_error_0 = data[i-1];
+ FLAC__int32 last_error_1 = data[i-1] - data[i-2];
+ FLAC__int32 last_error_2 = last_error_1 - (data[i-2] - data[i-3]);
+ FLAC__int32 last_error_3 = last_error_2 - (data[i-2] - 2*data[i-3] + data[i-4]);
+ FLAC__int32 error, save;
+ for(; i < data_len_int; 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;
+ }
+ }
+
+ /* prefer lower order */
+ if(total_error_0 <= flac_min(flac_min(flac_min(total_error_1, total_error_2), total_error_3), total_error_4))
+ order = 0;
+ else if(total_error_1 <= flac_min(flac_min(total_error_2, total_error_3), total_error_4))
+ order = 1;
+ else if(total_error_2 <= flac_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);
+
+ residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[1] = (float)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[2] = (float)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[3] = (float)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[4] = (float)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0);
+
+ return order;
+}
+
+#endif /* FLAC__SSSE3_SUPPORTED */
+#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
+#endif /* FLAC__NO_ASM */
+#endif /* FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/src/libFLAC/flac.pc.in b/src/libFLAC/flac.pc.in
new file mode 100644
index 0000000..56e8594
--- /dev/null
+++ b/src/libFLAC/flac.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: FLAC
+Description: Free Lossless Audio Codec Library
+Version: @VERSION@
+Requires.private: @OGG_PACKAGE@
+Libs: -L${libdir} -lFLAC
+Libs.private: -lm
+Cflags: -I${includedir}
diff --git a/src/libFLAC/float.c b/src/libFLAC/float.c
new file mode 100644
index 0000000..a06ad28
--- /dev/null
+++ b/src/libFLAC/float.c
@@ -0,0 +1,302 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2004-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "FLAC/assert.h"
+#include "share/compat.h"
+#include "private/float.h"
+
+#ifdef FLAC__INTEGER_ONLY_LIBRARY
+
+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, uint32_t fracbits, uint32_t 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
index 0000000..8bbffbe
--- /dev/null
+++ b/src/libFLAC/format.c
@@ -0,0 +1,608 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef 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 "share/alloc.h"
+#include "share/compat.h"
+#include "private/format.h"
+#include "private/macros.h"
+
+#if (defined GIT_COMMIT_HASH && defined GIT_COMMIT_DATE)
+# ifdef GIT_COMMIT_TAG
+FLAC_API const char *FLAC__VERSION_STRING = GIT_COMMIT_TAG;
+FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC " GIT_COMMIT_TAG " " GIT_COMMIT_DATE;
+# else
+FLAC_API const char *FLAC__VERSION_STRING = "git-" GIT_COMMIT_HASH " " GIT_COMMIT_DATE;
+FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC git-" GIT_COMMIT_HASH " " GIT_COMMIT_DATE;
+# endif
+#else
+/* PACKAGE_VERSION should come from configure */
+FLAC_API const char *FLAC__VERSION_STRING = PACKAGE_VERSION;
+FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC " PACKAGE_VERSION " 20230623";
+#endif
+
+FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4] = { 'f','L','a','C' };
+FLAC_API const uint32_t FLAC__STREAM_SYNC = 0x664C6143;
+FLAC_API const uint32_t FLAC__STREAM_SYNC_LEN = 32; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN = 16; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN = 16; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN = 24; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN = 24; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN = 20; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN = 3; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN = 5; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN = 36; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN = 128; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_APPLICATION_ID_LEN = 32; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN = 64; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN = 64; /* bits */
+FLAC_API const uint32_t 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 uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN = 32; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN = 64; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN = 8; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN = 3*8; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN = 64; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN = 8; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN = 12*8; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN = 1; /* bit */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN = 1; /* bit */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN = 6+13*8; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN = 8; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN = 128*8; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN = 64; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN = 1; /* bit */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN = 7+258*8; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN = 8; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_TYPE_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_COLORS_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN = 32; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_IS_LAST_LEN = 1; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_TYPE_LEN = 7; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_LENGTH_LEN = 24; /* bits */
+
+FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC = 0x3ffe;
+FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC_LEN = 14; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_RESERVED_LEN = 1; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN = 1; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCK_SIZE_LEN = 4; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_SAMPLE_RATE_LEN = 4; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN = 4; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN = 3; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_ZERO_PAD_LEN = 1; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_CRC_LEN = 8; /* bits */
+
+FLAC_API const uint32_t FLAC__FRAME_FOOTER_CRC_LEN = 16; /* bits */
+
+FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_TYPE_LEN = 2; /* bits */
+FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN = 4; /* bits */
+FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN = 4; /* bits */
+FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN = 5; /* bits */
+FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN = 5; /* bits */
+
+FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER = 15; /* == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN)-1 */
+FLAC_API const uint32_t 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 uint32_t FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN = 4; /* bits */
+FLAC_API const uint32_t FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN = 5; /* bits */
+
+FLAC_API const uint32_t FLAC__SUBFRAME_ZERO_PAD_LEN = 1; /* bits */
+FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_LEN = 6; /* bits */
+FLAC_API const uint32_t FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN = 1; /* bits */
+
+FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK = 0x00;
+FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK = 0x02;
+FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK = 0x10;
+FLAC_API const uint32_t 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(uint32_t sample_rate)
+{
+ if(sample_rate > FLAC__MAX_SAMPLE_RATE) {
+ return false;
+ }
+ else
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__format_blocksize_is_subset(uint32_t blocksize, uint32_t sample_rate)
+{
+ if(blocksize > 16384)
+ return false;
+ else if(sample_rate <= 48000 && blocksize > 4608)
+ return false;
+ else
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__format_sample_rate_is_subset(uint32_t sample_rate)
+{
+ if( // sample rate is not subset if
+ !FLAC__format_sample_rate_is_valid(sample_rate) || // sample rate is invalid or
+ sample_rate >= ((1u << 16) * 10) || // sample rate is larger then or equal to 655360 or
+ (sample_rate >= (1u << 16) && sample_rate % 10 != 0) //sample rate is >= 65536 and not divisible by 10
+ ) {
+ 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)
+{
+ uint32_t i;
+ FLAC__uint64 prev_sample_number = 0;
+ FLAC__bool got_prev = false;
+
+ FLAC__ASSERT(0 != seek_table);
+
+ if((FLAC__uint64)(seek_table->num_points) * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN))
+ return false;
+
+ 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 uint32_t FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table)
+{
+ uint32_t i, j;
+ FLAC__bool first;
+
+ FLAC__ASSERT(0 != seek_table);
+
+ if (seek_table->num_points == 0)
+ return 0;
+
+ /* 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 uint32_t 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, uint32_t length)
+{
+ if(length == (uint32_t)(-1)) {
+ while(*value) {
+ uint32_t n = utf8len_(value);
+ if(n == 0)
+ return false;
+ value += n;
+ }
+ }
+ else {
+ const FLAC__byte *end = value + length;
+ while(value < end) {
+ uint32_t 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, uint32_t 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) {
+ uint32_t 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)
+{
+ uint32_t 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; ) {
+ uint32_t 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
+ */
+#if 0 /* UNUSED */
+uint32_t FLAC__format_get_max_rice_partition_order(uint32_t blocksize, uint32_t 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
+ );
+}
+#endif
+
+uint32_t FLAC__format_get_max_rice_partition_order_from_blocksize(uint32_t blocksize)
+{
+ uint32_t max_rice_partition_order = 0;
+ while(!(blocksize & 1)) {
+ max_rice_partition_order++;
+ blocksize >>= 1;
+ }
+ return flac_min(FLAC__MAX_RICE_PARTITION_ORDER, max_rice_partition_order);
+}
+
+uint32_t FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(uint32_t limit, uint32_t blocksize, uint32_t predictor_order)
+{
+ uint32_t 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);
+}
+
+#if defined(_MSC_VER)
+// silence three MSVC warnings 'result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)'
+#pragma warning ( disable : 4334 )
+#endif
+
+FLAC__bool FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(FLAC__EntropyCodingMethod_PartitionedRiceContents *object, uint32_t max_partition_order)
+{
+ FLAC__ASSERT(0 != object);
+
+ if(object->capacity_by_order < max_partition_order || object->parameters == NULL || object->raw_bits == NULL) {
+ if(0 == (object->parameters = safe_realloc_(object->parameters, sizeof(uint32_t)*(1 << max_partition_order))))
+ return false;
+ if(0 == (object->raw_bits = safe_realloc_(object->raw_bits, sizeof(uint32_t)*(1 << max_partition_order))))
+ return false;
+ memset(object->raw_bits, 0, sizeof(uint32_t)*(1 << max_partition_order));
+ object->capacity_by_order = max_partition_order;
+ }
+
+ return true;
+}
+
+#if defined(_MSC_VER)
+#pragma warning ( default : 4334 )
+#endif
diff --git a/src/libFLAC/include/Makefile.am b/src/libFLAC/include/Makefile.am
new file mode 100644
index 0000000..8484d12
--- /dev/null
+++ b/src/libFLAC/include/Makefile.am
@@ -0,0 +1,32 @@
+# libFLAC - Free Lossless Audio Codec library
+# Copyright (C) 2001-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# 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/Makefile.in b/src/libFLAC/include/Makefile.in
new file mode 100644
index 0000000..b59a2cb
--- /dev/null
+++ b/src/libFLAC/include/Makefile.in
@@ -0,0 +1,689 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in 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.
+
+@SET_MAKE@
+
+# libFLAC - Free Lossless Audio Codec library
+# Copyright (C) 2001-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# 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.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/libFLAC/include
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/add_cflags.m4 \
+ $(top_srcdir)/m4/add_cxxflags.m4 \
+ $(top_srcdir)/m4/ax_add_fortify_source.m4 \
+ $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_enable_debug.m4 \
+ $(top_srcdir)/m4/bswap.m4 $(top_srcdir)/m4/clang.m4 \
+ $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gcc_version.m4 \
+ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/ogg.m4 \
+ $(top_srcdir)/m4/really_gcc.m4 \
+ $(top_srcdir)/m4/stack_protect.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_64_BIT_WORDS = @ENABLE_64_BIT_WORDS@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLAC__HAS_OGG = @FLAC__HAS_OGG@
+FLAC__TEST_LEVEL = @FLAC__TEST_LEVEL@
+FLAC__TEST_WITH_VALGRIND = @FLAC__TEST_WITH_VALGRIND@
+GCC_MAJOR_VERSION = @GCC_MAJOR_VERSION@
+GCC_MINOR_VERSION = @GCC_MINOR_VERSION@
+GCC_VERSION = @GCC_VERSION@
+GIT_COMMIT_VERSION_HASH = @GIT_COMMIT_VERSION_HASH@
+GIT_FOUND = @GIT_FOUND@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_FUZZING_ENGINE = @LIB_FUZZING_ENGINE@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OBJ_FORMAT = @OBJ_FORMAT@
+OGG_CFLAGS = @OGG_CFLAGS@
+OGG_LIBS = @OGG_LIBS@
+OGG_PACKAGE = @OGG_PACKAGE@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = private protected
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/libFLAC/include/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/libFLAC/include/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-generic clean-libtool cscopelist-am ctags \
+ ctags-am distclean distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/libFLAC/include/private/Makefile.am b/src/libFLAC/include/private/Makefile.am
new file mode 100644
index 0000000..3e63d31
--- /dev/null
+++ b/src/libFLAC/include/private/Makefile.am
@@ -0,0 +1,53 @@
+# libFLAC - Free Lossless Audio Codec library
+# Copyright (C) 2001-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# 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 \
+ macros.h \
+ md5.h \
+ memory.h \
+ metadata.h \
+ ogg_decoder_aspect.h \
+ ogg_encoder_aspect.h \
+ ogg_helper.h \
+ ogg_mapping.h \
+ stream_encoder.h \
+ stream_encoder_framing.h \
+ window.h
diff --git a/src/libFLAC/include/private/Makefile.in b/src/libFLAC/include/private/Makefile.in
new file mode 100644
index 0000000..475175f
--- /dev/null
+++ b/src/libFLAC/include/private/Makefile.in
@@ -0,0 +1,599 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in 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.
+
+@SET_MAKE@
+
+# libFLAC - Free Lossless Audio Codec library
+# Copyright (C) 2001-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# 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.
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/libFLAC/include/private
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/add_cflags.m4 \
+ $(top_srcdir)/m4/add_cxxflags.m4 \
+ $(top_srcdir)/m4/ax_add_fortify_source.m4 \
+ $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_enable_debug.m4 \
+ $(top_srcdir)/m4/bswap.m4 $(top_srcdir)/m4/clang.m4 \
+ $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gcc_version.m4 \
+ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/ogg.m4 \
+ $(top_srcdir)/m4/really_gcc.m4 \
+ $(top_srcdir)/m4/stack_protect.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_64_BIT_WORDS = @ENABLE_64_BIT_WORDS@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLAC__HAS_OGG = @FLAC__HAS_OGG@
+FLAC__TEST_LEVEL = @FLAC__TEST_LEVEL@
+FLAC__TEST_WITH_VALGRIND = @FLAC__TEST_WITH_VALGRIND@
+GCC_MAJOR_VERSION = @GCC_MAJOR_VERSION@
+GCC_MINOR_VERSION = @GCC_MINOR_VERSION@
+GCC_VERSION = @GCC_VERSION@
+GIT_COMMIT_VERSION_HASH = @GIT_COMMIT_VERSION_HASH@
+GIT_FOUND = @GIT_FOUND@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_FUZZING_ENGINE = @LIB_FUZZING_ENGINE@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OBJ_FORMAT = @OBJ_FORMAT@
+OGG_CFLAGS = @OGG_CFLAGS@
+OGG_LIBS = @OGG_LIBS@
+OGG_PACKAGE = @OGG_PACKAGE@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_HEADERS = \
+ all.h \
+ bitmath.h \
+ bitreader.h \
+ bitwriter.h \
+ cpu.h \
+ crc.h \
+ fixed.h \
+ float.h \
+ format.h \
+ lpc.h \
+ macros.h \
+ md5.h \
+ memory.h \
+ metadata.h \
+ ogg_decoder_aspect.h \
+ ogg_encoder_aspect.h \
+ ogg_helper.h \
+ ogg_mapping.h \
+ stream_encoder.h \
+ stream_encoder_framing.h \
+ window.h
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/libFLAC/include/private/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/libFLAC/include/private/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool cscopelist-am ctags ctags-am distclean \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/libFLAC/include/private/all.h b/src/libFLAC/include/private/all.h
new file mode 100644
index 0000000..10b6949
--- /dev/null
+++ b/src/libFLAC/include/private/all.h
@@ -0,0 +1,50 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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
index 0000000..12e062f
--- /dev/null
+++ b/src/libFLAC/include/private/bitmath.h
@@ -0,0 +1,210 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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"
+#include "FLAC/assert.h"
+
+#include "share/compat.h"
+
+#if defined(_MSC_VER)
+#include <intrin.h> /* for _BitScanReverse* */
+#endif
+
+/* Will never be emitted for MSVC, GCC, Intel compilers */
+static inline uint32_t FLAC__clz_soft_uint32(FLAC__uint32 word)
+{
+ static const uint8_t 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,
+ };
+
+ return word > 0xffffff ? byte_to_unary_table[word >> 24] :
+ word > 0xffff ? byte_to_unary_table[word >> 16] + 8 :
+ word > 0xff ? byte_to_unary_table[word >> 8] + 16 :
+ byte_to_unary_table[word] + 24;
+}
+
+static inline uint32_t FLAC__clz_uint32(FLAC__uint32 v)
+{
+/* Never used with input 0 */
+ FLAC__ASSERT(v > 0);
+#if defined(__INTEL_COMPILER)
+ return _bit_scan_reverse(v) ^ 31U;
+#elif defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+/* This will translate either to (bsr ^ 31U), clz , ctlz, cntlz, lzcnt depending on
+ * -march= setting or to a software routine in exotic machines. */
+ return __builtin_clz(v);
+#elif defined(_MSC_VER)
+ {
+ uint32_t idx;
+ _BitScanReverse(&idx, v);
+ return idx ^ 31U;
+ }
+#else
+ return FLAC__clz_soft_uint32(v);
+#endif
+}
+
+/* Used when 64-bit bsr/clz is unavailable; can use 32-bit bsr/clz when possible */
+static inline uint32_t FLAC__clz_soft_uint64(FLAC__uint64 word)
+{
+ return (FLAC__uint32)(word>>32) ? FLAC__clz_uint32((FLAC__uint32)(word>>32)) :
+ FLAC__clz_uint32((FLAC__uint32)word) + 32;
+}
+
+static inline uint32_t FLAC__clz_uint64(FLAC__uint64 v)
+{
+ /* Never used with input 0 */
+ FLAC__ASSERT(v > 0);
+#if defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+ return __builtin_clzll(v);
+#elif (defined(__INTEL_COMPILER) || defined(_MSC_VER)) && (defined(_M_IA64) || defined(_M_X64))
+ {
+ uint32_t idx;
+ _BitScanReverse64(&idx, v);
+ return idx ^ 63U;
+ }
+#else
+ return FLAC__clz_soft_uint64(v);
+#endif
+}
+
+/* These two functions work with input 0 */
+static inline uint32_t FLAC__clz2_uint32(FLAC__uint32 v)
+{
+ if (!v)
+ return 32;
+ return FLAC__clz_uint32(v);
+}
+
+static inline uint32_t FLAC__clz2_uint64(FLAC__uint64 v)
+{
+ if (!v)
+ return 64;
+ return FLAC__clz_uint64(v);
+}
+
+/* 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
+ */
+
+static inline uint32_t FLAC__bitmath_ilog2(FLAC__uint32 v)
+{
+ FLAC__ASSERT(v > 0);
+#if defined(__INTEL_COMPILER)
+ return _bit_scan_reverse(v);
+#elif defined(_MSC_VER)
+ {
+ uint32_t idx;
+ _BitScanReverse(&idx, v);
+ return idx;
+ }
+#else
+ return FLAC__clz_uint32(v) ^ 31U;
+#endif
+}
+
+static inline uint32_t FLAC__bitmath_ilog2_wide(FLAC__uint64 v)
+{
+ FLAC__ASSERT(v > 0);
+#if defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+ return __builtin_clzll(v) ^ 63U;
+/* Sorry, only supported in x64/Itanium.. and both have fast FPU which makes integer-only encoder pointless */
+#elif (defined(__INTEL_COMPILER) || defined(_MSC_VER)) && (defined(_M_IA64) || defined(_M_X64))
+ {
+ uint32_t idx;
+ _BitScanReverse64(&idx, v);
+ return idx;
+ }
+#else
+/* Brain-damaged compilers will use the fastest possible way that is,
+ de Bruijn sequences (http://supertech.csail.mit.edu/papers/debruijn.pdf)
+ (C) Timothy B. Terriberry (tterribe@xiph.org) 2001-2009 CC0 (Public domain).
+*/
+ {
+ static const uint8_t DEBRUIJN_IDX64[64]={
+ 0, 1, 2, 7, 3,13, 8,19, 4,25,14,28, 9,34,20,40,
+ 5,17,26,38,15,46,29,48,10,31,35,54,21,50,41,57,
+ 63, 6,12,18,24,27,33,39,16,37,45,47,30,53,49,56,
+ 62,11,23,32,36,44,52,55,61,22,43,51,60,42,59,58
+ };
+ v|= v>>1;
+ v|= v>>2;
+ v|= v>>4;
+ v|= v>>8;
+ v|= v>>16;
+ v|= v>>32;
+ v= (v>>1)+1;
+ return DEBRUIJN_IDX64[v*FLAC__U64L(0x218A392CD3D5DBF)>>58&0x3F];
+ }
+#endif
+}
+
+uint32_t FLAC__bitmath_silog2(FLAC__int64 v);
+
+#endif
diff --git a/src/libFLAC/include/private/bitreader.h b/src/libFLAC/include/private/bitreader.h
new file mode 100644
index 0000000..c36c926
--- /dev/null
+++ b/src/libFLAC/include/private/bitreader.h
@@ -0,0 +1,101 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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__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_set_framesync_location(FLAC__BitReader *br);
+FLAC__bool FLAC__bitreader_rewind_to_after_last_seen_framesync(FLAC__BitReader *br);
+
+/*
+ * 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);
+uint32_t FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br);
+uint32_t FLAC__bitreader_get_input_bits_unconsumed(const FLAC__BitReader *br);
+void FLAC__bitreader_set_limit(FLAC__BitReader *br, uint32_t limit);
+void FLAC__bitreader_remove_limit(FLAC__BitReader *br);
+uint32_t FLAC__bitreader_limit_remaining(FLAC__BitReader *br);
+void FLAC__bitreader_limit_invalidate(FLAC__BitReader *br);
+
+/*
+ * read functions
+ */
+
+FLAC__bool FLAC__bitreader_read_raw_uint32(FLAC__BitReader *br, FLAC__uint32 *val, uint32_t bits);
+FLAC__bool FLAC__bitreader_read_raw_int32(FLAC__BitReader *br, FLAC__int32 *val, uint32_t bits);
+FLAC__bool FLAC__bitreader_read_raw_uint64(FLAC__BitReader *br, FLAC__uint64 *val, uint32_t bits);
+FLAC__bool FLAC__bitreader_read_raw_int64(FLAC__BitReader *br, FLAC__int64 *val, uint32_t 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, uint32_t 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, uint32_t nvals); /* WATCHOUT: does not CRC the read data! */
+FLAC__bool FLAC__bitreader_read_byte_block_aligned_no_crc(FLAC__BitReader *br, FLAC__byte *val, uint32_t nvals); /* WATCHOUT: does not CRC the read data! */
+FLAC__bool FLAC__bitreader_read_unary_unsigned(FLAC__BitReader *br, uint32_t *val);
+FLAC__bool FLAC__bitreader_read_rice_signed(FLAC__BitReader *br, int *val, uint32_t parameter);
+FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], uint32_t nvals, uint32_t parameter);
+#ifdef FLAC__BMI2_SUPPORTED
+FLAC__bool FLAC__bitreader_read_rice_signed_block_bmi2(FLAC__BitReader *br, int vals[], uint32_t nvals, uint32_t parameter);
+#endif
+
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitreader_read_golomb_signed(FLAC__BitReader *br, int *val, uint32_t parameter);
+FLAC__bool FLAC__bitreader_read_golomb_unsigned(FLAC__BitReader *br, uint32_t *val, uint32_t parameter);
+#endif
+FLAC__bool FLAC__bitreader_read_utf8_uint32(FLAC__BitReader *br, FLAC__uint32 *val, FLAC__byte *raw, uint32_t *rawlen);
+FLAC__bool FLAC__bitreader_read_utf8_uint64(FLAC__BitReader *br, FLAC__uint64 *val, FLAC__byte *raw, uint32_t *rawlen);
+#endif
diff --git a/src/libFLAC/include/private/bitwriter.h b/src/libFLAC/include/private/bitwriter.h
new file mode 100644
index 0000000..39bcf25
--- /dev/null
+++ b/src/libFLAC/include/private/bitwriter.h
@@ -0,0 +1,104 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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);
+
+/*
+ * 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);
+uint32_t 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, uint32_t bits);
+FLAC__bool FLAC__bitwriter_write_raw_uint32(FLAC__BitWriter *bw, FLAC__uint32 val, uint32_t bits);
+FLAC__bool FLAC__bitwriter_write_raw_int32(FLAC__BitWriter *bw, FLAC__int32 val, uint32_t bits);
+FLAC__bool FLAC__bitwriter_write_raw_uint64(FLAC__BitWriter *bw, FLAC__uint64 val, uint32_t bits);
+FLAC__bool FLAC__bitwriter_write_raw_int64(FLAC__BitWriter *bw, FLAC__int64 val, uint32_t 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[], uint32_t nvals);
+FLAC__bool FLAC__bitwriter_write_unary_unsigned(FLAC__BitWriter *bw, uint32_t val);
+#if 0 /* UNUSED */
+uint32_t FLAC__bitwriter_rice_bits(FLAC__int32 val, uint32_t parameter);
+uint32_t FLAC__bitwriter_golomb_bits_signed(int val, uint32_t parameter);
+uint32_t FLAC__bitwriter_golomb_bits_unsigned(uint32_t val, uint32_t parameter);
+FLAC__bool FLAC__bitwriter_write_rice_signed(FLAC__BitWriter *bw, FLAC__int32 val, uint32_t parameter);
+#endif
+FLAC__bool FLAC__bitwriter_write_rice_signed_block(FLAC__BitWriter *bw, const FLAC__int32 *vals, uint32_t nvals, uint32_t parameter);
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitwriter_write_golomb_signed(FLAC__BitWriter *bw, int val, uint32_t parameter);
+FLAC__bool FLAC__bitwriter_write_golomb_unsigned(FLAC__BitWriter *bw, uint32_t val, uint32_t 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
index 0000000..8843c74
--- /dev/null
+++ b/src/libFLAC/include/private/cpu.h
@@ -0,0 +1,198 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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
+
+#ifndef FLAC__CPU_X86_64
+
+#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
+#define FLAC__CPU_X86_64
+#endif
+
+#endif
+
+#ifndef FLAC__CPU_IA32
+
+#if defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) ||defined( __i386) || defined(_M_IX86)
+#define FLAC__CPU_IA32
+#endif
+
+#endif
+
+#ifndef __has_attribute
+#define __has_attribute(x) 0
+#endif
+
+#if FLAC__HAS_X86INTRIN
+/* SSE intrinsics support by ICC/MSVC/GCC */
+#if defined __INTEL_COMPILER
+ #define FLAC__SSE_TARGET(x)
+ #define FLAC__SSE_SUPPORTED 1
+ #define FLAC__SSE2_SUPPORTED 1
+ #if (__INTEL_COMPILER >= 1000) /* Intel C++ Compiler 10.0 */
+ #define FLAC__SSSE3_SUPPORTED 1
+ #define FLAC__SSE4_1_SUPPORTED 1
+ #define FLAC__SSE4_2_SUPPORTED 1
+ #endif
+ #ifdef FLAC__USE_AVX
+ #if (__INTEL_COMPILER >= 1110) /* Intel C++ Compiler 11.1 */
+ #define FLAC__AVX_SUPPORTED 1
+ #endif
+ #if (__INTEL_COMPILER >= 1300) /* Intel C++ Compiler 13.0 */
+ #define FLAC__AVX2_SUPPORTED 1
+ #define FLAC__FMA_SUPPORTED 1
+ #endif
+ #endif
+#elif defined __clang__ && __has_attribute(__target__) /* clang */
+ #define FLAC__SSE_TARGET(x) __attribute__ ((__target__ (x)))
+ #define FLAC__SSE_SUPPORTED 1
+ #define FLAC__SSE2_SUPPORTED 1
+ #define FLAC__SSSE3_SUPPORTED 1
+ #define FLAC__SSE4_1_SUPPORTED 1
+ #define FLAC__SSE4_2_SUPPORTED 1
+ #ifdef FLAC__USE_AVX
+ #define FLAC__AVX_SUPPORTED 1
+ #define FLAC__AVX2_SUPPORTED 1
+ #define FLAC__FMA_SUPPORTED 1
+ #define FLAC__BMI2_SUPPORTED 1
+ #endif
+#elif defined __GNUC__ && !defined __clang__ && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) /* GCC 4.9+ */
+ #define FLAC__SSE_TARGET(x) __attribute__ ((__target__ (x)))
+ #define FLAC__SSE_SUPPORTED 1
+ #define FLAC__SSE2_SUPPORTED 1
+ #define FLAC__SSSE3_SUPPORTED 1
+ #define FLAC__SSE4_1_SUPPORTED 1
+ #define FLAC__SSE4_2_SUPPORTED 1
+ #ifdef FLAC__USE_AVX
+ #define FLAC__AVX_SUPPORTED 1
+ #define FLAC__AVX2_SUPPORTED 1
+ #define FLAC__FMA_SUPPORTED 1
+ #define FLAC__BMI2_SUPPORTED 1
+ #endif
+#elif defined _MSC_VER
+ #define FLAC__SSE_TARGET(x)
+ #define FLAC__SSE_SUPPORTED 1
+ #define FLAC__SSE2_SUPPORTED 1
+ #if (_MSC_VER >= 1500) /* MS Visual Studio 2008 */
+ #define FLAC__SSSE3_SUPPORTED 1
+ #define FLAC__SSE4_1_SUPPORTED 1
+ #define FLAC__SSE4_2_SUPPORTED 1
+ #endif
+ #ifdef FLAC__USE_AVX
+ #if (_MSC_FULL_VER >= 160040219) /* MS Visual Studio 2010 SP1 */
+ #define FLAC__AVX_SUPPORTED 1
+ #endif
+ #if (_MSC_VER >= 1700) /* MS Visual Studio 2012 */
+ #define FLAC__AVX2_SUPPORTED 1
+ #define FLAC__FMA_SUPPORTED 1
+ #endif
+ #endif
+#else
+ #define FLAC__SSE_TARGET(x)
+ #ifdef __SSE__
+ #define FLAC__SSE_SUPPORTED 1
+ #endif
+ #ifdef __SSE2__
+ #define FLAC__SSE2_SUPPORTED 1
+ #endif
+ #ifdef __SSSE3__
+ #define FLAC__SSSE3_SUPPORTED 1
+ #endif
+ #ifdef __SSE4_1__
+ #define FLAC__SSE4_1_SUPPORTED 1
+ #endif
+ #ifdef __SSE4_2__
+ #define FLAC__SSE4_2_SUPPORTED 1
+ #endif
+ #ifdef FLAC__USE_AVX
+ #ifdef __AVX__
+ #define FLAC__AVX_SUPPORTED 1
+ #endif
+ #ifdef __AVX2__
+ #define FLAC__AVX2_SUPPORTED 1
+ #endif
+ #ifdef __FMA__
+ #define FLAC__FMA_SUPPORTED 1
+ #endif
+ #endif
+#endif /* compiler version */
+#endif /* intrinsics support */
+
+
+#ifndef FLAC__AVX_SUPPORTED
+#define FLAC__AVX_SUPPORTED 0
+#endif
+
+typedef enum {
+ FLAC__CPUINFO_TYPE_IA32,
+ FLAC__CPUINFO_TYPE_X86_64,
+ FLAC__CPUINFO_TYPE_UNKNOWN
+} FLAC__CPUInfo_Type;
+
+typedef struct {
+ FLAC__bool intel;
+
+ FLAC__bool cmov;
+ FLAC__bool mmx;
+ FLAC__bool sse;
+ FLAC__bool sse2;
+
+ FLAC__bool sse3;
+ FLAC__bool ssse3;
+ FLAC__bool sse41;
+ FLAC__bool sse42;
+ FLAC__bool avx;
+ FLAC__bool avx2;
+ FLAC__bool fma;
+ FLAC__bool bmi2;
+} FLAC__CPUInfo_x86;
+
+typedef struct {
+ FLAC__bool use_asm;
+ FLAC__CPUInfo_Type type;
+ FLAC__CPUInfo_x86 x86;
+} FLAC__CPUInfo;
+
+void FLAC__cpu_info(FLAC__CPUInfo *info);
+
+FLAC__uint32 FLAC__cpu_have_cpuid_asm_ia32(void);
+
+void FLAC__cpu_info_asm_ia32(FLAC__uint32 level, FLAC__uint32 *eax, FLAC__uint32 *ebx, FLAC__uint32 *ecx, FLAC__uint32 *edx);
+
+#endif
diff --git a/src/libFLAC/include/private/crc.h b/src/libFLAC/include/private/crc.h
new file mode 100644
index 0000000..fe44502
--- /dev/null
+++ b/src/libFLAC/include/private/crc.h
@@ -0,0 +1,60 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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
+*/
+FLAC__uint8 FLAC__crc8(const FLAC__byte *data, uint32_t len);
+
+/* 16 bit CRC generator, MSB shifted first
+** polynomial = x^16 + x^15 + x^2 + x^0
+** init = 0
+*/
+extern FLAC__uint16 const FLAC__crc16_table[8][256];
+
+#define FLAC__CRC16_UPDATE(data, crc) ((((crc)<<8) & 0xffff) ^ FLAC__crc16_table[0][((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[0][((crc)>>8) ^ (data)]) & 0xffff)
+#endif
+
+FLAC__uint16 FLAC__crc16(const FLAC__byte *data, uint32_t len);
+FLAC__uint16 FLAC__crc16_update_words32(const FLAC__uint32 *words, uint32_t len, FLAC__uint16 crc);
+FLAC__uint16 FLAC__crc16_update_words64(const FLAC__uint64 *words, uint32_t len, FLAC__uint16 crc);
+
+#endif
diff --git a/src/libFLAC/include/private/fixed.h b/src/libFLAC/include/private/fixed.h
new file mode 100644
index 0000000..c4efecd
--- /dev/null
+++ b/src/libFLAC/include/private/fixed.h
@@ -0,0 +1,117 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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/cpu.h"
+#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
+uint32_t FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+uint32_t FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+uint32_t FLAC__fixed_compute_best_predictor_limit_residual(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+uint32_t FLAC__fixed_compute_best_predictor_limit_residual_33bit(const FLAC__int64 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+# ifndef FLAC__NO_ASM
+# if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
+# ifdef FLAC__SSE2_SUPPORTED
+uint32_t FLAC__fixed_compute_best_predictor_intrin_sse2(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1]);
+# endif
+# ifdef FLAC__SSSE3_SUPPORTED
+uint32_t FLAC__fixed_compute_best_predictor_intrin_ssse3(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+# endif
+# ifdef FLAC__SSE4_2_SUPPORTED
+uint32_t FLAC__fixed_compute_best_predictor_limit_residual_intrin_sse42(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+# endif
+# ifdef FLAC__AVX2_SUPPORTED
+uint32_t FLAC__fixed_compute_best_predictor_wide_intrin_avx2(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+uint32_t FLAC__fixed_compute_best_predictor_limit_residual_intrin_avx2(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+# endif
+# endif
+# endif
+#else
+uint32_t FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+uint32_t FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+uint32_t FLAC__fixed_compute_best_predictor_limit_residual(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+uint32_t FLAC__fixed_compute_best_predictor_limit_residual_33bit(const FLAC__int64 data[], uint32_t 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[], uint32_t data_len, uint32_t order, FLAC__int32 residual[]);
+void FLAC__fixed_compute_residual_wide(const FLAC__int32 data[], uint32_t data_len, uint32_t order, FLAC__int32 residual[]);
+void FLAC__fixed_compute_residual_wide_33bit(const FLAC__int64 data[], uint32_t data_len, uint32_t 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[], uint32_t data_len, uint32_t order, FLAC__int32 data[]);
+void FLAC__fixed_restore_signal_wide(const FLAC__int32 residual[], uint32_t data_len, uint32_t order, FLAC__int32 data[]);
+void FLAC__fixed_restore_signal_wide_33bit(const FLAC__int32 residual[], uint32_t data_len, uint32_t order, FLAC__int64 data[]);
+
+#endif
diff --git a/src/libFLAC/include/private/float.h b/src/libFLAC/include/private/float.h
new file mode 100644
index 0000000..bec2634
--- /dev/null
+++ b/src/libFLAC/include/private/float.h
@@ -0,0 +1,95 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2004-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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"
+
+/*
+ * All the code in libFLAC that uses float and double
+ * should be protected by checks of the macro
+ * FLAC__INTEGER_ONLY_LIBRARY.
+ *
+ */
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+/*
+ * FLAC__real is the basic floating point type used in LPC analysis.
+ *
+ * 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 (uint32_t)(-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, uint32_t fracbits, uint32_t precision);
+
+#endif
+
+#endif
diff --git a/src/libFLAC/include/private/format.h b/src/libFLAC/include/private/format.h
new file mode 100644
index 0000000..7630f6f
--- /dev/null
+++ b/src/libFLAC/include/private/format.h
@@ -0,0 +1,47 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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"
+
+#if 0 /* UNUSED */
+uint32_t FLAC__format_get_max_rice_partition_order(uint32_t blocksize, uint32_t predictor_order);
+#endif
+uint32_t FLAC__format_get_max_rice_partition_order_from_blocksize(uint32_t blocksize);
+uint32_t FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(uint32_t limit, uint32_t blocksize, uint32_t 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, uint32_t max_partition_order);
+
+#endif
diff --git a/src/libFLAC/include/private/lpc.h b/src/libFLAC/include/private/lpc.h
new file mode 100644
index 0000000..766f056
--- /dev/null
+++ b/src/libFLAC/include/private/lpc.h
@@ -0,0 +1,238 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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/cpu.h"
+#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[], uint32_t data_len);
+void FLAC__lpc_window_data_wide(const FLAC__int64 in[], const FLAC__real window[], FLAC__real out[], uint32_t data_len);
+void FLAC__lpc_window_data_partial(const FLAC__int32 in[], const FLAC__real window[], FLAC__real out[], uint32_t data_len, uint32_t part_size, uint32_t data_shift);
+void FLAC__lpc_window_data_partial_wide(const FLAC__int64 in[], const FLAC__real window[], FLAC__real out[], uint32_t data_len, uint32_t part_size, uint32_t data_shift);
+
+/*
+ * 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[], uint32_t data_len, uint32_t lag, double autoc[]);
+#ifndef FLAC__NO_ASM
+# if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
+# ifdef FLAC__SSE2_SUPPORTED
+void FLAC__lpc_compute_autocorrelation_intrin_sse2_lag_8(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_sse2_lag_10(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_sse2_lag_14(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]);
+# endif
+# endif
+# if defined FLAC__CPU_X86_64 && FLAC__HAS_X86INTRIN
+# ifdef FLAC__FMA_SUPPORTED
+void FLAC__lpc_compute_autocorrelation_intrin_fma_lag_8(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_fma_lag_12(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_fma_lag_16(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]);
+# endif
+# endif
+#if defined FLAC__CPU_ARM64 && FLAC__HAS_NEONINTRIN && FLAC__HAS_A64NEONINTRIN
+void FLAC__lpc_compute_autocorrelation_intrin_neon_lag_8(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_neon_lag_10(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_neon_lag_14(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]);
+#endif
+#endif /* FLAC__NO_ASM */
+
+/*
+ * 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 double autoc[], uint32_t *max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], 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[], uint32_t order, uint32_t 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, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+FLAC__bool FLAC__lpc_compute_residual_from_qlp_coefficients_limit_residual(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+FLAC__bool FLAC__lpc_compute_residual_from_qlp_coefficients_limit_residual_33bit(const FLAC__int64 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+#ifndef FLAC__NO_ASM
+# ifdef FLAC__CPU_ARM64
+void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_neon(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_neon(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+# endif
+
+# if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
+# ifdef FLAC__SSE2_SUPPORTED
+void FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_sse2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+# endif
+# ifdef FLAC__SSE4_1_SUPPORTED
+void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse41(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_sse41(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+# endif
+# ifdef FLAC__AVX2_SUPPORTED
+void FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_avx2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_avx2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_avx2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+# endif
+# endif
+#endif
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
+
+uint32_t FLAC__lpc_max_prediction_before_shift_bps(uint32_t subframe_bps, const FLAC__int32 qlp_coeff[], uint32_t order);
+uint32_t FLAC__lpc_max_residual_bps(uint32_t subframe_bps, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization);
+
+/*
+ * 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[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+void FLAC__lpc_restore_signal_wide(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+void FLAC__lpc_restore_signal_wide_33bit(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int64 data[]);
+
+#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
+ */
+double FLAC__lpc_compute_expected_bits_per_residual_sample(double lpc_error, uint32_t total_samples);
+double FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(double lpc_error, 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
+ */
+uint32_t FLAC__lpc_compute_best_order(const double lpc_error[], uint32_t max_order, uint32_t total_samples, uint32_t overhead_bits_per_order);
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
+
+#endif
diff --git a/src/libFLAC/include/private/macros.h b/src/libFLAC/include/private/macros.h
new file mode 100644
index 0000000..8204ed5
--- /dev/null
+++ b/src/libFLAC/include/private/macros.h
@@ -0,0 +1,74 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2012-2023 Xiph.Org Foundation
+ *
+ * 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__MACROS_H
+#define FLAC__PRIVATE__MACROS_H
+
+#if defined(__GNUC__) && (__GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 3))
+
+#define flac_max(a,b) \
+ ({ __typeof__ (a) _a = (a); \
+ __typeof__ (b) _b = (b); \
+ _a > _b ? _a : _b; })
+
+#define MIN_PASTE(A,B) A##B
+#define MIN_IMPL(A,B,L) ({ \
+ __typeof__(A) MIN_PASTE(__a,L) = (A); \
+ __typeof__(B) MIN_PASTE(__b,L) = (B); \
+ MIN_PASTE(__a,L) < MIN_PASTE(__b,L) ? MIN_PASTE(__a,L) : MIN_PASTE(__b,L); \
+ })
+
+#define flac_min(A,B) MIN_IMPL(A,B,__COUNTER__)
+
+/* Whatever other unix that has sys/param.h */
+#elif defined(HAVE_SYS_PARAM_H)
+#include <sys/param.h>
+#if defined(MIN) && defined(MAX)
+#define flac_max(a,b) MAX(a,b)
+#define flac_min(a,b) MIN(a,b)
+#endif
+
+/* Windows VS has them in stdlib.h.. XXX:Untested */
+#elif defined(_MSC_VER)
+#include <stdlib.h>
+#define flac_max(a,b) __max(a,b)
+#define flac_min(a,b) __min(a,b)
+#endif
+
+#ifndef flac_min
+#define flac_min(x,y) ((x) <= (y) ? (x) : (y))
+#endif
+
+#ifndef flac_max
+#define flac_max(x,y) ((x) >= (y) ? (x) : (y))
+#endif
+
+#endif
diff --git a/src/libFLAC/include/private/md5.h b/src/libFLAC/include/private/md5.h
new file mode 100644
index 0000000..f9d79c3
--- /dev/null
+++ b/src/libFLAC/include/private/md5.h
@@ -0,0 +1,50 @@
+#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 union {
+ FLAC__byte *p8;
+ FLAC__int16 *p16;
+ FLAC__int32 *p32;
+} FLAC__multibyte;
+
+typedef struct {
+ FLAC__uint32 in[16];
+ FLAC__uint32 buf[4];
+ FLAC__uint32 bytes[2];
+ FLAC__multibyte 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[], uint32_t channels, uint32_t samples, uint32_t bytes_per_sample);
+
+#endif
diff --git a/src/libFLAC/include/private/memory.h b/src/libFLAC/include/private/memory.h
new file mode 100644
index 0000000..4221bcf
--- /dev/null
+++ b/src/libFLAC/include/private/memory.h
@@ -0,0 +1,58 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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(size_t elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_pointer);
+FLAC__bool FLAC__memory_alloc_aligned_uint32_array(size_t elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_pointer);
+FLAC__bool FLAC__memory_alloc_aligned_int64_array(size_t elements, FLAC__int64 **unaligned_pointer, FLAC__int64 **aligned_pointer);
+FLAC__bool FLAC__memory_alloc_aligned_uint64_array(size_t elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_pointer);
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+FLAC__bool FLAC__memory_alloc_aligned_real_array(size_t elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer);
+#endif
+void *safe_malloc_mul_2op_p(size_t size1, size_t size2);
+
+#endif
diff --git a/src/libFLAC/include/private/metadata.h b/src/libFLAC/include/private/metadata.h
new file mode 100644
index 0000000..d3ceb53
--- /dev/null
+++ b/src/libFLAC/include/private/metadata.h
@@ -0,0 +1,46 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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
index 0000000..c923641
--- /dev/null
+++ b/src/libFLAC/include/private/ogg_decoder_aspect.h
@@ -0,0 +1,80 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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;
+ uint32_t 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
index 0000000..0e9bb4b
--- /dev/null
+++ b/src/libFLAC/include/private/ogg_encoder_aspect.h
@@ -0,0 +1,63 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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;
+ uint32_t 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, uint32_t 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, uint32_t samples, uint32_t current_frame, void *client_data);
+
+FLAC__StreamEncoderWriteStatus FLAC__ogg_encoder_aspect_write_callback_wrapper(FLAC__OggEncoderAspect *aspect, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t 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
index 0000000..6768578
--- /dev/null
+++ b/src/libFLAC/include/private/ogg_helper.h
@@ -0,0 +1,44 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2004-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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
index 0000000..1a213a4
--- /dev/null
+++ b/src/libFLAC/include/private/ogg_mapping.h
@@ -0,0 +1,64 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2004-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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 packet type field in bytes. */
+#define FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH (1u)
+
+extern const uint32_t 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 uint32_t FLAC__OGG_MAPPING_VERSION_MAJOR_LEN; /* = 8 bits */
+extern const uint32_t 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 uint32_t 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.h b/src/libFLAC/include/private/stream_encoder.h
new file mode 100644
index 0000000..0a1b672
--- /dev/null
+++ b/src/libFLAC/include/private/stream_encoder.h
@@ -0,0 +1,67 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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_H
+#define FLAC__PRIVATE__STREAM_ENCODER_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/*
+ * This is used to avoid overflow with unusual signals in 32-bit
+ * accumulator in the *precompute_partition_info_sums_* functions.
+ */
+#define FLAC__MAX_EXTRA_RESIDUAL_BPS 4
+
+#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN
+#include "private/cpu.h"
+#include "FLAC/format.h"
+
+#ifdef FLAC__SSE2_SUPPORTED
+extern void FLAC__precompute_partition_info_sums_intrin_sse2(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[],
+ uint32_t residual_samples, uint32_t predictor_order, uint32_t min_partition_order, uint32_t max_partition_order, uint32_t bps);
+#endif
+
+#ifdef FLAC__SSSE3_SUPPORTED
+extern void FLAC__precompute_partition_info_sums_intrin_ssse3(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[],
+ uint32_t residual_samples, uint32_t predictor_order, uint32_t min_partition_order, uint32_t max_partition_order, uint32_t bps);
+#endif
+
+#ifdef FLAC__AVX2_SUPPORTED
+extern void FLAC__precompute_partition_info_sums_intrin_avx2(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[],
+ uint32_t residual_samples, uint32_t predictor_order, uint32_t min_partition_order, uint32_t max_partition_order, uint32_t bps);
+#endif
+
+#endif
+
+#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
index 0000000..705965a
--- /dev/null
+++ b/src/libFLAC/include/private/stream_encoder_framing.h
@@ -0,0 +1,46 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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 update_vendor_string);
+FLAC__bool FLAC__frame_add_header(const FLAC__FrameHeader *header, FLAC__BitWriter *bw);
+FLAC__bool FLAC__subframe_add_constant(const FLAC__Subframe_Constant *subframe, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw);
+FLAC__bool FLAC__subframe_add_fixed(const FLAC__Subframe_Fixed *subframe, uint32_t residual_samples, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw);
+FLAC__bool FLAC__subframe_add_lpc(const FLAC__Subframe_LPC *subframe, uint32_t residual_samples, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw);
+FLAC__bool FLAC__subframe_add_verbatim(const FLAC__Subframe_Verbatim *subframe, uint32_t samples, uint32_t subframe_bps, uint32_t 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
index 0000000..87a3fdf
--- /dev/null
+++ b/src/libFLAC/include/private/window.h
@@ -0,0 +1,74 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2006-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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_partial_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end);
+void FLAC__window_punchout_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end);
+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
index 0000000..97e85a8
--- /dev/null
+++ b/src/libFLAC/include/protected/Makefile.am
@@ -0,0 +1,35 @@
+# libFLAC - Free Lossless Audio Codec library
+# Copyright (C) 2001-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# 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/Makefile.in b/src/libFLAC/include/protected/Makefile.in
new file mode 100644
index 0000000..5b2e4af
--- /dev/null
+++ b/src/libFLAC/include/protected/Makefile.in
@@ -0,0 +1,581 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in 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.
+
+@SET_MAKE@
+
+# libFLAC - Free Lossless Audio Codec library
+# Copyright (C) 2001-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# 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.
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/libFLAC/include/protected
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/add_cflags.m4 \
+ $(top_srcdir)/m4/add_cxxflags.m4 \
+ $(top_srcdir)/m4/ax_add_fortify_source.m4 \
+ $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_enable_debug.m4 \
+ $(top_srcdir)/m4/bswap.m4 $(top_srcdir)/m4/clang.m4 \
+ $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gcc_version.m4 \
+ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/ogg.m4 \
+ $(top_srcdir)/m4/really_gcc.m4 \
+ $(top_srcdir)/m4/stack_protect.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_64_BIT_WORDS = @ENABLE_64_BIT_WORDS@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLAC__HAS_OGG = @FLAC__HAS_OGG@
+FLAC__TEST_LEVEL = @FLAC__TEST_LEVEL@
+FLAC__TEST_WITH_VALGRIND = @FLAC__TEST_WITH_VALGRIND@
+GCC_MAJOR_VERSION = @GCC_MAJOR_VERSION@
+GCC_MINOR_VERSION = @GCC_MINOR_VERSION@
+GCC_VERSION = @GCC_VERSION@
+GIT_COMMIT_VERSION_HASH = @GIT_COMMIT_VERSION_HASH@
+GIT_FOUND = @GIT_FOUND@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_FUZZING_ENGINE = @LIB_FUZZING_ENGINE@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OBJ_FORMAT = @OBJ_FORMAT@
+OGG_CFLAGS = @OGG_CFLAGS@
+OGG_LIBS = @OGG_LIBS@
+OGG_PACKAGE = @OGG_PACKAGE@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_HEADERS = \
+ all.h \
+ stream_decoder.h \
+ stream_encoder.h
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/libFLAC/include/protected/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/libFLAC/include/protected/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool cscopelist-am ctags ctags-am distclean \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/libFLAC/include/protected/all.h b/src/libFLAC/include/protected/all.h
new file mode 100644
index 0000000..9f6de97
--- /dev/null
+++ b/src/libFLAC/include/protected/all.h
@@ -0,0 +1,39 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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
index 0000000..4a9c768
--- /dev/null
+++ b/src/libFLAC/include/protected/stream_decoder.h
@@ -0,0 +1,60 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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;
+ FLAC__StreamDecoderInitStatus initstate;
+ uint32_t channels;
+ FLAC__ChannelAssignment channel_assignment;
+ uint32_t bits_per_sample;
+ uint32_t sample_rate; /* in Hz */
+ uint32_t 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
+ */
+uint32_t 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
index 0000000..863e43b
--- /dev/null
+++ b/src/libFLAC/include/protected/stream_encoder.h
@@ -0,0 +1,124 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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_PARTIAL_TUKEY,
+ FLAC__APODIZATION_PUNCHOUT_TUKEY,
+ FLAC__APODIZATION_SUBDIVIDE_TUKEY,
+ FLAC__APODIZATION_WELCH
+} FLAC__ApodizationFunction;
+
+typedef struct {
+ FLAC__ApodizationFunction type;
+ union {
+ struct {
+ FLAC__real stddev;
+ } gauss;
+ struct {
+ FLAC__real p;
+ } tukey;
+ struct {
+ FLAC__real p;
+ FLAC__real start;
+ FLAC__real end;
+ } multiple_tukey;
+ struct {
+ FLAC__real p;
+ FLAC__int32 parts;
+ } subdivide_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;
+ uint32_t channels;
+ uint32_t bits_per_sample;
+ uint32_t sample_rate;
+ uint32_t blocksize;
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+ uint32_t num_apodizations;
+ FLAC__ApodizationSpecification apodizations[FLAC__MAX_APODIZATION_FUNCTIONS];
+#endif
+ uint32_t max_lpc_order;
+ uint32_t qlp_coeff_precision;
+ FLAC__bool do_qlp_coeff_prec_search;
+ FLAC__bool do_exhaustive_model_search;
+ FLAC__bool do_escape_coding;
+ uint32_t min_residual_partition_order;
+ uint32_t max_residual_partition_order;
+ uint32_t rice_parameter_search_dist;
+ FLAC__uint64 total_samples_estimate;
+ FLAC__bool limit_min_bitrate;
+ FLAC__StreamMetadata **metadata;
+ uint32_t 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
index 0000000..5dfc5ea
--- /dev/null
+++ b/src/libFLAC/libFLAC.m4
@@ -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_LIBS="-L$libFLAC_libraries"
+ elif test "x$libFLAC_prefix" = "xno" || test "x$libFLAC_prefix" = "xyes" ; then
+ LIBFLAC_LIBS=""
+ elif test "x$libFLAC_prefix" != "x" ; then
+ LIBFLAC_LIBS="-L$libFLAC_prefix/lib"
+ elif test "x$prefix" != "xNONE"; then
+ LIBFLAC_LIBS="-L$prefix/lib"
+ fi
+
+ if test "x$libFLAC_prefix" != "xno" ; then
+ LIBFLAC_LIBS="$LIBFLAC_LIBS -lFLAC $OGG_LIBS -lm"
+ fi
+
+ 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_RUN_IFELSE([AC_LANG_PROGRAM([[
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <FLAC/format.h>
+]],[[
+ 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 occurred. 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/lpc.c b/src/libFLAC/lpc.c
new file mode 100644
index 0000000..bcb8673
--- /dev/null
+++ b/src/libFLAC/lpc.c
@@ -0,0 +1,1629 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "FLAC/assert.h"
+#include "FLAC/format.h"
+#include "share/compat.h"
+#include "private/bitmath.h"
+#include "private/lpc.h"
+#include "private/macros.h"
+
+#if !defined(NDEBUG) || defined FLAC__OVERFLOW_DETECT || defined FLAC__OVERFLOW_DETECT_VERBOSE
+#include <stdio.h>
+#endif
+
+/* OPT: #undef'ing this may improve the speed on some architectures */
+#define FLAC__LPC_UNROLLED_FILTER_LOOPS
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+#if defined(_MSC_VER) && (_MSC_VER < 1800)
+#include <float.h>
+static inline long int lround(double x) {
+ return (long)(x + _copysign(0.5, x));
+}
+#elif !defined(HAVE_LROUND) && defined(__GNUC__)
+static inline long int lround(double x) {
+ return (long)(x + __builtin_copysign(0.5, x));
+}
+/* If this fails, we are in the presence of a mid 90's compiler, move along... */
+#endif
+
+void FLAC__lpc_window_data(const FLAC__int32 in[], const FLAC__real window[], FLAC__real out[], uint32_t data_len)
+{
+ uint32_t i;
+ for(i = 0; i < data_len; i++)
+ out[i] = in[i] * window[i];
+}
+
+void FLAC__lpc_window_data_wide(const FLAC__int64 in[], const FLAC__real window[], FLAC__real out[], uint32_t data_len)
+{
+ uint32_t i;
+ for(i = 0; i < data_len; i++)
+ out[i] = in[i] * window[i];
+}
+
+void FLAC__lpc_window_data_partial(const FLAC__int32 in[], const FLAC__real window[], FLAC__real out[], uint32_t data_len, uint32_t part_size, uint32_t data_shift)
+{
+ uint32_t i, j;
+ if((part_size + data_shift) < data_len){
+ for(i = 0; i < part_size; i++)
+ out[i] = in[data_shift+i] * window[i];
+ i = flac_min(i,data_len - part_size - data_shift);
+ for(j = data_len - part_size; j < data_len; i++, j++)
+ out[i] = in[data_shift+i] * window[j];
+ if(i < data_len)
+ out[i] = 0.0f;
+ }
+}
+
+void FLAC__lpc_window_data_partial_wide(const FLAC__int64 in[], const FLAC__real window[], FLAC__real out[], uint32_t data_len, uint32_t part_size, uint32_t data_shift)
+{
+ uint32_t i, j;
+ if((part_size + data_shift) < data_len){
+ for(i = 0; i < part_size; i++)
+ out[i] = in[data_shift+i] * window[i];
+ i = flac_min(i,data_len - part_size - data_shift);
+ for(j = data_len - part_size; j < data_len; i++, j++)
+ out[i] = in[data_shift+i] * window[j];
+ if(i < data_len)
+ out[i] = 0.0f;
+ }
+}
+
+void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[])
+{
+ /* a readable, but slower, version */
+#if 0
+ double d;
+ uint32_t 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] * (double)data[i - lag];
+ autoc[lag] = d;
+ }
+#endif
+ if (data_len < FLAC__MAX_LPC_ORDER || lag > 16) {
+ /*
+ * this version tends to run faster because of better data locality
+ * ('data_len' is usually much larger than 'lag')
+ */
+ double d;
+ uint32_t sample, coeff;
+ const uint32_t 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];
+ }
+ }
+ else if(lag <= 8) {
+ #undef MAX_LAG
+ #define MAX_LAG 8
+ #include "deduplication/lpc_compute_autocorrelation_intrin.c"
+ }
+ else if(lag <= 12) {
+ #undef MAX_LAG
+ #define MAX_LAG 12
+ #include "deduplication/lpc_compute_autocorrelation_intrin.c"
+ }
+ else if(lag <= 16) {
+ #undef MAX_LAG
+ #define MAX_LAG 16
+ #include "deduplication/lpc_compute_autocorrelation_intrin.c"
+ }
+
+}
+
+void FLAC__lpc_compute_lp_coefficients(const double autoc[], uint32_t *max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], double error[])
+{
+ uint32_t i, j;
+ double r, err, 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];
+ r /= err;
+
+ /* Update LPC coefficients and total error. */
+ lpc[i]=r;
+ for(j = 0; j < (i>>1); j++) {
+ 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 https://sourceforge.net/p/flac/bugs/234/ */
+ if(err == 0.0) {
+ *max_order = i+1;
+ return;
+ }
+ }
+}
+
+int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], uint32_t order, uint32_t precision, FLAC__int32 qlp_coeff[], int *shift)
+{
+ uint32_t i;
+ 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 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) {
+ double error = 0.0;
+ FLAC__int32 q;
+ for(i = 0; i < order; i++) {
+ error += lp_coeff[i] * (1 << *shift);
+ q = lround(error);
+
+#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
+ * not allowed in the decoder, so it must be handled specially by scaling
+ * down coeffs
+ */
+ else {
+ const int nshift = -(*shift);
+ double error = 0.0;
+ FLAC__int32 q;
+#ifndef NDEBUG
+ 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);
+ q = lround(error);
+#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;
+}
+
+#if defined(_MSC_VER)
+// silence MSVC warnings about __restrict modifier
+#pragma warning ( disable : 4028 )
+#endif
+
+void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 * flac_restrict data, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict residual)
+#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS)
+{
+ FLAC__int64 sumo;
+ uint32_t 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(sumo > 2147483647ll || sumo < -2147483648ll)
+ fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%" PRId64 "\n",i,j,qlp_coeff[j],*history,sumo);
+ }
+ *(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]; /* Falls through. */
+ case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */
+ case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */
+ case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */
+ case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */
+ case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */
+ case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */
+ case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */
+ case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */
+ case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */
+ case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */
+ case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */
+ case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */
+ case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */
+ case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */
+ case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */
+ case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */
+ case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */
+ case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */
+ 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 * flac_restrict data, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict residual)
+#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS)
+{
+ uint32_t 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((FLAC__int64)(*data) - (sum >> lp_quantization)) > 32) {
+ fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, data=%d, sum=%" PRId64 ", residual=%" PRId64 "\n", i, *data, (int64_t)(sum >> lp_quantization), ((FLAC__int64)(*data) - (sum >> lp_quantization)));
+ 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] - (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] - (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] - (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] - (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] - (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] - (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] - (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] - (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] - (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] - (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] - (sum >> lp_quantization);
+ }
+ }
+ else { /* order == 1 */
+ for(i = 0; i < (int)data_len; i++)
+ residual[i] = data[i] - ((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]; /* Falls through. */
+ case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31]; /* Falls through. */
+ case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30]; /* Falls through. */
+ case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29]; /* Falls through. */
+ case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28]; /* Falls through. */
+ case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27]; /* Falls through. */
+ case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26]; /* Falls through. */
+ case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25]; /* Falls through. */
+ case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24]; /* Falls through. */
+ case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23]; /* Falls through. */
+ case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22]; /* Falls through. */
+ case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21]; /* Falls through. */
+ case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20]; /* Falls through. */
+ case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19]; /* Falls through. */
+ case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18]; /* Falls through. */
+ case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17]; /* Falls through. */
+ case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16]; /* Falls through. */
+ case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15]; /* Falls through. */
+ case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14]; /* Falls through. */
+ 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] - (sum >> lp_quantization);
+ }
+ }
+}
+#endif
+
+FLAC__bool FLAC__lpc_compute_residual_from_qlp_coefficients_limit_residual(const FLAC__int32 * flac_restrict data, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict residual)
+{
+ int i;
+ FLAC__int64 sum, residual_to_check;
+
+ FLAC__ASSERT(order > 0);
+ FLAC__ASSERT(order <= 32);
+
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ switch(order) {
+ case 32: sum += qlp_coeff[31] * (FLAC__int64)data[i-32]; /* Falls through. */
+ case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31]; /* Falls through. */
+ case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30]; /* Falls through. */
+ case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29]; /* Falls through. */
+ case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28]; /* Falls through. */
+ case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27]; /* Falls through. */
+ case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26]; /* Falls through. */
+ case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25]; /* Falls through. */
+ case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24]; /* Falls through. */
+ case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23]; /* Falls through. */
+ case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22]; /* Falls through. */
+ case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21]; /* Falls through. */
+ case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20]; /* Falls through. */
+ case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19]; /* Falls through. */
+ case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18]; /* Falls through. */
+ case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17]; /* Falls through. */
+ case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16]; /* Falls through. */
+ case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15]; /* Falls through. */
+ case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14]; /* Falls through. */
+ case 13: sum += qlp_coeff[12] * (FLAC__int64)data[i-13]; /* Falls through. */
+ case 12: sum += qlp_coeff[11] * (FLAC__int64)data[i-12]; /* Falls through. */
+ case 11: sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; /* Falls through. */
+ case 10: sum += qlp_coeff[ 9] * (FLAC__int64)data[i-10]; /* Falls through. */
+ case 9: sum += qlp_coeff[ 8] * (FLAC__int64)data[i- 9]; /* Falls through. */
+ case 8: sum += qlp_coeff[ 7] * (FLAC__int64)data[i- 8]; /* Falls through. */
+ case 7: sum += qlp_coeff[ 6] * (FLAC__int64)data[i- 7]; /* Falls through. */
+ case 6: sum += qlp_coeff[ 5] * (FLAC__int64)data[i- 6]; /* Falls through. */
+ case 5: sum += qlp_coeff[ 4] * (FLAC__int64)data[i- 5]; /* Falls through. */
+ case 4: sum += qlp_coeff[ 3] * (FLAC__int64)data[i- 4]; /* Falls through. */
+ case 3: sum += qlp_coeff[ 2] * (FLAC__int64)data[i- 3]; /* Falls through. */
+ case 2: sum += qlp_coeff[ 1] * (FLAC__int64)data[i- 2]; /* Falls through. */
+ case 1: sum += qlp_coeff[ 0] * (FLAC__int64)data[i- 1];
+ }
+ residual_to_check = data[i] - (sum >> lp_quantization);
+ /* residual must not be INT32_MIN because abs(INT32_MIN) is undefined */
+ if(residual_to_check <= INT32_MIN || residual_to_check > INT32_MAX)
+ return false;
+ else
+ residual[i] = residual_to_check;
+ }
+ return true;
+}
+
+FLAC__bool FLAC__lpc_compute_residual_from_qlp_coefficients_limit_residual_33bit(const FLAC__int64 * flac_restrict data, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict residual)
+{
+ int i;
+ FLAC__int64 sum, residual_to_check;
+
+ FLAC__ASSERT(order > 0);
+ FLAC__ASSERT(order <= 32);
+
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ switch(order) {
+ case 32: sum += qlp_coeff[31] * data[i-32]; /* Falls through. */
+ case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */
+ case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */
+ case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */
+ case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */
+ case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */
+ case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */
+ case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */
+ case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */
+ case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */
+ case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */
+ case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */
+ case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */
+ case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */
+ case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */
+ case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */
+ case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */
+ case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */
+ case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */
+ case 13: sum += qlp_coeff[12] * data[i-13]; /* Falls through. */
+ case 12: sum += qlp_coeff[11] * data[i-12]; /* Falls through. */
+ case 11: sum += qlp_coeff[10] * data[i-11]; /* Falls through. */
+ case 10: sum += qlp_coeff[ 9] * data[i-10]; /* Falls through. */
+ case 9: sum += qlp_coeff[ 8] * data[i- 9]; /* Falls through. */
+ case 8: sum += qlp_coeff[ 7] * data[i- 8]; /* Falls through. */
+ case 7: sum += qlp_coeff[ 6] * data[i- 7]; /* Falls through. */
+ case 6: sum += qlp_coeff[ 5] * data[i- 6]; /* Falls through. */
+ case 5: sum += qlp_coeff[ 4] * data[i- 5]; /* Falls through. */
+ case 4: sum += qlp_coeff[ 3] * data[i- 4]; /* Falls through. */
+ case 3: sum += qlp_coeff[ 2] * data[i- 3]; /* Falls through. */
+ case 2: sum += qlp_coeff[ 1] * data[i- 2]; /* Falls through. */
+ case 1: sum += qlp_coeff[ 0] * data[i- 1];
+ }
+ residual_to_check = data[i] - (sum >> lp_quantization);
+ /* residual must not be INT32_MIN because abs(INT32_MIN) is undefined */
+ if(residual_to_check <= INT32_MIN || residual_to_check > INT32_MAX)
+ return false;
+ else
+ residual[i] = residual_to_check;
+ }
+ return true;
+}
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
+
+uint32_t FLAC__lpc_max_prediction_before_shift_bps(uint32_t subframe_bps, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order)
+{
+ /* This used to be subframe_bps + qlp_coeff_precision + FLAC__bitmath_ilog2(order)
+ * but that treats both the samples as well as the predictor as unknown. The
+ * predictor is known however, so taking the log2 of the sum of the absolute values
+ * of all coefficients is a more accurate representation of the predictor */
+ FLAC__int32 abs_sum_of_qlp_coeff = 0;
+ uint32_t i;
+ for(i = 0; i < order; i++)
+ abs_sum_of_qlp_coeff += abs(qlp_coeff[i]);
+ if(abs_sum_of_qlp_coeff == 0)
+ abs_sum_of_qlp_coeff = 1;
+ return subframe_bps + FLAC__bitmath_silog2(abs_sum_of_qlp_coeff);
+}
+
+
+uint32_t FLAC__lpc_max_residual_bps(uint32_t subframe_bps, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization)
+{
+ FLAC__int32 predictor_sum_bps = FLAC__lpc_max_prediction_before_shift_bps(subframe_bps, qlp_coeff, order) - lp_quantization;
+ if((int)subframe_bps > predictor_sum_bps)
+ return subframe_bps + 1;
+ else
+ return predictor_sum_bps + 1;
+}
+
+#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && !defined(FUZZING_BUILD_MODE_FLAC_SANITIZE_SIGNED_INTEGER_OVERFLOW)
+/* The attribute below is to silence the undefined sanitizer of oss-fuzz.
+ * Because fuzzing feeds bogus predictors and residual samples to the
+ * decoder, having overflows in this section is unavoidable. Also,
+ * because the calculated values are audio path only, there is no
+ * potential for security problems */
+__attribute__((no_sanitize("signed-integer-overflow")))
+#endif
+void FLAC__lpc_restore_signal(const FLAC__int32 * flac_restrict residual, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict data)
+#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS)
+{
+ FLAC__int64 sumo;
+ uint32_t 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);
+#ifdef FLAC__OVERFLOW_DETECT
+ if(sumo > 2147483647ll || sumo < -2147483648ll)
+ fprintf(stderr,"FLAC__lpc_restore_signal: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%" PRId64 "\n",i,j,qlp_coeff[j],*history,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]; /* Falls through. */
+ case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */
+ case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */
+ case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */
+ case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */
+ case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */
+ case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */
+ case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */
+ case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */
+ case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */
+ case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */
+ case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */
+ case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */
+ case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */
+ case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */
+ case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */
+ case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */
+ case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */
+ case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */
+ 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 * flac_restrict residual, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict data)
+#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS)
+{
+ uint32_t 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));
+#ifdef FLAC__OVERFLOW_DETECT
+ if(FLAC__bitmath_silog2((FLAC__int64)(*r) + (sum >> lp_quantization)) > 32) {
+ fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, residual=%d, sum=%" PRId64 ", data=%" PRId64 "\n", i, *r, (sum >> lp_quantization), ((FLAC__int64)(*r) + (sum >> lp_quantization)));
+ break;
+ }
+#endif
+ *(data++) = (FLAC__int32)(*(r++) + (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] = (FLAC__int32) (residual[i] + (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] = (FLAC__int32) (residual[i] + (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] = (FLAC__int32) (residual[i] + (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] = (FLAC__int32) (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] * (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] = (FLAC__int32) (residual[i] + (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] = (FLAC__int32) (residual[i] + (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] = (FLAC__int32) (residual[i] + (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] = (FLAC__int32) (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] * (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] = (FLAC__int32) (residual[i] + (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] = (FLAC__int32) (residual[i] + (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] = (FLAC__int32) (residual[i] + (sum >> lp_quantization));
+ }
+ }
+ else { /* order == 1 */
+ for(i = 0; i < (int)data_len; i++)
+ data[i] = (FLAC__int32)(residual[i] + ((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]; /* Falls through. */
+ case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31]; /* Falls through. */
+ case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30]; /* Falls through. */
+ case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29]; /* Falls through. */
+ case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28]; /* Falls through. */
+ case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27]; /* Falls through. */
+ case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26]; /* Falls through. */
+ case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25]; /* Falls through. */
+ case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24]; /* Falls through. */
+ case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23]; /* Falls through. */
+ case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22]; /* Falls through. */
+ case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21]; /* Falls through. */
+ case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20]; /* Falls through. */
+ case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19]; /* Falls through. */
+ case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18]; /* Falls through. */
+ case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17]; /* Falls through. */
+ case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16]; /* Falls through. */
+ case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15]; /* Falls through. */
+ case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14]; /* Falls through. */
+ 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] = (FLAC__int32) (residual[i] + (sum >> lp_quantization));
+ }
+ }
+}
+#endif
+
+#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && !defined(FUZZING_BUILD_MODE_FLAC_SANITIZE_SIGNED_INTEGER_OVERFLOW)
+/* The attribute below is to silence the undefined sanitizer of oss-fuzz.
+ * Because fuzzing feeds bogus predictors and residual samples to the
+ * decoder, having overflows in this section is unavoidable. Also,
+ * because the calculated values are audio path only, there is no
+ * potential for security problems */
+__attribute__((no_sanitize("signed-integer-overflow")))
+#endif
+void FLAC__lpc_restore_signal_wide_33bit(const FLAC__int32 * flac_restrict residual, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int64 * flac_restrict data)
+#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS)
+{
+ uint32_t i, j;
+ FLAC__int64 sum;
+ const FLAC__int32 *r = residual;
+ const FLAC__int64 *history;
+
+ 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));
+#ifdef FLAC__OVERFLOW_DETECT
+ if(FLAC__bitmath_silog2((FLAC__int64)(*r) + (sum >> lp_quantization)) > 33) {
+ fprintf(stderr,"FLAC__lpc_restore_signal_33bit: OVERFLOW, i=%u, residual=%d, sum=%" PRId64 ", data=%" PRId64 "\n", i, *r, (sum >> lp_quantization), ((FLAC__int64)(*r) + (sum >> lp_quantization)));
+ break;
+ }
+#endif
+ *(data++) = (FLAC__int64)(*(r++)) + (sum >> lp_quantization);
+ }
+}
+#else /* unrolled version for normal use */
+{
+ int i;
+ FLAC__int64 sum;
+
+ FLAC__ASSERT(order > 0);
+ FLAC__ASSERT(order <= 32);
+
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ switch(order) {
+ case 32: sum += qlp_coeff[31] * data[i-32]; /* Falls through. */
+ case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */
+ case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */
+ case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */
+ case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */
+ case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */
+ case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */
+ case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */
+ case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */
+ case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */
+ case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */
+ case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */
+ case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */
+ case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */
+ case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */
+ case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */
+ case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */
+ case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */
+ case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */
+ case 13: sum += qlp_coeff[12] * data[i-13]; /* Falls through. */
+ case 12: sum += qlp_coeff[11] * data[i-12]; /* Falls through. */
+ case 11: sum += qlp_coeff[10] * data[i-11]; /* Falls through. */
+ case 10: sum += qlp_coeff[ 9] * data[i-10]; /* Falls through. */
+ case 9: sum += qlp_coeff[ 8] * data[i- 9]; /* Falls through. */
+ case 8: sum += qlp_coeff[ 7] * data[i- 8]; /* Falls through. */
+ case 7: sum += qlp_coeff[ 6] * data[i- 7]; /* Falls through. */
+ case 6: sum += qlp_coeff[ 5] * data[i- 6]; /* Falls through. */
+ case 5: sum += qlp_coeff[ 4] * data[i- 5]; /* Falls through. */
+ case 4: sum += qlp_coeff[ 3] * data[i- 4]; /* Falls through. */
+ case 3: sum += qlp_coeff[ 2] * data[i- 3]; /* Falls through. */
+ case 2: sum += qlp_coeff[ 1] * data[i- 2]; /* Falls through. */
+ case 1: sum += qlp_coeff[ 0] * data[i- 1];
+ }
+ data[i] = residual[i] + (sum >> lp_quantization);
+ }
+}
+#endif
+
+#if defined(_MSC_VER)
+#pragma warning ( default : 4028 )
+#endif
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+double FLAC__lpc_compute_expected_bits_per_residual_sample(double lpc_error, uint32_t total_samples)
+{
+ double error_scale;
+
+ FLAC__ASSERT(total_samples > 0);
+
+ error_scale = 0.5 / (double)total_samples;
+
+ return FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error, error_scale);
+}
+
+double FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(double lpc_error, double error_scale)
+{
+ if(lpc_error > 0.0) {
+ double bps = (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;
+ }
+}
+
+uint32_t FLAC__lpc_compute_best_order(const double lpc_error[], uint32_t max_order, uint32_t total_samples, uint32_t overhead_bits_per_order)
+{
+ uint32_t order, indx, 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 */
+ double bits, best_bits, error_scale;
+
+ FLAC__ASSERT(max_order > 0);
+ FLAC__ASSERT(total_samples > 0);
+
+ error_scale = 0.5 / (double)total_samples;
+
+ best_index = 0;
+ best_bits = (uint32_t)(-1);
+
+ for(indx = 0, order = 1; indx < max_order; indx++, order++) {
+ bits = FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error[indx], error_scale) * (double)(total_samples - order) + (double)(order * overhead_bits_per_order);
+ if(bits < best_bits) {
+ best_index = indx;
+ best_bits = bits;
+ }
+ }
+
+ return best_index+1; /* +1 since indx of lpc_error[] is order-1 */
+}
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/src/libFLAC/lpc_intrin_avx2.c b/src/libFLAC/lpc_intrin_avx2.c
new file mode 100644
index 0000000..7f1c03e
--- /dev/null
+++ b/src/libFLAC/lpc_intrin_avx2.c
@@ -0,0 +1,1122 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "private/cpu.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#ifndef FLAC__NO_ASM
+#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
+#include "private/lpc.h"
+#ifdef FLAC__AVX2_SUPPORTED
+
+#include "FLAC/assert.h"
+#include "FLAC/format.h"
+
+#include <immintrin.h> /* AVX2 */
+
+FLAC__SSE_TARGET("avx2")
+void FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_avx2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[])
+{
+ int i;
+ FLAC__int32 sum;
+ const __m128i cnt = _mm_cvtsi32_si128(lp_quantization);
+
+ FLAC__ASSERT(order > 0);
+ FLAC__ASSERT(order <= 32);
+
+ if(order <= 12) {
+ if(order > 8) {
+ if(order > 10) {
+ if(order == 12) {
+ __m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11;
+ q0 = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
+ q1 = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
+ q2 = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
+ q3 = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]);
+ q4 = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]);
+ q5 = _mm256_set1_epi32(0xffff & qlp_coeff[5 ]);
+ q6 = _mm256_set1_epi32(0xffff & qlp_coeff[6 ]);
+ q7 = _mm256_set1_epi32(0xffff & qlp_coeff[7 ]);
+ q8 = _mm256_set1_epi32(0xffff & qlp_coeff[8 ]);
+ q9 = _mm256_set1_epi32(0xffff & qlp_coeff[9 ]);
+ q10 = _mm256_set1_epi32(0xffff & qlp_coeff[10]);
+ q11 = _mm256_set1_epi32(0xffff & qlp_coeff[11]);
+
+ for(i = 0; i < (int)data_len-7; i+=8) {
+ __m256i summ, mull;
+ summ = _mm256_madd_epi16(q11, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-12)));
+ mull = _mm256_madd_epi16(q10, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-11))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q9, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-10))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q8, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-9 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q7, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-8 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q6, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-7 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q5, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-6 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
+ summ = _mm256_sra_epi32(summ, cnt);
+ _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ));
+ }
+ }
+ else { /* order == 11 */
+ __m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10;
+ q0 = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
+ q1 = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
+ q2 = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
+ q3 = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]);
+ q4 = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]);
+ q5 = _mm256_set1_epi32(0xffff & qlp_coeff[5 ]);
+ q6 = _mm256_set1_epi32(0xffff & qlp_coeff[6 ]);
+ q7 = _mm256_set1_epi32(0xffff & qlp_coeff[7 ]);
+ q8 = _mm256_set1_epi32(0xffff & qlp_coeff[8 ]);
+ q9 = _mm256_set1_epi32(0xffff & qlp_coeff[9 ]);
+ q10 = _mm256_set1_epi32(0xffff & qlp_coeff[10]);
+
+ for(i = 0; i < (int)data_len-7; i+=8) {
+ __m256i summ, mull;
+ summ = _mm256_madd_epi16(q10, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-11)));
+ mull = _mm256_madd_epi16(q9, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-10))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q8, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-9 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q7, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-8 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q6, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-7 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q5, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-6 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
+ summ = _mm256_sra_epi32(summ, cnt);
+ _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ));
+ }
+ }
+ }
+ else {
+ if(order == 10) {
+ __m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9;
+ q0 = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
+ q1 = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
+ q2 = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
+ q3 = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]);
+ q4 = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]);
+ q5 = _mm256_set1_epi32(0xffff & qlp_coeff[5 ]);
+ q6 = _mm256_set1_epi32(0xffff & qlp_coeff[6 ]);
+ q7 = _mm256_set1_epi32(0xffff & qlp_coeff[7 ]);
+ q8 = _mm256_set1_epi32(0xffff & qlp_coeff[8 ]);
+ q9 = _mm256_set1_epi32(0xffff & qlp_coeff[9 ]);
+
+ for(i = 0; i < (int)data_len-7; i+=8) {
+ __m256i summ, mull;
+ summ = _mm256_madd_epi16(q9, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-10)));
+ mull = _mm256_madd_epi16(q8, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-9 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q7, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-8 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q6, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-7 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q5, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-6 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
+ summ = _mm256_sra_epi32(summ, cnt);
+ _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ));
+ }
+ }
+ else { /* order == 9 */
+ __m256i q0, q1, q2, q3, q4, q5, q6, q7, q8;
+ q0 = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
+ q1 = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
+ q2 = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
+ q3 = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]);
+ q4 = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]);
+ q5 = _mm256_set1_epi32(0xffff & qlp_coeff[5 ]);
+ q6 = _mm256_set1_epi32(0xffff & qlp_coeff[6 ]);
+ q7 = _mm256_set1_epi32(0xffff & qlp_coeff[7 ]);
+ q8 = _mm256_set1_epi32(0xffff & qlp_coeff[8 ]);
+
+ for(i = 0; i < (int)data_len-7; i+=8) {
+ __m256i summ, mull;
+ summ = _mm256_madd_epi16(q8, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-9 )));
+ mull = _mm256_madd_epi16(q7, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-8 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q6, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-7 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q5, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-6 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
+ summ = _mm256_sra_epi32(summ, cnt);
+ _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ));
+ }
+ }
+ }
+ }
+ else if(order > 4) {
+ if(order > 6) {
+ if(order == 8) {
+ __m256i q0, q1, q2, q3, q4, q5, q6, q7;
+ q0 = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
+ q1 = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
+ q2 = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
+ q3 = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]);
+ q4 = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]);
+ q5 = _mm256_set1_epi32(0xffff & qlp_coeff[5 ]);
+ q6 = _mm256_set1_epi32(0xffff & qlp_coeff[6 ]);
+ q7 = _mm256_set1_epi32(0xffff & qlp_coeff[7 ]);
+
+ for(i = 0; i < (int)data_len-7; i+=8) {
+ __m256i summ, mull;
+ summ = _mm256_madd_epi16(q7, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-8 )));
+ mull = _mm256_madd_epi16(q6, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-7 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q5, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-6 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
+ summ = _mm256_sra_epi32(summ, cnt);
+ _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ));
+ }
+ }
+ else { /* order == 7 */
+ __m256i q0, q1, q2, q3, q4, q5, q6;
+ q0 = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
+ q1 = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
+ q2 = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
+ q3 = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]);
+ q4 = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]);
+ q5 = _mm256_set1_epi32(0xffff & qlp_coeff[5 ]);
+ q6 = _mm256_set1_epi32(0xffff & qlp_coeff[6 ]);
+
+ for(i = 0; i < (int)data_len-7; i+=8) {
+ __m256i summ, mull;
+ summ = _mm256_madd_epi16(q6, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-7 )));
+ mull = _mm256_madd_epi16(q5, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-6 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
+ summ = _mm256_sra_epi32(summ, cnt);
+ _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ));
+ }
+ }
+ }
+ else {
+ if(order == 6) {
+ __m256i q0, q1, q2, q3, q4, q5;
+ q0 = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
+ q1 = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
+ q2 = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
+ q3 = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]);
+ q4 = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]);
+ q5 = _mm256_set1_epi32(0xffff & qlp_coeff[5 ]);
+
+ for(i = 0; i < (int)data_len-7; i+=8) {
+ __m256i summ, mull;
+ summ = _mm256_madd_epi16(q5, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-6 )));
+ mull = _mm256_madd_epi16(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
+ summ = _mm256_sra_epi32(summ, cnt);
+ _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ));
+ }
+ }
+ else { /* order == 5 */
+ __m256i q0, q1, q2, q3, q4;
+ q0 = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
+ q1 = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
+ q2 = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
+ q3 = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]);
+ q4 = _mm256_set1_epi32(0xffff & qlp_coeff[4 ]);
+
+ for(i = 0; i < (int)data_len-7; i+=8) {
+ __m256i summ, mull;
+ summ = _mm256_madd_epi16(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5 )));
+ mull = _mm256_madd_epi16(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
+ summ = _mm256_sra_epi32(summ, cnt);
+ _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ));
+ }
+ }
+ }
+ }
+ else {
+ if(order > 2) {
+ if(order == 4) {
+ __m256i q0, q1, q2, q3;
+ q0 = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
+ q1 = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
+ q2 = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
+ q3 = _mm256_set1_epi32(0xffff & qlp_coeff[3 ]);
+
+ for(i = 0; i < (int)data_len-7; i+=8) {
+ __m256i summ, mull;
+ summ = _mm256_madd_epi16(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4 )));
+ mull = _mm256_madd_epi16(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
+ summ = _mm256_sra_epi32(summ, cnt);
+ _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ));
+ }
+ }
+ else { /* order == 3 */
+ __m256i q0, q1, q2;
+ q0 = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
+ q1 = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
+ q2 = _mm256_set1_epi32(0xffff & qlp_coeff[2 ]);
+
+ for(i = 0; i < (int)data_len-7; i+=8) {
+ __m256i summ, mull;
+ summ = _mm256_madd_epi16(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3 )));
+ mull = _mm256_madd_epi16(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2 ))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_madd_epi16(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
+ summ = _mm256_sra_epi32(summ, cnt);
+ _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ));
+ }
+ }
+ }
+ else {
+ if(order == 2) {
+ __m256i q0, q1;
+ q0 = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
+ q1 = _mm256_set1_epi32(0xffff & qlp_coeff[1 ]);
+
+ for(i = 0; i < (int)data_len-7; i+=8) {
+ __m256i summ, mull;
+ summ = _mm256_madd_epi16(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2 )));
+ mull = _mm256_madd_epi16(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1 ))); summ = _mm256_add_epi32(summ, mull);
+ summ = _mm256_sra_epi32(summ, cnt);
+ _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ));
+ }
+ }
+ else { /* order == 1 */
+ __m256i q0;
+ q0 = _mm256_set1_epi32(0xffff & qlp_coeff[0 ]);
+
+ for(i = 0; i < (int)data_len-7; i+=8) {
+ __m256i summ;
+ summ = _mm256_madd_epi16(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1 )));
+ summ = _mm256_sra_epi32(summ, cnt);
+ _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ));
+ }
+ }
+ }
+ }
+ for(; i < (int)data_len; i++) {
+ sum = 0;
+ switch(order) {
+ case 12: sum += qlp_coeff[11] * data[i-12]; /* Falls through. */
+ case 11: sum += qlp_coeff[10] * data[i-11]; /* Falls through. */
+ case 10: sum += qlp_coeff[ 9] * data[i-10]; /* Falls through. */
+ case 9: sum += qlp_coeff[ 8] * data[i- 9]; /* Falls through. */
+ case 8: sum += qlp_coeff[ 7] * data[i- 8]; /* Falls through. */
+ case 7: sum += qlp_coeff[ 6] * data[i- 7]; /* Falls through. */
+ case 6: sum += qlp_coeff[ 5] * data[i- 6]; /* Falls through. */
+ case 5: sum += qlp_coeff[ 4] * data[i- 5]; /* Falls through. */
+ case 4: sum += qlp_coeff[ 3] * data[i- 4]; /* Falls through. */
+ case 3: sum += qlp_coeff[ 2] * data[i- 3]; /* Falls through. */
+ case 2: sum += qlp_coeff[ 1] * data[i- 2]; /* Falls through. */
+ case 1: sum += qlp_coeff[ 0] * data[i- 1];
+ }
+ residual[i] = data[i] - (sum >> 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]; /* Falls through. */
+ case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */
+ case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */
+ case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */
+ case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */
+ case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */
+ case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */
+ case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */
+ case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */
+ case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */
+ case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */
+ case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */
+ case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */
+ case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */
+ case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */
+ case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */
+ case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */
+ case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */
+ case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */
+ 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);
+ }
+ }
+ _mm256_zeroupper();
+}
+
+FLAC__SSE_TARGET("avx2")
+void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_avx2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[])
+{
+ int i;
+ FLAC__int32 sum;
+ const __m128i cnt = _mm_cvtsi32_si128(lp_quantization);
+
+ FLAC__ASSERT(order > 0);
+ FLAC__ASSERT(order <= 32);
+
+ if(order <= 12) {
+ if(order > 8) {
+ if(order > 10) {
+ if(order == 12) {
+ __m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11;
+ q0 = _mm256_set1_epi32(qlp_coeff[0 ]);
+ q1 = _mm256_set1_epi32(qlp_coeff[1 ]);
+ q2 = _mm256_set1_epi32(qlp_coeff[2 ]);
+ q3 = _mm256_set1_epi32(qlp_coeff[3 ]);
+ q4 = _mm256_set1_epi32(qlp_coeff[4 ]);
+ q5 = _mm256_set1_epi32(qlp_coeff[5 ]);
+ q6 = _mm256_set1_epi32(qlp_coeff[6 ]);
+ q7 = _mm256_set1_epi32(qlp_coeff[7 ]);
+ q8 = _mm256_set1_epi32(qlp_coeff[8 ]);
+ q9 = _mm256_set1_epi32(qlp_coeff[9 ]);
+ q10 = _mm256_set1_epi32(qlp_coeff[10]);
+ q11 = _mm256_set1_epi32(qlp_coeff[11]);
+
+ for(i = 0; i < (int)data_len-7; i+=8) {
+ __m256i summ, mull;
+ summ = _mm256_mullo_epi32(q11, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-12)));
+ mull = _mm256_mullo_epi32(q10, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-11))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q9, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-10))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q8, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-9))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q7, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-8))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q6, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-7))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q5, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-6))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1))); summ = _mm256_add_epi32(summ, mull);
+ summ = _mm256_sra_epi32(summ, cnt);
+ _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ));
+ }
+ }
+ else { /* order == 11 */
+ __m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10;
+ q0 = _mm256_set1_epi32(qlp_coeff[0 ]);
+ q1 = _mm256_set1_epi32(qlp_coeff[1 ]);
+ q2 = _mm256_set1_epi32(qlp_coeff[2 ]);
+ q3 = _mm256_set1_epi32(qlp_coeff[3 ]);
+ q4 = _mm256_set1_epi32(qlp_coeff[4 ]);
+ q5 = _mm256_set1_epi32(qlp_coeff[5 ]);
+ q6 = _mm256_set1_epi32(qlp_coeff[6 ]);
+ q7 = _mm256_set1_epi32(qlp_coeff[7 ]);
+ q8 = _mm256_set1_epi32(qlp_coeff[8 ]);
+ q9 = _mm256_set1_epi32(qlp_coeff[9 ]);
+ q10 = _mm256_set1_epi32(qlp_coeff[10]);
+
+ for(i = 0; i < (int)data_len-7; i+=8) {
+ __m256i summ, mull;
+ summ = _mm256_mullo_epi32(q10, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-11)));
+ mull = _mm256_mullo_epi32(q9, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-10))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q8, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-9))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q7, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-8))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q6, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-7))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q5, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-6))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1))); summ = _mm256_add_epi32(summ, mull);
+ summ = _mm256_sra_epi32(summ, cnt);
+ _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ));
+ }
+ }
+ }
+ else {
+ if(order == 10) {
+ __m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9;
+ q0 = _mm256_set1_epi32(qlp_coeff[0 ]);
+ q1 = _mm256_set1_epi32(qlp_coeff[1 ]);
+ q2 = _mm256_set1_epi32(qlp_coeff[2 ]);
+ q3 = _mm256_set1_epi32(qlp_coeff[3 ]);
+ q4 = _mm256_set1_epi32(qlp_coeff[4 ]);
+ q5 = _mm256_set1_epi32(qlp_coeff[5 ]);
+ q6 = _mm256_set1_epi32(qlp_coeff[6 ]);
+ q7 = _mm256_set1_epi32(qlp_coeff[7 ]);
+ q8 = _mm256_set1_epi32(qlp_coeff[8 ]);
+ q9 = _mm256_set1_epi32(qlp_coeff[9 ]);
+
+ for(i = 0; i < (int)data_len-7; i+=8) {
+ __m256i summ, mull;
+ summ = _mm256_mullo_epi32(q9, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-10)));
+ mull = _mm256_mullo_epi32(q8, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-9))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q7, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-8))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q6, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-7))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q5, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-6))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1))); summ = _mm256_add_epi32(summ, mull);
+ summ = _mm256_sra_epi32(summ, cnt);
+ _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ));
+ }
+ }
+ else { /* order == 9 */
+ __m256i q0, q1, q2, q3, q4, q5, q6, q7, q8;
+ q0 = _mm256_set1_epi32(qlp_coeff[0 ]);
+ q1 = _mm256_set1_epi32(qlp_coeff[1 ]);
+ q2 = _mm256_set1_epi32(qlp_coeff[2 ]);
+ q3 = _mm256_set1_epi32(qlp_coeff[3 ]);
+ q4 = _mm256_set1_epi32(qlp_coeff[4 ]);
+ q5 = _mm256_set1_epi32(qlp_coeff[5 ]);
+ q6 = _mm256_set1_epi32(qlp_coeff[6 ]);
+ q7 = _mm256_set1_epi32(qlp_coeff[7 ]);
+ q8 = _mm256_set1_epi32(qlp_coeff[8 ]);
+
+ for(i = 0; i < (int)data_len-7; i+=8) {
+ __m256i summ, mull;
+ summ = _mm256_mullo_epi32(q8, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-9)));
+ mull = _mm256_mullo_epi32(q7, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-8))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q6, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-7))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q5, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-6))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1))); summ = _mm256_add_epi32(summ, mull);
+ summ = _mm256_sra_epi32(summ, cnt);
+ _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ));
+ }
+ }
+ }
+ }
+ else if(order > 4) {
+ if(order > 6) {
+ if(order == 8) {
+ __m256i q0, q1, q2, q3, q4, q5, q6, q7;
+ q0 = _mm256_set1_epi32(qlp_coeff[0 ]);
+ q1 = _mm256_set1_epi32(qlp_coeff[1 ]);
+ q2 = _mm256_set1_epi32(qlp_coeff[2 ]);
+ q3 = _mm256_set1_epi32(qlp_coeff[3 ]);
+ q4 = _mm256_set1_epi32(qlp_coeff[4 ]);
+ q5 = _mm256_set1_epi32(qlp_coeff[5 ]);
+ q6 = _mm256_set1_epi32(qlp_coeff[6 ]);
+ q7 = _mm256_set1_epi32(qlp_coeff[7 ]);
+
+ for(i = 0; i < (int)data_len-7; i+=8) {
+ __m256i summ, mull;
+ summ = _mm256_mullo_epi32(q7, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-8)));
+ mull = _mm256_mullo_epi32(q6, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-7))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q5, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-6))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1))); summ = _mm256_add_epi32(summ, mull);
+ summ = _mm256_sra_epi32(summ, cnt);
+ _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ));
+ }
+ }
+ else { /* order == 7 */
+ __m256i q0, q1, q2, q3, q4, q5, q6;
+ q0 = _mm256_set1_epi32(qlp_coeff[0 ]);
+ q1 = _mm256_set1_epi32(qlp_coeff[1 ]);
+ q2 = _mm256_set1_epi32(qlp_coeff[2 ]);
+ q3 = _mm256_set1_epi32(qlp_coeff[3 ]);
+ q4 = _mm256_set1_epi32(qlp_coeff[4 ]);
+ q5 = _mm256_set1_epi32(qlp_coeff[5 ]);
+ q6 = _mm256_set1_epi32(qlp_coeff[6 ]);
+
+ for(i = 0; i < (int)data_len-7; i+=8) {
+ __m256i summ, mull;
+ summ = _mm256_mullo_epi32(q6, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-7)));
+ mull = _mm256_mullo_epi32(q5, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-6))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1))); summ = _mm256_add_epi32(summ, mull);
+ summ = _mm256_sra_epi32(summ, cnt);
+ _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ));
+ }
+ }
+ }
+ else {
+ if(order == 6) {
+ __m256i q0, q1, q2, q3, q4, q5;
+ q0 = _mm256_set1_epi32(qlp_coeff[0 ]);
+ q1 = _mm256_set1_epi32(qlp_coeff[1 ]);
+ q2 = _mm256_set1_epi32(qlp_coeff[2 ]);
+ q3 = _mm256_set1_epi32(qlp_coeff[3 ]);
+ q4 = _mm256_set1_epi32(qlp_coeff[4 ]);
+ q5 = _mm256_set1_epi32(qlp_coeff[5 ]);
+
+ for(i = 0; i < (int)data_len-7; i+=8) {
+ __m256i summ, mull;
+ summ = _mm256_mullo_epi32(q5, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-6)));
+ mull = _mm256_mullo_epi32(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1))); summ = _mm256_add_epi32(summ, mull);
+ summ = _mm256_sra_epi32(summ, cnt);
+ _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ));
+ }
+ }
+ else { /* order == 5 */
+ __m256i q0, q1, q2, q3, q4;
+ q0 = _mm256_set1_epi32(qlp_coeff[0 ]);
+ q1 = _mm256_set1_epi32(qlp_coeff[1 ]);
+ q2 = _mm256_set1_epi32(qlp_coeff[2 ]);
+ q3 = _mm256_set1_epi32(qlp_coeff[3 ]);
+ q4 = _mm256_set1_epi32(qlp_coeff[4 ]);
+
+ for(i = 0; i < (int)data_len-7; i+=8) {
+ __m256i summ, mull;
+ summ = _mm256_mullo_epi32(q4, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-5)));
+ mull = _mm256_mullo_epi32(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1))); summ = _mm256_add_epi32(summ, mull);
+ summ = _mm256_sra_epi32(summ, cnt);
+ _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ));
+ }
+ }
+ }
+ }
+ else {
+ if(order > 2) {
+ if(order == 4) {
+ __m256i q0, q1, q2, q3;
+ q0 = _mm256_set1_epi32(qlp_coeff[0 ]);
+ q1 = _mm256_set1_epi32(qlp_coeff[1 ]);
+ q2 = _mm256_set1_epi32(qlp_coeff[2 ]);
+ q3 = _mm256_set1_epi32(qlp_coeff[3 ]);
+
+ for(i = 0; i < (int)data_len-7; i+=8) {
+ __m256i summ, mull;
+ summ = _mm256_mullo_epi32(q3, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-4)));
+ mull = _mm256_mullo_epi32(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1))); summ = _mm256_add_epi32(summ, mull);
+ summ = _mm256_sra_epi32(summ, cnt);
+ _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ));
+ }
+ }
+ else { /* order == 3 */
+ __m256i q0, q1, q2;
+ q0 = _mm256_set1_epi32(qlp_coeff[0 ]);
+ q1 = _mm256_set1_epi32(qlp_coeff[1 ]);
+ q2 = _mm256_set1_epi32(qlp_coeff[2 ]);
+
+ for(i = 0; i < (int)data_len-7; i+=8) {
+ __m256i summ, mull;
+ summ = _mm256_mullo_epi32(q2, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-3)));
+ mull = _mm256_mullo_epi32(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2))); summ = _mm256_add_epi32(summ, mull);
+ mull = _mm256_mullo_epi32(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1))); summ = _mm256_add_epi32(summ, mull);
+ summ = _mm256_sra_epi32(summ, cnt);
+ _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ));
+ }
+ }
+ }
+ else {
+ if(order == 2) {
+ __m256i q0, q1;
+ q0 = _mm256_set1_epi32(qlp_coeff[0 ]);
+ q1 = _mm256_set1_epi32(qlp_coeff[1 ]);
+
+ for(i = 0; i < (int)data_len-7; i+=8) {
+ __m256i summ, mull;
+ summ = _mm256_mullo_epi32(q1, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-2)));
+ mull = _mm256_mullo_epi32(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1))); summ = _mm256_add_epi32(summ, mull);
+ summ = _mm256_sra_epi32(summ, cnt);
+ _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ));
+ }
+ }
+ else { /* order == 1 */
+ __m256i q0;
+ q0 = _mm256_set1_epi32(qlp_coeff[0 ]);
+
+ for(i = 0; i < (int)data_len-7; i+=8) {
+ __m256i summ;
+ summ = _mm256_mullo_epi32(q0, _mm256_loadu_si256((const __m256i*)(const void*)(data+i-1)));
+ summ = _mm256_sra_epi32(summ, cnt);
+ _mm256_storeu_si256((__m256i*)(void*)(residual+i), _mm256_sub_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(data+i)), summ));
+ }
+ }
+ }
+ }
+ for(; i < (int)data_len; i++) {
+ sum = 0;
+ switch(order) {
+ case 12: sum += qlp_coeff[11] * data[i-12]; /* Falls through. */
+ case 11: sum += qlp_coeff[10] * data[i-11]; /* Falls through. */
+ case 10: sum += qlp_coeff[ 9] * data[i-10]; /* Falls through. */
+ case 9: sum += qlp_coeff[ 8] * data[i- 9]; /* Falls through. */
+ case 8: sum += qlp_coeff[ 7] * data[i- 8]; /* Falls through. */
+ case 7: sum += qlp_coeff[ 6] * data[i- 7]; /* Falls through. */
+ case 6: sum += qlp_coeff[ 5] * data[i- 6]; /* Falls through. */
+ case 5: sum += qlp_coeff[ 4] * data[i- 5]; /* Falls through. */
+ case 4: sum += qlp_coeff[ 3] * data[i- 4]; /* Falls through. */
+ case 3: sum += qlp_coeff[ 2] * data[i- 3]; /* Falls through. */
+ case 2: sum += qlp_coeff[ 1] * data[i- 2]; /* Falls through. */
+ case 1: sum += qlp_coeff[ 0] * data[i- 1];
+ }
+ residual[i] = data[i] - (sum >> 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]; /* Falls through. */
+ case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */
+ case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */
+ case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */
+ case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */
+ case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */
+ case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */
+ case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */
+ case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */
+ case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */
+ case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */
+ case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */
+ case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */
+ case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */
+ case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */
+ case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */
+ case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */
+ case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */
+ case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */
+ 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);
+ }
+ }
+ _mm256_zeroupper();
+}
+
+static FLAC__int32 pack_arr[8] = { 0, 2, 4, 6, 1, 3, 5, 7 };
+
+FLAC__SSE_TARGET("avx2")
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_avx2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[])
+{
+ int i;
+ FLAC__int64 sum;
+ const __m128i cnt = _mm_cvtsi32_si128(lp_quantization);
+ const __m256i pack = _mm256_loadu_si256((const __m256i *)(const void*)pack_arr);
+
+ FLAC__ASSERT(order > 0);
+ FLAC__ASSERT(order <= 32);
+ FLAC__ASSERT(lp_quantization <= 32); /* there's no _mm256_sra_epi64() so we have to use _mm256_srl_epi64() */
+
+ if(order <= 12) {
+ if(order > 8) {
+ if(order > 10) {
+ if(order == 12) {
+ __m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11;
+ q0 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
+ q1 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
+ q2 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
+ q3 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ]));
+ q4 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ]));
+ q5 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[5 ]));
+ q6 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[6 ]));
+ q7 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[7 ]));
+ q8 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[8 ]));
+ q9 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[9 ]));
+ q10 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[10]));
+ q11 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[11]));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m256i summ, mull;
+ summ = _mm256_mul_epi32(q11, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-12))));
+ mull = _mm256_mul_epi32(q10, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-11)))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q9, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-10)))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q8, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-9 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q7, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-8 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q6, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-7 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q5, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-6 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q4, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-5 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q3, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q2, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q1, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q0, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
+ summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), _mm256_castsi256_si128(summ)));
+ }
+ }
+ else { /* order == 11 */
+ __m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10;
+ q0 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
+ q1 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
+ q2 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
+ q3 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ]));
+ q4 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ]));
+ q5 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[5 ]));
+ q6 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[6 ]));
+ q7 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[7 ]));
+ q8 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[8 ]));
+ q9 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[9 ]));
+ q10 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[10]));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m256i summ, mull;
+ summ = _mm256_mul_epi32(q10, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-11))));
+ mull = _mm256_mul_epi32(q9, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-10)))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q8, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-9 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q7, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-8 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q6, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-7 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q5, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-6 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q4, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-5 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q3, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q2, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q1, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q0, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
+ summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), _mm256_castsi256_si128(summ)));
+ }
+ }
+ }
+ else {
+ if(order == 10) {
+ __m256i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9;
+ q0 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
+ q1 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
+ q2 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
+ q3 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ]));
+ q4 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ]));
+ q5 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[5 ]));
+ q6 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[6 ]));
+ q7 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[7 ]));
+ q8 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[8 ]));
+ q9 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[9 ]));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m256i summ, mull;
+ summ = _mm256_mul_epi32(q9, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-10))));
+ mull = _mm256_mul_epi32(q8, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-9 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q7, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-8 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q6, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-7 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q5, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-6 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q4, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-5 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q3, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q2, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q1, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q0, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
+ summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), _mm256_castsi256_si128(summ)));
+ }
+ }
+ else { /* order == 9 */
+ __m256i q0, q1, q2, q3, q4, q5, q6, q7, q8;
+ q0 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
+ q1 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
+ q2 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
+ q3 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ]));
+ q4 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ]));
+ q5 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[5 ]));
+ q6 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[6 ]));
+ q7 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[7 ]));
+ q8 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[8 ]));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m256i summ, mull;
+ summ = _mm256_mul_epi32(q8, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-9 ))));
+ mull = _mm256_mul_epi32(q7, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-8 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q6, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-7 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q5, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-6 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q4, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-5 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q3, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q2, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q1, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q0, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
+ summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), _mm256_castsi256_si128(summ)));
+ }
+ }
+ }
+ }
+ else if(order > 4) {
+ if(order > 6) {
+ if(order == 8) {
+ __m256i q0, q1, q2, q3, q4, q5, q6, q7;
+ q0 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
+ q1 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
+ q2 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
+ q3 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ]));
+ q4 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ]));
+ q5 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[5 ]));
+ q6 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[6 ]));
+ q7 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[7 ]));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m256i summ, mull;
+ summ = _mm256_mul_epi32(q7, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-8 ))));
+ mull = _mm256_mul_epi32(q6, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-7 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q5, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-6 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q4, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-5 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q3, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q2, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q1, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q0, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
+ summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), _mm256_castsi256_si128(summ)));
+ }
+ }
+ else { /* order == 7 */
+ __m256i q0, q1, q2, q3, q4, q5, q6;
+ q0 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
+ q1 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
+ q2 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
+ q3 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ]));
+ q4 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ]));
+ q5 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[5 ]));
+ q6 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[6 ]));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m256i summ, mull;
+ summ = _mm256_mul_epi32(q6, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-7 ))));
+ mull = _mm256_mul_epi32(q5, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-6 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q4, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-5 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q3, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q2, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q1, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q0, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
+ summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), _mm256_castsi256_si128(summ)));
+ }
+ }
+ }
+ else {
+ if(order == 6) {
+ __m256i q0, q1, q2, q3, q4, q5;
+ q0 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
+ q1 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
+ q2 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
+ q3 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ]));
+ q4 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ]));
+ q5 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[5 ]));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m256i summ, mull;
+ summ = _mm256_mul_epi32(q5, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-6 ))));
+ mull = _mm256_mul_epi32(q4, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-5 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q3, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q2, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q1, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q0, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
+ summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), _mm256_castsi256_si128(summ)));
+ }
+ }
+ else { /* order == 5 */
+ __m256i q0, q1, q2, q3, q4;
+ q0 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
+ q1 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
+ q2 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
+ q3 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ]));
+ q4 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[4 ]));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m256i summ, mull;
+ summ = _mm256_mul_epi32(q4, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-5 ))));
+ mull = _mm256_mul_epi32(q3, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-4 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q2, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q1, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q0, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
+ summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), _mm256_castsi256_si128(summ)));
+ }
+ }
+ }
+ }
+ else {
+ if(order > 2) {
+ if(order == 4) {
+ __m256i q0, q1, q2, q3;
+ q0 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
+ q1 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
+ q2 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
+ q3 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[3 ]));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m256i summ, mull;
+ summ = _mm256_mul_epi32(q3, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-4 ))));
+ mull = _mm256_mul_epi32(q2, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-3 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q1, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q0, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
+ summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), _mm256_castsi256_si128(summ)));
+ }
+ }
+ else { /* order == 3 */
+ __m256i q0, q1, q2;
+ q0 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
+ q1 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
+ q2 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[2 ]));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m256i summ, mull;
+ summ = _mm256_mul_epi32(q2, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-3 ))));
+ mull = _mm256_mul_epi32(q1, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-2 )))); summ = _mm256_add_epi64(summ, mull);
+ mull = _mm256_mul_epi32(q0, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
+ summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), _mm256_castsi256_si128(summ)));
+ }
+ }
+ }
+ else {
+ if(order == 2) {
+ __m256i q0, q1;
+ q0 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
+ q1 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[1 ]));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m256i summ, mull;
+ summ = _mm256_mul_epi32(q1, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-2 ))));
+ mull = _mm256_mul_epi32(q0, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-1 )))); summ = _mm256_add_epi64(summ, mull);
+ summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), _mm256_castsi256_si128(summ)));
+ }
+ }
+ else { /* order == 1 */
+ __m256i q0;
+ q0 = _mm256_cvtepu32_epi64(_mm_set1_epi32(qlp_coeff[0 ]));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m256i summ;
+ summ = _mm256_mul_epi32(q0, _mm256_cvtepu32_epi64(_mm_loadu_si128((const __m128i*)(const void*)(data+i-1 ))));
+ summ = _mm256_permutevar8x32_epi32(_mm256_srl_epi64(summ, cnt), pack);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), _mm256_castsi256_si128(summ)));
+ }
+ }
+ }
+ }
+ for(; i < (int)data_len; i++) {
+ sum = 0;
+ switch(order) {
+ case 12: sum += qlp_coeff[11] * (FLAC__int64)data[i-12]; /* Falls through. */
+ case 11: sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; /* Falls through. */
+ case 10: sum += qlp_coeff[ 9] * (FLAC__int64)data[i-10]; /* Falls through. */
+ case 9: sum += qlp_coeff[ 8] * (FLAC__int64)data[i- 9]; /* Falls through. */
+ case 8: sum += qlp_coeff[ 7] * (FLAC__int64)data[i- 8]; /* Falls through. */
+ case 7: sum += qlp_coeff[ 6] * (FLAC__int64)data[i- 7]; /* Falls through. */
+ case 6: sum += qlp_coeff[ 5] * (FLAC__int64)data[i- 6]; /* Falls through. */
+ case 5: sum += qlp_coeff[ 4] * (FLAC__int64)data[i- 5]; /* Falls through. */
+ case 4: sum += qlp_coeff[ 3] * (FLAC__int64)data[i- 4]; /* Falls through. */
+ case 3: sum += qlp_coeff[ 2] * (FLAC__int64)data[i- 3]; /* Falls through. */
+ case 2: sum += qlp_coeff[ 1] * (FLAC__int64)data[i- 2]; /* Falls through. */
+ case 1: sum += qlp_coeff[ 0] * (FLAC__int64)data[i- 1];
+ }
+ residual[i] = data[i] - (FLAC__int32)(sum >> 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]; /* Falls through. */
+ case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31]; /* Falls through. */
+ case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30]; /* Falls through. */
+ case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29]; /* Falls through. */
+ case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28]; /* Falls through. */
+ case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27]; /* Falls through. */
+ case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26]; /* Falls through. */
+ case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25]; /* Falls through. */
+ case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24]; /* Falls through. */
+ case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23]; /* Falls through. */
+ case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22]; /* Falls through. */
+ case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21]; /* Falls through. */
+ case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20]; /* Falls through. */
+ case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19]; /* Falls through. */
+ case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18]; /* Falls through. */
+ case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17]; /* Falls through. */
+ case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16]; /* Falls through. */
+ case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15]; /* Falls through. */
+ case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14]; /* Falls through. */
+ 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);
+ }
+ }
+ _mm256_zeroupper();
+}
+
+#endif /* FLAC__AVX2_SUPPORTED */
+#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
+#endif /* FLAC__NO_ASM */
+#endif /* FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/src/libFLAC/lpc_intrin_fma.c b/src/libFLAC/lpc_intrin_fma.c
new file mode 100644
index 0000000..c0740a8
--- /dev/null
+++ b/src/libFLAC/lpc_intrin_fma.c
@@ -0,0 +1,73 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2022-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "private/cpu.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#ifndef FLAC__NO_ASM
+#if defined FLAC__CPU_X86_64 && FLAC__HAS_X86INTRIN
+#include "private/lpc.h"
+#ifdef FLAC__FMA_SUPPORTED
+
+#include "FLAC/assert.h"
+
+FLAC__SSE_TARGET("fma")
+void FLAC__lpc_compute_autocorrelation_intrin_fma_lag_8(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[])
+{
+#undef MAX_LAG
+#define MAX_LAG 8
+#include "deduplication/lpc_compute_autocorrelation_intrin.c"
+}
+
+FLAC__SSE_TARGET("fma")
+void FLAC__lpc_compute_autocorrelation_intrin_fma_lag_12(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[])
+{
+#undef MAX_LAG
+#define MAX_LAG 12
+#include "deduplication/lpc_compute_autocorrelation_intrin.c"
+}
+FLAC__SSE_TARGET("fma")
+void FLAC__lpc_compute_autocorrelation_intrin_fma_lag_16(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[])
+{
+#undef MAX_LAG
+#define MAX_LAG 16
+#include "deduplication/lpc_compute_autocorrelation_intrin.c"
+
+}
+
+#endif /* FLAC__FMA_SUPPORTED */
+#endif /* FLAC__CPU_X86_64 && FLAC__HAS_X86INTRIN */
+#endif /* FLAC__NO_ASM */
+#endif /* FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/src/libFLAC/lpc_intrin_neon.c b/src/libFLAC/lpc_intrin_neon.c
new file mode 100644
index 0000000..b9945d5
--- /dev/null
+++ b/src/libFLAC/lpc_intrin_neon.c
@@ -0,0 +1,1273 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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 "private/cpu.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#ifndef FLAC__NO_ASM
+#if defined FLAC__CPU_ARM64 && FLAC__HAS_NEONINTRIN
+#include "private/lpc.h"
+#include "FLAC/assert.h"
+#include "FLAC/format.h"
+#include "private/macros.h"
+#include <arm_neon.h>
+
+#if FLAC__HAS_A64NEONINTRIN
+void FLAC__lpc_compute_autocorrelation_intrin_neon_lag_14(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[])
+{
+#undef MAX_LAG
+#define MAX_LAG 14
+#include "deduplication/lpc_compute_autocorrelation_intrin_neon.c"
+}
+
+void FLAC__lpc_compute_autocorrelation_intrin_neon_lag_10(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[])
+{
+#undef MAX_LAG
+#define MAX_LAG 10
+#include "deduplication/lpc_compute_autocorrelation_intrin_neon.c"
+}
+
+void FLAC__lpc_compute_autocorrelation_intrin_neon_lag_8(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[])
+{
+#undef MAX_LAG
+#define MAX_LAG 8
+#include "deduplication/lpc_compute_autocorrelation_intrin_neon.c"
+}
+
+#endif /* ifdef FLAC__HAS_A64NEONINTRIN */
+
+
+#define MUL_32_BIT_LOOP_UNROOL_3(qlp_coeff_vec, lane) \
+ summ_0 = vmulq_laneq_s32(tmp_vec[0], qlp_coeff_vec, lane); \
+ summ_1 = vmulq_laneq_s32(tmp_vec[4], qlp_coeff_vec, lane); \
+ summ_2 = vmulq_laneq_s32(tmp_vec[8], qlp_coeff_vec, lane);
+
+
+#define MACC_32BIT_LOOP_UNROOL_3(tmp_vec_ind, qlp_coeff_vec, lane) \
+ summ_0 = vmlaq_laneq_s32(summ_0,tmp_vec[tmp_vec_ind] ,qlp_coeff_vec, lane); \
+ summ_1 = vmlaq_laneq_s32(summ_1,tmp_vec[tmp_vec_ind+4] ,qlp_coeff_vec, lane); \
+ summ_2 = vmlaq_laneq_s32(summ_2,tmp_vec[tmp_vec_ind+8] ,qlp_coeff_vec, lane);
+
+void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_neon(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[])
+{
+ int i;
+ FLAC__int32 sum;
+ int32x4_t tmp_vec[20];
+
+ FLAC__ASSERT(order > 0);
+ FLAC__ASSERT(order <= 32);
+
+ // Using prologue reads is valid as encoder->private_->local_lpc_compute_residual_from_qlp_coefficients(signal+order,....)
+ if(order <= 12) {
+ if(order > 8) {
+ if(order > 10) {
+ if (order == 12) {
+ int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]};
+ int32x4_t qlp_coeff_1 = {qlp_coeff[4], qlp_coeff[5], qlp_coeff[6], qlp_coeff[7]};
+ int32x4_t qlp_coeff_2 = {qlp_coeff[8], qlp_coeff[9], qlp_coeff[10], qlp_coeff[11]};
+
+ tmp_vec[0] = vld1q_s32(data - 12);
+ tmp_vec[1] = vld1q_s32(data - 11);
+ tmp_vec[2] = vld1q_s32(data - 10);
+ tmp_vec[3] = vld1q_s32(data - 9);
+ tmp_vec[4] = vld1q_s32(data - 8);
+ tmp_vec[5] = vld1q_s32(data - 7);
+ tmp_vec[6] = vld1q_s32(data - 6);
+ tmp_vec[7] = vld1q_s32(data - 5);
+
+ for (i = 0; i < (int)data_len - 11; i += 12)
+ {
+ int32x4_t summ_0, summ_1, summ_2;
+
+ tmp_vec[8] = vld1q_s32(data + i - 4);
+ tmp_vec[9] = vld1q_s32(data+i-3);
+ tmp_vec[10] = vld1q_s32(data+i-2);
+ tmp_vec[11] = vld1q_s32(data+i-1);
+ tmp_vec[12] = vld1q_s32(data+i);
+ tmp_vec[13] = vld1q_s32(data+i+1);
+ tmp_vec[14] = vld1q_s32(data+i+2);
+ tmp_vec[15] = vld1q_s32(data+i+3);
+ tmp_vec[16] = vld1q_s32(data + i + 4);
+ tmp_vec[17] = vld1q_s32(data + i + 5);
+ tmp_vec[18] = vld1q_s32(data + i + 6);
+ tmp_vec[19] = vld1q_s32(data + i + 7);
+
+ MUL_32_BIT_LOOP_UNROOL_3(qlp_coeff_2, 3)
+ MACC_32BIT_LOOP_UNROOL_3(1, qlp_coeff_2, 2)
+ MACC_32BIT_LOOP_UNROOL_3(2, qlp_coeff_2, 1)
+ MACC_32BIT_LOOP_UNROOL_3(3, qlp_coeff_2, 0)
+ MACC_32BIT_LOOP_UNROOL_3(4, qlp_coeff_1, 3)
+ MACC_32BIT_LOOP_UNROOL_3(5, qlp_coeff_1, 2)
+ MACC_32BIT_LOOP_UNROOL_3(6, qlp_coeff_1, 1)
+ MACC_32BIT_LOOP_UNROOL_3(7, qlp_coeff_1, 0)
+ MACC_32BIT_LOOP_UNROOL_3(8, qlp_coeff_0, 3)
+ MACC_32BIT_LOOP_UNROOL_3(9, qlp_coeff_0, 2)
+ MACC_32BIT_LOOP_UNROOL_3(10, qlp_coeff_0, 1)
+ MACC_32BIT_LOOP_UNROOL_3(11, qlp_coeff_0, 0)
+
+ vst1q_s32(residual+i + 0, vsubq_s32(vld1q_s32(data+i + 0) , vshlq_s32(summ_0,vdupq_n_s32(-lp_quantization))));
+ vst1q_s32(residual+i + 4, vsubq_s32(vld1q_s32(data+i + 4) , vshlq_s32(summ_1,vdupq_n_s32(-lp_quantization))));
+ vst1q_s32(residual+i + 8, vsubq_s32(vld1q_s32(data+i + 8) , vshlq_s32(summ_2,vdupq_n_s32(-lp_quantization))));
+
+ tmp_vec[0] = tmp_vec[12];
+ tmp_vec[1] = tmp_vec[13];
+ tmp_vec[2] = tmp_vec[14];
+ tmp_vec[3] = tmp_vec[15];
+ tmp_vec[4] = tmp_vec[16];
+ tmp_vec[5] = tmp_vec[17];
+ tmp_vec[6] = tmp_vec[18];
+ tmp_vec[7] = tmp_vec[19];
+ }
+ }
+
+ else { /* order == 11 */
+ int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]};
+ int32x4_t qlp_coeff_1 = {qlp_coeff[4], qlp_coeff[5], qlp_coeff[6], qlp_coeff[7]};
+ int32x4_t qlp_coeff_2 = {qlp_coeff[8], qlp_coeff[9], qlp_coeff[10], 0};
+
+ tmp_vec[0] = vld1q_s32(data - 11);
+ tmp_vec[1] = vld1q_s32(data - 10);
+ tmp_vec[2] = vld1q_s32(data - 9);
+ tmp_vec[3] = vld1q_s32(data - 8);
+ tmp_vec[4] = vld1q_s32(data - 7);
+ tmp_vec[5] = vld1q_s32(data - 6);
+ tmp_vec[6] = vld1q_s32(data - 5);
+
+ for (i = 0; i < (int)data_len - 11; i += 12)
+ {
+ int32x4_t summ_0, summ_1, summ_2;
+ tmp_vec[7] = vld1q_s32(data + i - 4);
+ tmp_vec[8] = vld1q_s32(data + i - 3);
+ tmp_vec[9] = vld1q_s32(data + i - 2);
+ tmp_vec[10] = vld1q_s32(data + i - 1);
+ tmp_vec[11] = vld1q_s32(data + i - 0);
+ tmp_vec[12] = vld1q_s32(data + i + 1);
+ tmp_vec[13] = vld1q_s32(data + i + 2);
+ tmp_vec[14] = vld1q_s32(data + i + 3);
+ tmp_vec[15] = vld1q_s32(data + i + 4);
+ tmp_vec[16] = vld1q_s32(data + i + 5);
+ tmp_vec[17] = vld1q_s32(data + i + 6);
+ tmp_vec[18] = vld1q_s32(data + i + 7);
+
+
+ MUL_32_BIT_LOOP_UNROOL_3(qlp_coeff_2, 2)
+ MACC_32BIT_LOOP_UNROOL_3(1, qlp_coeff_2, 1)
+ MACC_32BIT_LOOP_UNROOL_3(2, qlp_coeff_2, 0)
+ MACC_32BIT_LOOP_UNROOL_3(3, qlp_coeff_1, 3)
+ MACC_32BIT_LOOP_UNROOL_3(4, qlp_coeff_1, 2)
+ MACC_32BIT_LOOP_UNROOL_3(5, qlp_coeff_1, 1)
+ MACC_32BIT_LOOP_UNROOL_3(6, qlp_coeff_1, 0)
+ MACC_32BIT_LOOP_UNROOL_3(7, qlp_coeff_0, 3)
+ MACC_32BIT_LOOP_UNROOL_3(8, qlp_coeff_0, 2)
+ MACC_32BIT_LOOP_UNROOL_3(9, qlp_coeff_0, 1)
+ MACC_32BIT_LOOP_UNROOL_3(10, qlp_coeff_0, 0)
+
+ vst1q_s32(residual+i + 0, vsubq_s32(vld1q_s32(data+i + 0) , vshlq_s32(summ_0,vdupq_n_s32(-lp_quantization))));
+ vst1q_s32(residual+i + 4, vsubq_s32(vld1q_s32(data+i + 4) , vshlq_s32(summ_1,vdupq_n_s32(-lp_quantization))));
+ vst1q_s32(residual+i + 8, vsubq_s32(vld1q_s32(data+i + 8) , vshlq_s32(summ_2,vdupq_n_s32(-lp_quantization))));
+
+
+ tmp_vec[0] = tmp_vec[12];
+ tmp_vec[1] = tmp_vec[13];
+ tmp_vec[2] = tmp_vec[14];
+ tmp_vec[3] = tmp_vec[15];
+ tmp_vec[4] = tmp_vec[16];
+ tmp_vec[5] = tmp_vec[17];
+ tmp_vec[6] = tmp_vec[18];
+ }
+ }
+ }
+ else {
+ if(order == 10) {
+ int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]};
+ int32x4_t qlp_coeff_1 = {qlp_coeff[4], qlp_coeff[5], qlp_coeff[6], qlp_coeff[7]};
+ int32x4_t qlp_coeff_2 = {qlp_coeff[8], qlp_coeff[9], 0, 0};
+
+ tmp_vec[0] = vld1q_s32(data - 10);
+ tmp_vec[1] = vld1q_s32(data - 9);
+ tmp_vec[2] = vld1q_s32(data - 8);
+ tmp_vec[3] = vld1q_s32(data - 7);
+ tmp_vec[4] = vld1q_s32(data - 6);
+ tmp_vec[5] = vld1q_s32(data - 5);
+
+ for (i = 0; i < (int)data_len - 11; i += 12)
+ {
+ int32x4_t summ_0, summ_1, summ_2;
+ tmp_vec[6] = vld1q_s32(data + i - 4);
+ tmp_vec[7] = vld1q_s32(data + i - 3);
+ tmp_vec[8] = vld1q_s32(data + i - 2);
+ tmp_vec[9] = vld1q_s32(data + i - 1);
+ tmp_vec[10] = vld1q_s32(data + i - 0);
+ tmp_vec[11] = vld1q_s32(data + i + 1);
+ tmp_vec[12] = vld1q_s32(data + i + 2);
+ tmp_vec[13] = vld1q_s32(data + i + 3);
+ tmp_vec[14] = vld1q_s32(data + i + 4);
+ tmp_vec[15] = vld1q_s32(data + i + 5);
+ tmp_vec[16] = vld1q_s32(data + i + 6);
+ tmp_vec[17] = vld1q_s32(data + i + 7);
+
+
+ MUL_32_BIT_LOOP_UNROOL_3(qlp_coeff_2, 1)
+ MACC_32BIT_LOOP_UNROOL_3(1, qlp_coeff_2, 0)
+ MACC_32BIT_LOOP_UNROOL_3(2, qlp_coeff_1, 3)
+ MACC_32BIT_LOOP_UNROOL_3(3, qlp_coeff_1, 2)
+ MACC_32BIT_LOOP_UNROOL_3(4, qlp_coeff_1, 1)
+ MACC_32BIT_LOOP_UNROOL_3(5, qlp_coeff_1, 0)
+ MACC_32BIT_LOOP_UNROOL_3(6, qlp_coeff_0, 3)
+ MACC_32BIT_LOOP_UNROOL_3(7, qlp_coeff_0, 2)
+ MACC_32BIT_LOOP_UNROOL_3(8, qlp_coeff_0, 1)
+ MACC_32BIT_LOOP_UNROOL_3(9, qlp_coeff_0, 0)
+
+ vst1q_s32(residual+i + 0, vsubq_s32(vld1q_s32(data+i + 0) , vshlq_s32(summ_0,vdupq_n_s32(-lp_quantization))));
+ vst1q_s32(residual+i + 4, vsubq_s32(vld1q_s32(data+i + 4) , vshlq_s32(summ_1,vdupq_n_s32(-lp_quantization))));
+ vst1q_s32(residual+i + 8, vsubq_s32(vld1q_s32(data+i + 8) , vshlq_s32(summ_2,vdupq_n_s32(-lp_quantization))));
+
+
+ tmp_vec[0] = tmp_vec[12];
+ tmp_vec[1] = tmp_vec[13];
+ tmp_vec[2] = tmp_vec[14];
+ tmp_vec[3] = tmp_vec[15];
+ tmp_vec[4] = tmp_vec[16];
+ tmp_vec[5] = tmp_vec[17];
+ }
+ }
+ else { /* order == 9 */
+ int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]};
+ int32x4_t qlp_coeff_1 = {qlp_coeff[4], qlp_coeff[5], qlp_coeff[6], qlp_coeff[7]};
+ int32x4_t qlp_coeff_2 = {qlp_coeff[8], 0, 0, 0};
+
+ tmp_vec[0] = vld1q_s32(data - 9);
+ tmp_vec[1] = vld1q_s32(data - 8);
+ tmp_vec[2] = vld1q_s32(data - 7);
+ tmp_vec[3] = vld1q_s32(data - 6);
+ tmp_vec[4] = vld1q_s32(data - 5);
+
+ for (i = 0; i < (int)data_len - 11; i += 12)
+ {
+ int32x4_t summ_0, summ_1, summ_2;
+ tmp_vec[5] = vld1q_s32(data + i - 4);
+ tmp_vec[6] = vld1q_s32(data + i - 3);
+ tmp_vec[7] = vld1q_s32(data + i - 2);
+ tmp_vec[8] = vld1q_s32(data + i - 1);
+ tmp_vec[9] = vld1q_s32(data + i - 0);
+ tmp_vec[10] = vld1q_s32(data + i + 1);
+ tmp_vec[11] = vld1q_s32(data + i + 2);
+ tmp_vec[12] = vld1q_s32(data + i + 3);
+ tmp_vec[13] = vld1q_s32(data + i + 4);
+ tmp_vec[14] = vld1q_s32(data + i + 5);
+ tmp_vec[15] = vld1q_s32(data + i + 6);
+ tmp_vec[16] = vld1q_s32(data + i + 7);
+
+ MUL_32_BIT_LOOP_UNROOL_3(qlp_coeff_2, 0)
+ MACC_32BIT_LOOP_UNROOL_3(1, qlp_coeff_1, 3)
+ MACC_32BIT_LOOP_UNROOL_3(2, qlp_coeff_1, 2)
+ MACC_32BIT_LOOP_UNROOL_3(3, qlp_coeff_1, 1)
+ MACC_32BIT_LOOP_UNROOL_3(4, qlp_coeff_1, 0)
+ MACC_32BIT_LOOP_UNROOL_3(5, qlp_coeff_0, 3)
+ MACC_32BIT_LOOP_UNROOL_3(6, qlp_coeff_0, 2)
+ MACC_32BIT_LOOP_UNROOL_3(7, qlp_coeff_0, 1)
+ MACC_32BIT_LOOP_UNROOL_3(8, qlp_coeff_0, 0)
+
+ vst1q_s32(residual+i + 0, vsubq_s32(vld1q_s32(data+i + 0) , vshlq_s32(summ_0,vdupq_n_s32(-lp_quantization))));
+ vst1q_s32(residual+i + 4, vsubq_s32(vld1q_s32(data+i + 4) , vshlq_s32(summ_1,vdupq_n_s32(-lp_quantization))));
+ vst1q_s32(residual+i + 8, vsubq_s32(vld1q_s32(data+i + 8) , vshlq_s32(summ_2,vdupq_n_s32(-lp_quantization))));
+
+ tmp_vec[0] = tmp_vec[12];
+ tmp_vec[1] = tmp_vec[13];
+ tmp_vec[2] = tmp_vec[14];
+ tmp_vec[3] = tmp_vec[15];
+ tmp_vec[4] = tmp_vec[16];
+ }
+ }
+ }
+ }
+ else if(order > 4) {
+ if(order > 6) {
+ if(order == 8) {
+ int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]};
+ int32x4_t qlp_coeff_1 = {qlp_coeff[4], qlp_coeff[5], qlp_coeff[6], qlp_coeff[7]};
+
+ tmp_vec[0] = vld1q_s32(data - 8);
+ tmp_vec[1] = vld1q_s32(data - 7);
+ tmp_vec[2] = vld1q_s32(data - 6);
+ tmp_vec[3] = vld1q_s32(data - 5);
+
+ for (i = 0; i < (int)data_len - 11; i += 12)
+ {
+ int32x4_t summ_0, summ_1, summ_2;
+ tmp_vec[4] = vld1q_s32(data + i - 4);
+ tmp_vec[5] = vld1q_s32(data + i - 3);
+ tmp_vec[6] = vld1q_s32(data + i - 2);
+ tmp_vec[7] = vld1q_s32(data + i - 1);
+ tmp_vec[8] = vld1q_s32(data + i - 0);
+ tmp_vec[9] = vld1q_s32(data + i + 1);
+ tmp_vec[10] = vld1q_s32(data + i + 2);
+ tmp_vec[11] = vld1q_s32(data + i + 3);
+ tmp_vec[12] = vld1q_s32(data + i + 4);
+ tmp_vec[13] = vld1q_s32(data + i + 5);
+ tmp_vec[14] = vld1q_s32(data + i + 6);
+ tmp_vec[15] = vld1q_s32(data + i + 7);
+
+ MUL_32_BIT_LOOP_UNROOL_3(qlp_coeff_1, 3)
+ MACC_32BIT_LOOP_UNROOL_3(1, qlp_coeff_1, 2)
+ MACC_32BIT_LOOP_UNROOL_3(2, qlp_coeff_1, 1)
+ MACC_32BIT_LOOP_UNROOL_3(3, qlp_coeff_1, 0)
+ MACC_32BIT_LOOP_UNROOL_3(4, qlp_coeff_0, 3)
+ MACC_32BIT_LOOP_UNROOL_3(5, qlp_coeff_0, 2)
+ MACC_32BIT_LOOP_UNROOL_3(6, qlp_coeff_0, 1)
+ MACC_32BIT_LOOP_UNROOL_3(7, qlp_coeff_0, 0)
+
+ vst1q_s32(residual+i + 0, vsubq_s32(vld1q_s32(data+i + 0) , vshlq_s32(summ_0,vdupq_n_s32(-lp_quantization))));
+ vst1q_s32(residual+i + 4, vsubq_s32(vld1q_s32(data+i + 4) , vshlq_s32(summ_1,vdupq_n_s32(-lp_quantization))));
+ vst1q_s32(residual+i + 8, vsubq_s32(vld1q_s32(data+i + 8) , vshlq_s32(summ_2,vdupq_n_s32(-lp_quantization))));
+
+ tmp_vec[0] = tmp_vec[12];
+ tmp_vec[1] = tmp_vec[13];
+ tmp_vec[2] = tmp_vec[14];
+ tmp_vec[3] = tmp_vec[15];
+ }
+ }
+ else { /* order == 7 */
+ int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]};
+ int32x4_t qlp_coeff_1 = {qlp_coeff[4], qlp_coeff[5], qlp_coeff[6], 0};
+
+ tmp_vec[0] = vld1q_s32(data - 7);
+ tmp_vec[1] = vld1q_s32(data - 6);
+ tmp_vec[2] = vld1q_s32(data - 5);
+
+ for (i = 0; i < (int)data_len - 11; i += 12)
+ {
+ int32x4_t summ_0, summ_1, summ_2;
+ tmp_vec[3] = vld1q_s32(data + i - 4);
+ tmp_vec[4] = vld1q_s32(data + i - 3);
+ tmp_vec[5] = vld1q_s32(data + i - 2);
+ tmp_vec[6] = vld1q_s32(data + i - 1);
+ tmp_vec[7] = vld1q_s32(data + i - 0);
+ tmp_vec[8] = vld1q_s32(data + i + 1);
+ tmp_vec[9] = vld1q_s32(data + i + 2);
+ tmp_vec[10] = vld1q_s32(data + i + 3);
+ tmp_vec[11] = vld1q_s32(data + i + 4);
+ tmp_vec[12] = vld1q_s32(data + i + 5);
+ tmp_vec[13] = vld1q_s32(data + i + 6);
+ tmp_vec[14] = vld1q_s32(data + i + 7);
+
+ MUL_32_BIT_LOOP_UNROOL_3(qlp_coeff_1, 2)
+ MACC_32BIT_LOOP_UNROOL_3(1, qlp_coeff_1, 1)
+ MACC_32BIT_LOOP_UNROOL_3(2, qlp_coeff_1, 0)
+ MACC_32BIT_LOOP_UNROOL_3(3, qlp_coeff_0, 3)
+ MACC_32BIT_LOOP_UNROOL_3(4, qlp_coeff_0, 2)
+ MACC_32BIT_LOOP_UNROOL_3(5, qlp_coeff_0, 1)
+ MACC_32BIT_LOOP_UNROOL_3(6, qlp_coeff_0, 0)
+
+ vst1q_s32(residual+i + 0, vsubq_s32(vld1q_s32(data+i + 0) , vshlq_s32(summ_0,vdupq_n_s32(-lp_quantization))));
+ vst1q_s32(residual+i + 4, vsubq_s32(vld1q_s32(data+i + 4) , vshlq_s32(summ_1,vdupq_n_s32(-lp_quantization))));
+ vst1q_s32(residual+i + 8, vsubq_s32(vld1q_s32(data+i + 8) , vshlq_s32(summ_2,vdupq_n_s32(-lp_quantization))));
+
+ tmp_vec[0] = tmp_vec[12];
+ tmp_vec[1] = tmp_vec[13];
+ tmp_vec[2] = tmp_vec[14];
+ }
+ }
+ }
+ else {
+ if(order == 6) {
+ int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]};
+ int32x4_t qlp_coeff_1 = {qlp_coeff[4], qlp_coeff[5], 0, 0};
+
+ tmp_vec[0] = vld1q_s32(data - 6);
+ tmp_vec[1] = vld1q_s32(data - 5);
+
+ for (i = 0; i < (int)data_len - 11; i += 12)
+ {
+ int32x4_t summ_0, summ_1, summ_2;
+ tmp_vec[2] = vld1q_s32(data + i - 4);
+ tmp_vec[3] = vld1q_s32(data + i - 3);
+ tmp_vec[4] = vld1q_s32(data + i - 2);
+ tmp_vec[5] = vld1q_s32(data + i - 1);
+ tmp_vec[6] = vld1q_s32(data + i - 0);
+ tmp_vec[7] = vld1q_s32(data + i + 1);
+ tmp_vec[8] = vld1q_s32(data + i + 2);
+ tmp_vec[9] = vld1q_s32(data + i + 3);
+ tmp_vec[10] = vld1q_s32(data + i + 4);
+ tmp_vec[11] = vld1q_s32(data + i + 5);
+ tmp_vec[12] = vld1q_s32(data + i + 6);
+ tmp_vec[13] = vld1q_s32(data + i + 7);
+
+ MUL_32_BIT_LOOP_UNROOL_3(qlp_coeff_1, 1)
+ MACC_32BIT_LOOP_UNROOL_3(1, qlp_coeff_1, 0)
+ MACC_32BIT_LOOP_UNROOL_3(2, qlp_coeff_0, 3)
+ MACC_32BIT_LOOP_UNROOL_3(3, qlp_coeff_0, 2)
+ MACC_32BIT_LOOP_UNROOL_3(4, qlp_coeff_0, 1)
+ MACC_32BIT_LOOP_UNROOL_3(5, qlp_coeff_0, 0)
+
+ vst1q_s32(residual+i + 0, vsubq_s32(vld1q_s32(data+i + 0) , vshlq_s32(summ_0,vdupq_n_s32(-lp_quantization))));
+ vst1q_s32(residual+i + 4, vsubq_s32(vld1q_s32(data+i + 4) , vshlq_s32(summ_1,vdupq_n_s32(-lp_quantization))));
+ vst1q_s32(residual+i + 8, vsubq_s32(vld1q_s32(data+i + 8) , vshlq_s32(summ_2,vdupq_n_s32(-lp_quantization))));
+
+ tmp_vec[0] = tmp_vec[12];
+ tmp_vec[1] = tmp_vec[13];
+ }
+ }
+ else { /* order == 5 */
+ int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]};
+ int32x4_t qlp_coeff_1 = {qlp_coeff[4], 0, 0, 0};
+
+ tmp_vec[0] = vld1q_s32(data - 5);
+
+ for (i = 0; i < (int)data_len - 11; i += 12)
+ {
+ int32x4_t summ_0, summ_1, summ_2;
+
+ tmp_vec[1] = vld1q_s32(data + i - 4);
+ tmp_vec[2] = vld1q_s32(data + i - 3);
+ tmp_vec[3] = vld1q_s32(data + i - 2);
+ tmp_vec[4] = vld1q_s32(data + i - 1);
+ tmp_vec[5] = vld1q_s32(data + i - 0);
+ tmp_vec[6] = vld1q_s32(data + i + 1);
+ tmp_vec[7] = vld1q_s32(data + i + 2);
+ tmp_vec[8] = vld1q_s32(data + i + 3);
+ tmp_vec[9] = vld1q_s32(data + i + 4);
+ tmp_vec[10] = vld1q_s32(data + i + 5);
+ tmp_vec[11] = vld1q_s32(data + i + 6);
+ tmp_vec[12] = vld1q_s32(data + i + 7);
+
+ MUL_32_BIT_LOOP_UNROOL_3(qlp_coeff_1, 0)
+ MACC_32BIT_LOOP_UNROOL_3(1, qlp_coeff_0, 3)
+ MACC_32BIT_LOOP_UNROOL_3(2, qlp_coeff_0, 2)
+ MACC_32BIT_LOOP_UNROOL_3(3, qlp_coeff_0, 1)
+ MACC_32BIT_LOOP_UNROOL_3(4, qlp_coeff_0, 0)
+
+ vst1q_s32(residual+i + 0, vsubq_s32(vld1q_s32(data+i + 0) , vshlq_s32(summ_0,vdupq_n_s32(-lp_quantization))));
+ vst1q_s32(residual+i + 4, vsubq_s32(vld1q_s32(data+i + 4) , vshlq_s32(summ_1,vdupq_n_s32(-lp_quantization))));
+ vst1q_s32(residual+i + 8, vsubq_s32(vld1q_s32(data+i + 8) , vshlq_s32(summ_2,vdupq_n_s32(-lp_quantization))));
+
+ tmp_vec[0] = tmp_vec[12];
+ }
+ }
+ }
+ }
+ else {
+ if(order > 2) {
+ if(order == 4) {
+ int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]};
+
+ for (i = 0; i < (int)data_len - 11; i += 12)
+ {
+ int32x4_t summ_0, summ_1, summ_2;
+ tmp_vec[0] = vld1q_s32(data + i - 4);
+ tmp_vec[1] = vld1q_s32(data + i - 3);
+ tmp_vec[2] = vld1q_s32(data + i - 2);
+ tmp_vec[3] = vld1q_s32(data + i - 1);
+ tmp_vec[4] = vld1q_s32(data + i - 0);
+ tmp_vec[5] = vld1q_s32(data + i + 1);
+ tmp_vec[6] = vld1q_s32(data + i + 2);
+ tmp_vec[7] = vld1q_s32(data + i + 3);
+ tmp_vec[8] = vld1q_s32(data + i + 4);
+ tmp_vec[9] = vld1q_s32(data + i + 5);
+ tmp_vec[10] = vld1q_s32(data + i + 6);
+ tmp_vec[11] = vld1q_s32(data + i + 7);
+
+ MUL_32_BIT_LOOP_UNROOL_3(qlp_coeff_0, 3)
+ MACC_32BIT_LOOP_UNROOL_3(1, qlp_coeff_0, 2)
+ MACC_32BIT_LOOP_UNROOL_3(2, qlp_coeff_0, 1)
+ MACC_32BIT_LOOP_UNROOL_3(3, qlp_coeff_0, 0)
+
+ vst1q_s32(residual+i + 0, vsubq_s32(vld1q_s32(data+i + 0) , vshlq_s32(summ_0,vdupq_n_s32(-lp_quantization))));
+ vst1q_s32(residual+i + 4, vsubq_s32(vld1q_s32(data+i + 4) , vshlq_s32(summ_1,vdupq_n_s32(-lp_quantization))));
+ vst1q_s32(residual+i + 8, vsubq_s32(vld1q_s32(data+i + 8) , vshlq_s32(summ_2,vdupq_n_s32(-lp_quantization))));
+ }
+ }
+ else { /* order == 3 */
+ int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], 0};
+
+ for (i = 0; i < (int)data_len - 11; i += 12)
+ {
+ int32x4_t summ_0, summ_1, summ_2;
+ tmp_vec[0] = vld1q_s32(data + i - 3);
+ tmp_vec[1] = vld1q_s32(data + i - 2);
+ tmp_vec[2] = vld1q_s32(data + i - 1);
+ tmp_vec[4] = vld1q_s32(data + i + 1);
+ tmp_vec[5] = vld1q_s32(data + i + 2);
+ tmp_vec[6] = vld1q_s32(data + i + 3);
+ tmp_vec[8] = vld1q_s32(data + i + 5);
+ tmp_vec[9] = vld1q_s32(data + i + 6);
+ tmp_vec[10] = vld1q_s32(data + i + 7);
+
+ MUL_32_BIT_LOOP_UNROOL_3(qlp_coeff_0, 2)
+ MACC_32BIT_LOOP_UNROOL_3(1, qlp_coeff_0, 1)
+ MACC_32BIT_LOOP_UNROOL_3(2, qlp_coeff_0, 0)
+
+ vst1q_s32(residual+i + 0, vsubq_s32(vld1q_s32(data+i + 0) , vshlq_s32(summ_0,vdupq_n_s32(-lp_quantization))));
+ vst1q_s32(residual+i + 4, vsubq_s32(vld1q_s32(data+i + 4) , vshlq_s32(summ_1,vdupq_n_s32(-lp_quantization))));
+ vst1q_s32(residual+i + 8, vsubq_s32(vld1q_s32(data+i + 8) , vshlq_s32(summ_2,vdupq_n_s32(-lp_quantization))));
+ }
+ }
+ }
+ else {
+ if(order == 2) {
+ int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], 0, 0};
+
+ for (i = 0; i < (int)data_len - 11; i += 12)
+ {
+ int32x4_t summ_0, summ_1, summ_2;
+ tmp_vec[0] = vld1q_s32(data + i - 2);
+ tmp_vec[1] = vld1q_s32(data + i - 1);
+ tmp_vec[4] = vld1q_s32(data + i + 2);
+ tmp_vec[5] = vld1q_s32(data + i + 3);
+ tmp_vec[8] = vld1q_s32(data + i + 6);
+ tmp_vec[9] = vld1q_s32(data + i + 7);
+
+ MUL_32_BIT_LOOP_UNROOL_3(qlp_coeff_0, 1)
+ MACC_32BIT_LOOP_UNROOL_3(1, qlp_coeff_0, 0)
+
+ vst1q_s32(residual+i + 0, vsubq_s32(vld1q_s32(data+i + 0) , vshlq_s32(summ_0,vdupq_n_s32(-lp_quantization))));
+ vst1q_s32(residual+i + 4, vsubq_s32(vld1q_s32(data+i + 4) , vshlq_s32(summ_1,vdupq_n_s32(-lp_quantization))));
+ vst1q_s32(residual+i + 8, vsubq_s32(vld1q_s32(data+i + 8) , vshlq_s32(summ_2,vdupq_n_s32(-lp_quantization))));
+ }
+ }
+ else { /* order == 1 */
+ int32x4_t qlp_coeff_0 = vdupq_n_s32(qlp_coeff[0]);
+
+ for (i = 0; i < (int)data_len - 11; i += 12)
+ {
+ int32x4_t summ_0, summ_1, summ_2;
+ tmp_vec[0] = vld1q_s32(data + i - 1);
+ tmp_vec[4] = vld1q_s32(data + i + 3);
+ tmp_vec[8] = vld1q_s32(data + i + 7);
+
+ summ_0 = vmulq_s32(tmp_vec[0], qlp_coeff_0);
+ summ_1 = vmulq_s32(tmp_vec[4], qlp_coeff_0);
+ summ_2 = vmulq_s32(tmp_vec[8], qlp_coeff_0);
+
+ vst1q_s32(residual+i + 0, vsubq_s32(vld1q_s32(data+i + 0) , vshlq_s32(summ_0,vdupq_n_s32(-lp_quantization))));
+ vst1q_s32(residual+i + 4, vsubq_s32(vld1q_s32(data+i + 4) , vshlq_s32(summ_1,vdupq_n_s32(-lp_quantization))));
+ vst1q_s32(residual+i + 8, vsubq_s32(vld1q_s32(data+i + 8) , vshlq_s32(summ_2,vdupq_n_s32(-lp_quantization))));
+ }
+ }
+ }
+ }
+ for(; i < (int)data_len; i++) {
+ sum = 0;
+ switch(order) {
+ case 12: sum += qlp_coeff[11] * data[i-12]; /* Falls through. */
+ case 11: sum += qlp_coeff[10] * data[i-11]; /* Falls through. */
+ case 10: sum += qlp_coeff[ 9] * data[i-10]; /* Falls through. */
+ case 9: sum += qlp_coeff[ 8] * data[i- 9]; /* Falls through. */
+ case 8: sum += qlp_coeff[ 7] * data[i- 8]; /* Falls through. */
+ case 7: sum += qlp_coeff[ 6] * data[i- 7]; /* Falls through. */
+ case 6: sum += qlp_coeff[ 5] * data[i- 6]; /* Falls through. */
+ case 5: sum += qlp_coeff[ 4] * data[i- 5]; /* Falls through. */
+ case 4: sum += qlp_coeff[ 3] * data[i- 4]; /* Falls through. */
+ case 3: sum += qlp_coeff[ 2] * data[i- 3]; /* Falls through. */
+ case 2: sum += qlp_coeff[ 1] * data[i- 2]; /* Falls through. */
+ case 1: sum += qlp_coeff[ 0] * data[i- 1];
+ }
+ residual[i] = data[i] - (sum >> 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]; /* Falls through. */
+ case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */
+ case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */
+ case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */
+ case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */
+ case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */
+ case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */
+ case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */
+ case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */
+ case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */
+ case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */
+ case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */
+ case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */
+ case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */
+ case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */
+ case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */
+ case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */
+ case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */
+ case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */
+ 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);
+ }
+ }
+}
+
+
+
+#define MUL_64_BIT_LOOP_UNROOL_3(qlp_coeff_vec, lane) \
+ summ_l_0 = vmull_laneq_s32(vget_low_s32(tmp_vec[0]),qlp_coeff_vec, lane); \
+ summ_h_0 = vmull_high_laneq_s32(tmp_vec[0], qlp_coeff_vec, lane);\
+ summ_l_1 = vmull_laneq_s32(vget_low_s32(tmp_vec[4]),qlp_coeff_vec, lane); \
+ summ_h_1 = vmull_high_laneq_s32(tmp_vec[4], qlp_coeff_vec, lane);\
+ summ_l_2 = vmull_laneq_s32(vget_low_s32(tmp_vec[8]),qlp_coeff_vec, lane);\
+ summ_h_2 = vmull_high_laneq_s32(tmp_vec[8], qlp_coeff_vec, lane);
+
+
+#define MACC_64_BIT_LOOP_UNROOL_3(tmp_vec_ind, qlp_coeff_vec, lane) \
+ summ_l_0 = vmlal_laneq_s32(summ_l_0,vget_low_s32(tmp_vec[tmp_vec_ind]),qlp_coeff_vec, lane); \
+ summ_h_0 = vmlal_high_laneq_s32(summ_h_0, tmp_vec[tmp_vec_ind], qlp_coeff_vec, lane); \
+ summ_l_1 = vmlal_laneq_s32(summ_l_1, vget_low_s32(tmp_vec[tmp_vec_ind+4]),qlp_coeff_vec, lane); \
+ summ_h_1 = vmlal_high_laneq_s32(summ_h_1, tmp_vec[tmp_vec_ind+4], qlp_coeff_vec, lane); \
+ summ_l_2 = vmlal_laneq_s32(summ_l_2, vget_low_s32(tmp_vec[tmp_vec_ind+8]),qlp_coeff_vec, lane);\
+ summ_h_2 = vmlal_high_laneq_s32(summ_h_2,tmp_vec[tmp_vec_ind+8], qlp_coeff_vec, lane);
+
+#define SHIFT_SUMS_64BITS_AND_STORE_SUB() \
+ res0 = vuzp1q_s32(vreinterpretq_s32_s64(vshlq_s64(summ_l_0,lp_quantization_vec)), vreinterpretq_s32_s64(vshlq_s64(summ_h_0,lp_quantization_vec))); \
+ res1 = vuzp1q_s32(vreinterpretq_s32_s64(vshlq_s64(summ_l_1,lp_quantization_vec)), vreinterpretq_s32_s64(vshlq_s64(summ_h_1,lp_quantization_vec))); \
+ res2 = vuzp1q_s32(vreinterpretq_s32_s64(vshlq_s64(summ_l_2,lp_quantization_vec)), vreinterpretq_s32_s64(vshlq_s64(summ_h_2,lp_quantization_vec))); \
+ vst1q_s32(residual+i+0, vsubq_s32(vld1q_s32(data+i+0), res0));\
+ vst1q_s32(residual+i+4, vsubq_s32(vld1q_s32(data+i+4), res1));\
+ vst1q_s32(residual+i+8, vsubq_s32(vld1q_s32(data+i+8), res2));
+
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_neon(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]) {
+ int i;
+ FLAC__int64 sum;
+
+ int32x4_t tmp_vec[20];
+ int32x4_t res0, res1, res2;
+ int64x2_t lp_quantization_vec = vdupq_n_s64(-lp_quantization);
+
+ FLAC__ASSERT(order > 0);
+ FLAC__ASSERT(order <= 32);
+
+ // Using prologue reads is valid as encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit(signal+order,....)
+ if(order <= 12) {
+ if(order > 8) {
+ if(order > 10) {
+ if(order == 12) {
+ int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]};
+ int32x4_t qlp_coeff_1 = {qlp_coeff[4],qlp_coeff[5],qlp_coeff[6],qlp_coeff[7]};
+ int32x4_t qlp_coeff_2 = {qlp_coeff[8],qlp_coeff[9],qlp_coeff[10],qlp_coeff[11]};
+
+ tmp_vec[0] = vld1q_s32(data - 12);
+ tmp_vec[1] = vld1q_s32(data - 11);
+ tmp_vec[2] = vld1q_s32(data - 10);
+ tmp_vec[3] = vld1q_s32(data - 9);
+ tmp_vec[4] = vld1q_s32(data - 8);
+ tmp_vec[5] = vld1q_s32(data - 7);
+ tmp_vec[6] = vld1q_s32(data - 6);
+ tmp_vec[7] = vld1q_s32(data - 5);
+
+ for (i = 0; i < (int)data_len - 11; i += 12)
+ {
+ int64x2_t summ_l_0, summ_h_0, summ_l_1, summ_h_1, summ_l_2, summ_h_2;
+
+ tmp_vec[8] = vld1q_s32(data+i-4);
+ tmp_vec[9] = vld1q_s32(data+i-3);
+ tmp_vec[10] = vld1q_s32(data+i-2);
+ tmp_vec[11] = vld1q_s32(data+i-1);
+ tmp_vec[12] = vld1q_s32(data+i);
+ tmp_vec[13] = vld1q_s32(data+i+1);
+ tmp_vec[14] = vld1q_s32(data+i+2);
+ tmp_vec[15] = vld1q_s32(data+i+3);
+ tmp_vec[16] = vld1q_s32(data + i + 4);
+ tmp_vec[17] = vld1q_s32(data + i + 5);
+ tmp_vec[18] = vld1q_s32(data + i + 6);
+ tmp_vec[19] = vld1q_s32(data + i + 7);
+
+ MUL_64_BIT_LOOP_UNROOL_3(qlp_coeff_2, 3)
+ MACC_64_BIT_LOOP_UNROOL_3(1, qlp_coeff_2, 2)
+ MACC_64_BIT_LOOP_UNROOL_3(2, qlp_coeff_2, 1)
+ MACC_64_BIT_LOOP_UNROOL_3(3, qlp_coeff_2, 0)
+ MACC_64_BIT_LOOP_UNROOL_3(4, qlp_coeff_1, 3)
+ MACC_64_BIT_LOOP_UNROOL_3(5, qlp_coeff_1, 2)
+ MACC_64_BIT_LOOP_UNROOL_3(6, qlp_coeff_1, 1)
+ MACC_64_BIT_LOOP_UNROOL_3(7, qlp_coeff_1, 0)
+ MACC_64_BIT_LOOP_UNROOL_3(8, qlp_coeff_0, 3)
+ MACC_64_BIT_LOOP_UNROOL_3(9, qlp_coeff_0, 2)
+ MACC_64_BIT_LOOP_UNROOL_3(10,qlp_coeff_0, 1)
+ MACC_64_BIT_LOOP_UNROOL_3(11,qlp_coeff_0, 0)
+
+ SHIFT_SUMS_64BITS_AND_STORE_SUB()
+
+ tmp_vec[0] = tmp_vec[12];
+ tmp_vec[1] = tmp_vec[13];
+ tmp_vec[2] = tmp_vec[14];
+ tmp_vec[3] = tmp_vec[15];
+ tmp_vec[4] = tmp_vec[16];
+ tmp_vec[5] = tmp_vec[17];
+ tmp_vec[6] = tmp_vec[18];
+ tmp_vec[7] = tmp_vec[19];
+ }
+ }
+ else { /* order == 11 */
+ int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]};
+ int32x4_t qlp_coeff_1 = {qlp_coeff[4],qlp_coeff[5],qlp_coeff[6],qlp_coeff[7]};
+ int32x4_t qlp_coeff_2 = {qlp_coeff[8],qlp_coeff[9],qlp_coeff[10],0};
+
+ tmp_vec[0] = vld1q_s32(data - 11);
+ tmp_vec[1] = vld1q_s32(data - 10);
+ tmp_vec[2] = vld1q_s32(data - 9);
+ tmp_vec[3] = vld1q_s32(data - 8);
+ tmp_vec[4] = vld1q_s32(data - 7);
+ tmp_vec[5] = vld1q_s32(data - 6);
+ tmp_vec[6] = vld1q_s32(data - 5);
+
+ for (i = 0; i < (int)data_len - 11; i += 12)
+ {
+ int64x2_t summ_l_0, summ_h_0, summ_l_1, summ_h_1, summ_l_2, summ_h_2;
+
+ tmp_vec[7] = vld1q_s32(data+i-4);
+ tmp_vec[8] = vld1q_s32(data+i-3);
+ tmp_vec[9] = vld1q_s32(data+i-2);
+ tmp_vec[10] = vld1q_s32(data+i-1);
+ tmp_vec[11] = vld1q_s32(data+i);
+ tmp_vec[12] = vld1q_s32(data+i+1);
+ tmp_vec[13] = vld1q_s32(data+i+2);
+ tmp_vec[14] = vld1q_s32(data+i+3);
+ tmp_vec[15] = vld1q_s32(data + i + 4);
+ tmp_vec[16] = vld1q_s32(data + i + 5);
+ tmp_vec[17] = vld1q_s32(data + i + 6);
+ tmp_vec[18] = vld1q_s32(data + i + 7);
+
+ MUL_64_BIT_LOOP_UNROOL_3(qlp_coeff_2, 2)
+ MACC_64_BIT_LOOP_UNROOL_3(1, qlp_coeff_2, 1)
+ MACC_64_BIT_LOOP_UNROOL_3(2, qlp_coeff_2, 0)
+ MACC_64_BIT_LOOP_UNROOL_3(3, qlp_coeff_1, 3)
+ MACC_64_BIT_LOOP_UNROOL_3(4, qlp_coeff_1, 2)
+ MACC_64_BIT_LOOP_UNROOL_3(5, qlp_coeff_1, 1)
+ MACC_64_BIT_LOOP_UNROOL_3(6, qlp_coeff_1, 0)
+ MACC_64_BIT_LOOP_UNROOL_3(7, qlp_coeff_0, 3)
+ MACC_64_BIT_LOOP_UNROOL_3(8, qlp_coeff_0, 2)
+ MACC_64_BIT_LOOP_UNROOL_3(9, qlp_coeff_0, 1)
+ MACC_64_BIT_LOOP_UNROOL_3(10,qlp_coeff_0, 0)
+
+ SHIFT_SUMS_64BITS_AND_STORE_SUB()
+
+ tmp_vec[0] = tmp_vec[12];
+ tmp_vec[1] = tmp_vec[13];
+ tmp_vec[2] = tmp_vec[14];
+ tmp_vec[3] = tmp_vec[15];
+ tmp_vec[4] = tmp_vec[16];
+ tmp_vec[5] = tmp_vec[17];
+ tmp_vec[6] = tmp_vec[18];
+ }
+ }
+ }
+ else
+ {
+ if (order == 10) {
+ int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]};
+ int32x4_t qlp_coeff_1 = {qlp_coeff[4], qlp_coeff[5], qlp_coeff[6], qlp_coeff[7]};
+ int32x4_t qlp_coeff_2 = {qlp_coeff[8], qlp_coeff[9], 0, 0};
+
+ tmp_vec[0] = vld1q_s32(data - 10);
+ tmp_vec[1] = vld1q_s32(data - 9);
+ tmp_vec[2] = vld1q_s32(data - 8);
+ tmp_vec[3] = vld1q_s32(data - 7);
+ tmp_vec[4] = vld1q_s32(data - 6);
+ tmp_vec[5] = vld1q_s32(data - 5);
+
+
+ for (i = 0; i < (int)data_len - 11; i += 12)
+ {
+ int64x2_t summ_l_0, summ_h_0, summ_l_1, summ_h_1, summ_l_2, summ_h_2;
+
+ tmp_vec[6] = vld1q_s32(data + i - 4);
+ tmp_vec[7] = vld1q_s32(data + i - 3);
+ tmp_vec[8] = vld1q_s32(data + i - 2);
+ tmp_vec[9] = vld1q_s32(data + i - 1);
+ tmp_vec[10] = vld1q_s32(data + i - 0);
+ tmp_vec[11] = vld1q_s32(data + i + 1);
+ tmp_vec[12] = vld1q_s32(data + i + 2);
+ tmp_vec[13] = vld1q_s32(data + i + 3);
+ tmp_vec[14] = vld1q_s32(data + i + 4);
+ tmp_vec[15] = vld1q_s32(data + i + 5);
+ tmp_vec[16] = vld1q_s32(data + i + 6);
+ tmp_vec[17] = vld1q_s32(data + i + 7);
+
+ MUL_64_BIT_LOOP_UNROOL_3(qlp_coeff_2, 1)
+ MACC_64_BIT_LOOP_UNROOL_3(1, qlp_coeff_2, 0)
+ MACC_64_BIT_LOOP_UNROOL_3(2, qlp_coeff_1, 3)
+ MACC_64_BIT_LOOP_UNROOL_3(3, qlp_coeff_1, 2)
+ MACC_64_BIT_LOOP_UNROOL_3(4, qlp_coeff_1, 1)
+ MACC_64_BIT_LOOP_UNROOL_3(5, qlp_coeff_1, 0)
+ MACC_64_BIT_LOOP_UNROOL_3(6, qlp_coeff_0, 3)
+ MACC_64_BIT_LOOP_UNROOL_3(7, qlp_coeff_0, 2)
+ MACC_64_BIT_LOOP_UNROOL_3(8, qlp_coeff_0, 1)
+ MACC_64_BIT_LOOP_UNROOL_3(9, qlp_coeff_0, 0)
+
+ SHIFT_SUMS_64BITS_AND_STORE_SUB()
+
+ tmp_vec[0] = tmp_vec[12];
+ tmp_vec[1] = tmp_vec[13];
+ tmp_vec[2] = tmp_vec[14];
+ tmp_vec[3] = tmp_vec[15];
+ tmp_vec[4] = tmp_vec[16];
+ tmp_vec[5] = tmp_vec[17];
+ }
+ }
+
+ else /* order == 9 */ {
+ int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]};
+ int32x4_t qlp_coeff_1 = {qlp_coeff[4], qlp_coeff[5], qlp_coeff[6], qlp_coeff[7]};
+ int32x4_t qlp_coeff_2 = {qlp_coeff[8], 0, 0, 0};
+
+ tmp_vec[0] = vld1q_s32(data - 9);
+ tmp_vec[1] = vld1q_s32(data - 8);
+ tmp_vec[2] = vld1q_s32(data - 7);
+ tmp_vec[3] = vld1q_s32(data - 6);
+ tmp_vec[4] = vld1q_s32(data - 5);
+
+ for (i = 0; i < (int)data_len - 11; i += 12)
+ {
+ int64x2_t summ_l_0, summ_h_0, summ_l_1, summ_h_1, summ_l_2, summ_h_2;
+
+ tmp_vec[5] = vld1q_s32(data + i - 4);
+ tmp_vec[6] = vld1q_s32(data + i - 3);
+ tmp_vec[7] = vld1q_s32(data + i - 2);
+ tmp_vec[8] = vld1q_s32(data + i - 1);
+ tmp_vec[9] = vld1q_s32(data + i - 0);
+ tmp_vec[10] = vld1q_s32(data + i + 1);
+ tmp_vec[11] = vld1q_s32(data + i + 2);
+ tmp_vec[12] = vld1q_s32(data + i + 3);
+ tmp_vec[13] = vld1q_s32(data + i + 4);
+ tmp_vec[14] = vld1q_s32(data + i + 5);
+ tmp_vec[15] = vld1q_s32(data + i + 6);
+ tmp_vec[16] = vld1q_s32(data + i + 7);
+
+ MUL_64_BIT_LOOP_UNROOL_3(qlp_coeff_2, 0)
+ MACC_64_BIT_LOOP_UNROOL_3(1, qlp_coeff_1, 3)
+ MACC_64_BIT_LOOP_UNROOL_3(2, qlp_coeff_1, 2)
+ MACC_64_BIT_LOOP_UNROOL_3(3, qlp_coeff_1, 1)
+ MACC_64_BIT_LOOP_UNROOL_3(4, qlp_coeff_1, 0)
+ MACC_64_BIT_LOOP_UNROOL_3(5, qlp_coeff_0, 3)
+ MACC_64_BIT_LOOP_UNROOL_3(6, qlp_coeff_0, 2)
+ MACC_64_BIT_LOOP_UNROOL_3(7, qlp_coeff_0, 1)
+ MACC_64_BIT_LOOP_UNROOL_3(8, qlp_coeff_0, 0)
+
+ SHIFT_SUMS_64BITS_AND_STORE_SUB()
+
+ tmp_vec[0] = tmp_vec[12];
+ tmp_vec[1] = tmp_vec[13];
+ tmp_vec[2] = tmp_vec[14];
+ tmp_vec[3] = tmp_vec[15];
+ tmp_vec[4] = tmp_vec[16];
+ }
+ }
+ }
+ }
+ else if (order > 4)
+ {
+ if (order > 6)
+ {
+ if (order == 8)
+ {
+ int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]};
+ int32x4_t qlp_coeff_1 = {qlp_coeff[4], qlp_coeff[5], qlp_coeff[6], qlp_coeff[7]};
+
+ tmp_vec[0] = vld1q_s32(data - 8);
+ tmp_vec[1] = vld1q_s32(data - 7);
+ tmp_vec[2] = vld1q_s32(data - 6);
+ tmp_vec[3] = vld1q_s32(data - 5);
+
+ for (i = 0; i < (int)data_len - 11; i += 12)
+ {
+ int64x2_t summ_l_0, summ_h_0, summ_l_1, summ_h_1, summ_l_2, summ_h_2;
+
+ tmp_vec[4] = vld1q_s32(data + i - 4);
+ tmp_vec[5] = vld1q_s32(data + i - 3);
+ tmp_vec[6] = vld1q_s32(data + i - 2);
+ tmp_vec[7] = vld1q_s32(data + i - 1);
+ tmp_vec[8] = vld1q_s32(data + i - 0);
+ tmp_vec[9] = vld1q_s32(data + i + 1);
+ tmp_vec[10] = vld1q_s32(data + i + 2);
+ tmp_vec[11] = vld1q_s32(data + i + 3);
+ tmp_vec[12] = vld1q_s32(data + i + 4);
+ tmp_vec[13] = vld1q_s32(data + i + 5);
+ tmp_vec[14] = vld1q_s32(data + i + 6);
+ tmp_vec[15] = vld1q_s32(data + i + 7);
+
+
+ MUL_64_BIT_LOOP_UNROOL_3(qlp_coeff_1, 3)
+ MACC_64_BIT_LOOP_UNROOL_3(1, qlp_coeff_1, 2)
+ MACC_64_BIT_LOOP_UNROOL_3(2, qlp_coeff_1, 1)
+ MACC_64_BIT_LOOP_UNROOL_3(3, qlp_coeff_1, 0)
+ MACC_64_BIT_LOOP_UNROOL_3(4, qlp_coeff_0, 3)
+ MACC_64_BIT_LOOP_UNROOL_3(5, qlp_coeff_0, 2)
+ MACC_64_BIT_LOOP_UNROOL_3(6, qlp_coeff_0, 1)
+ MACC_64_BIT_LOOP_UNROOL_3(7, qlp_coeff_0, 0)
+
+ SHIFT_SUMS_64BITS_AND_STORE_SUB()
+
+ tmp_vec[0] = tmp_vec[12];
+ tmp_vec[1] = tmp_vec[13];
+ tmp_vec[2] = tmp_vec[14];
+ tmp_vec[3] = tmp_vec[15];
+ }
+ }
+ else /* order == 7 */
+ {
+ int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]};
+ int32x4_t qlp_coeff_1 = {qlp_coeff[4], qlp_coeff[5], qlp_coeff[6], 0};
+
+ tmp_vec[0] = vld1q_s32(data - 7);
+ tmp_vec[1] = vld1q_s32(data - 6);
+ tmp_vec[2] = vld1q_s32(data - 5);
+
+
+ for (i = 0; i < (int)data_len - 11; i += 12)
+ {
+ int64x2_t summ_l_0, summ_h_0, summ_l_1, summ_h_1, summ_l_2, summ_h_2;
+ tmp_vec[3] = vld1q_s32(data +i - 4);
+ tmp_vec[4] = vld1q_s32(data + i - 3);
+ tmp_vec[5] = vld1q_s32(data + i - 2);
+ tmp_vec[6] = vld1q_s32(data + i - 1);
+ tmp_vec[7] = vld1q_s32(data + i - 0);
+ tmp_vec[8] = vld1q_s32(data + i + 1);
+ tmp_vec[9] = vld1q_s32(data + i + 2);
+ tmp_vec[10] = vld1q_s32(data + i + 3);
+ tmp_vec[11] = vld1q_s32(data + i + 4);
+ tmp_vec[12] = vld1q_s32(data + i + 5);
+ tmp_vec[13] = vld1q_s32(data + i + 6);
+ tmp_vec[14] = vld1q_s32(data + i + 7);
+
+
+ MUL_64_BIT_LOOP_UNROOL_3(qlp_coeff_1, 2)
+ MACC_64_BIT_LOOP_UNROOL_3(1, qlp_coeff_1, 1)
+ MACC_64_BIT_LOOP_UNROOL_3(2, qlp_coeff_1, 0)
+ MACC_64_BIT_LOOP_UNROOL_3(3, qlp_coeff_0, 3)
+ MACC_64_BIT_LOOP_UNROOL_3(4, qlp_coeff_0, 2)
+ MACC_64_BIT_LOOP_UNROOL_3(5, qlp_coeff_0, 1)
+ MACC_64_BIT_LOOP_UNROOL_3(6, qlp_coeff_0, 0)
+
+ SHIFT_SUMS_64BITS_AND_STORE_SUB()
+
+ tmp_vec[0] = tmp_vec[12];
+ tmp_vec[1] = tmp_vec[13];
+ tmp_vec[2] = tmp_vec[14];
+ }
+ }
+ }
+ else
+ {
+ if (order == 6) {
+ int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]};
+ int32x4_t qlp_coeff_1 = {qlp_coeff[4], qlp_coeff[5], 0, 0};
+
+ tmp_vec[0] = vld1q_s32(data - 6);
+ tmp_vec[1] = vld1q_s32(data - 5);
+
+ for (i = 0; i < (int)data_len - 11; i += 12)
+ {
+ int64x2_t summ_l_0, summ_h_0, summ_l_1, summ_h_1, summ_l_2, summ_h_2;
+
+ tmp_vec[2] = vld1q_s32(data + i - 4);
+ tmp_vec[3] = vld1q_s32(data + i - 3);
+ tmp_vec[4] = vld1q_s32(data + i - 2);
+ tmp_vec[5] = vld1q_s32(data + i - 1);
+ tmp_vec[6] = vld1q_s32(data + i - 0);
+ tmp_vec[7] = vld1q_s32(data + i + 1);
+ tmp_vec[8] = vld1q_s32(data + i + 2);
+ tmp_vec[9] = vld1q_s32(data + i + 3);
+ tmp_vec[10] = vld1q_s32(data + i + 4);
+ tmp_vec[11] = vld1q_s32(data + i + 5);
+ tmp_vec[12] = vld1q_s32(data + i + 6);
+ tmp_vec[13] = vld1q_s32(data + i + 7);
+
+
+ MUL_64_BIT_LOOP_UNROOL_3(qlp_coeff_1, 1)
+ MACC_64_BIT_LOOP_UNROOL_3(1, qlp_coeff_1, 0)
+ MACC_64_BIT_LOOP_UNROOL_3(2, qlp_coeff_0, 3)
+ MACC_64_BIT_LOOP_UNROOL_3(3, qlp_coeff_0, 2)
+ MACC_64_BIT_LOOP_UNROOL_3(4, qlp_coeff_0, 1)
+ MACC_64_BIT_LOOP_UNROOL_3(5, qlp_coeff_0, 0)
+
+ SHIFT_SUMS_64BITS_AND_STORE_SUB()
+
+ tmp_vec[0] = tmp_vec[12];
+ tmp_vec[1] = tmp_vec[13];
+ }
+ }
+
+ else
+ { /* order == 5 */
+ int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]};
+ int32x4_t qlp_coeff_1 = {qlp_coeff[4], 0, 0, 0};
+
+ tmp_vec[0] = vld1q_s32(data - 5);
+
+ for (i = 0; i < (int)data_len - 11; i += 12)
+ {
+ int64x2_t summ_l_0, summ_h_0, summ_l_1, summ_h_1, summ_l_2, summ_h_2;
+ tmp_vec[1] = vld1q_s32(data + i - 4);
+ tmp_vec[2] = vld1q_s32(data + i - 3);
+ tmp_vec[3] = vld1q_s32(data + i - 2);
+ tmp_vec[4] = vld1q_s32(data + i - 1);
+ tmp_vec[5] = vld1q_s32(data + i - 0);
+ tmp_vec[6] = vld1q_s32(data + i + 1);
+ tmp_vec[7] = vld1q_s32(data + i + 2);
+ tmp_vec[8] = vld1q_s32(data + i + 3);
+ tmp_vec[9] = vld1q_s32(data + i + 4);
+ tmp_vec[10] = vld1q_s32(data + i + 5);
+ tmp_vec[11] = vld1q_s32(data + i + 6);
+ tmp_vec[12] = vld1q_s32(data + i + 7);
+
+ MUL_64_BIT_LOOP_UNROOL_3(qlp_coeff_1, 0)
+ MACC_64_BIT_LOOP_UNROOL_3(1, qlp_coeff_0, 3)
+ MACC_64_BIT_LOOP_UNROOL_3(2, qlp_coeff_0, 2)
+ MACC_64_BIT_LOOP_UNROOL_3(3, qlp_coeff_0, 1)
+ MACC_64_BIT_LOOP_UNROOL_3(4, qlp_coeff_0, 0)
+
+ SHIFT_SUMS_64BITS_AND_STORE_SUB()
+
+ tmp_vec[0] = tmp_vec[12];
+ }
+ }
+ }
+ }
+ else
+ {
+ if (order > 2)
+ {
+ if (order == 4)
+ {
+ int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], qlp_coeff[3]};
+
+ for (i = 0; i < (int)data_len - 11; i += 12)
+ {
+ int64x2_t summ_l_0, summ_h_0, summ_l_1, summ_h_1, summ_l_2, summ_h_2;
+ tmp_vec[0] = vld1q_s32(data + i - 4);
+ tmp_vec[1] = vld1q_s32(data + i - 3);
+ tmp_vec[2] = vld1q_s32(data + i - 2);
+ tmp_vec[3] = vld1q_s32(data + i - 1);
+ tmp_vec[4] = vld1q_s32(data + i - 0);
+ tmp_vec[5] = vld1q_s32(data + i + 1);
+ tmp_vec[6] = vld1q_s32(data + i + 2);
+ tmp_vec[7] = vld1q_s32(data + i + 3);
+ tmp_vec[8] = vld1q_s32(data + i + 4);
+ tmp_vec[9] = vld1q_s32(data + i + 5);
+ tmp_vec[10] = vld1q_s32(data + i + 6);
+ tmp_vec[11] = vld1q_s32(data + i + 7);
+
+ MUL_64_BIT_LOOP_UNROOL_3(qlp_coeff_0, 3)
+ MACC_64_BIT_LOOP_UNROOL_3(1, qlp_coeff_0, 2)
+ MACC_64_BIT_LOOP_UNROOL_3(2, qlp_coeff_0, 1)
+ MACC_64_BIT_LOOP_UNROOL_3(3, qlp_coeff_0, 0)
+
+ SHIFT_SUMS_64BITS_AND_STORE_SUB()
+ }
+ }
+ else
+ { /* order == 3 */
+
+ int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], qlp_coeff[2], 0};
+
+ for (i = 0; i < (int)data_len - 11; i += 12)
+ {
+ int64x2_t summ_l_0, summ_h_0, summ_l_1, summ_h_1, summ_l_2, summ_h_2;
+ tmp_vec[0] = vld1q_s32(data + i - 3);
+ tmp_vec[1] = vld1q_s32(data + i - 2);
+ tmp_vec[2] = vld1q_s32(data + i - 1);
+ tmp_vec[4] = vld1q_s32(data + i + 1);
+ tmp_vec[5] = vld1q_s32(data + i + 2);
+ tmp_vec[6] = vld1q_s32(data + i + 3);
+ tmp_vec[8] = vld1q_s32(data + i + 5);
+ tmp_vec[9] = vld1q_s32(data + i + 6);
+ tmp_vec[10] = vld1q_s32(data + i + 7);
+
+ MUL_64_BIT_LOOP_UNROOL_3(qlp_coeff_0, 2)
+ MACC_64_BIT_LOOP_UNROOL_3(1, qlp_coeff_0, 1)
+ MACC_64_BIT_LOOP_UNROOL_3(2, qlp_coeff_0, 0)
+
+ SHIFT_SUMS_64BITS_AND_STORE_SUB()
+ }
+ }
+ }
+ else
+ {
+ if (order == 2)
+ {
+ int32x4_t qlp_coeff_0 = {qlp_coeff[0], qlp_coeff[1], 0, 0};
+
+ for (i = 0; i < (int)data_len - 11; i += 12)
+ {
+ int64x2_t summ_l_0, summ_h_0, summ_l_1, summ_h_1, summ_l_2, summ_h_2;
+ tmp_vec[0] = vld1q_s32(data + i - 2);
+ tmp_vec[1] = vld1q_s32(data + i - 1);
+ tmp_vec[4] = vld1q_s32(data + i + 2);
+ tmp_vec[5] = vld1q_s32(data + i + 3);
+ tmp_vec[8] = vld1q_s32(data + i + 6);
+ tmp_vec[9] = vld1q_s32(data + i + 7);
+
+ MUL_64_BIT_LOOP_UNROOL_3(qlp_coeff_0, 1)
+ MACC_64_BIT_LOOP_UNROOL_3(1, qlp_coeff_0, 0)
+
+ SHIFT_SUMS_64BITS_AND_STORE_SUB()
+ }
+ }
+
+ else
+ { /* order == 1 */
+
+ int32x2_t qlp_coeff_0_2 = vdup_n_s32(qlp_coeff[0]);
+ int32x4_t qlp_coeff_0_4 = vdupq_n_s32(qlp_coeff[0]);
+
+ for (i = 0; i < (int)data_len - 11; i += 12)
+ {
+ int64x2_t summ_l_0, summ_h_0, summ_l_1, summ_h_1, summ_l_2, summ_h_2;
+ tmp_vec[0] = vld1q_s32(data + i - 1);
+ tmp_vec[4] = vld1q_s32(data + i + 3);
+ tmp_vec[8] = vld1q_s32(data + i + 7);
+
+ summ_l_0 = vmull_s32(vget_low_s32(tmp_vec[0]), qlp_coeff_0_2);
+ summ_h_0 = vmull_high_s32(tmp_vec[0], qlp_coeff_0_4);
+
+ summ_l_1 = vmull_s32(vget_low_s32(tmp_vec[4]), qlp_coeff_0_2);
+ summ_h_1 = vmull_high_s32(tmp_vec[4], qlp_coeff_0_4);
+
+ summ_l_2 = vmull_s32(vget_low_s32(tmp_vec[8]), qlp_coeff_0_2);
+ summ_h_2 = vmull_high_s32(tmp_vec[8], qlp_coeff_0_4);
+
+ SHIFT_SUMS_64BITS_AND_STORE_SUB()
+ }
+ }
+ }
+ }
+ for (; i < (int)data_len; i++)
+ {
+ sum = 0;
+ switch (order)
+ {
+ case 12:
+ sum += qlp_coeff[11] * (FLAC__int64)data[i - 12]; /* Falls through. */
+ case 11:
+ sum += qlp_coeff[10] * (FLAC__int64)data[i - 11]; /* Falls through. */
+ case 10:
+ sum += qlp_coeff[9] * (FLAC__int64)data[i - 10]; /* Falls through. */
+ case 9:
+ sum += qlp_coeff[8] * (FLAC__int64)data[i - 9]; /* Falls through. */
+ case 8:
+ sum += qlp_coeff[7] * (FLAC__int64)data[i - 8]; /* Falls through. */
+ case 7:
+ sum += qlp_coeff[6] * (FLAC__int64)data[i - 7]; /* Falls through. */
+ case 6:
+ sum += qlp_coeff[5] * (FLAC__int64)data[i - 6]; /* Falls through. */
+ case 5:
+ sum += qlp_coeff[4] * (FLAC__int64)data[i - 5]; /* Falls through. */
+ case 4:
+ sum += qlp_coeff[3] * (FLAC__int64)data[i - 4]; /* Falls through. */
+ case 3:
+ sum += qlp_coeff[2] * (FLAC__int64)data[i - 3]; /* Falls through. */
+ case 2:
+ sum += qlp_coeff[1] * (FLAC__int64)data[i - 2]; /* Falls through. */
+ case 1:
+ sum += qlp_coeff[0] * (FLAC__int64)data[i - 1];
+ }
+ residual[i] = data[i] - (sum >> 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]; /* Falls through. */
+ case 31:
+ sum += qlp_coeff[30] * (FLAC__int64)data[i - 31]; /* Falls through. */
+ case 30:
+ sum += qlp_coeff[29] * (FLAC__int64)data[i - 30]; /* Falls through. */
+ case 29:
+ sum += qlp_coeff[28] * (FLAC__int64)data[i - 29]; /* Falls through. */
+ case 28:
+ sum += qlp_coeff[27] * (FLAC__int64)data[i - 28]; /* Falls through. */
+ case 27:
+ sum += qlp_coeff[26] * (FLAC__int64)data[i - 27]; /* Falls through. */
+ case 26:
+ sum += qlp_coeff[25] * (FLAC__int64)data[i - 26]; /* Falls through. */
+ case 25:
+ sum += qlp_coeff[24] * (FLAC__int64)data[i - 25]; /* Falls through. */
+ case 24:
+ sum += qlp_coeff[23] * (FLAC__int64)data[i - 24]; /* Falls through. */
+ case 23:
+ sum += qlp_coeff[22] * (FLAC__int64)data[i - 23]; /* Falls through. */
+ case 22:
+ sum += qlp_coeff[21] * (FLAC__int64)data[i - 22]; /* Falls through. */
+ case 21:
+ sum += qlp_coeff[20] * (FLAC__int64)data[i - 21]; /* Falls through. */
+ case 20:
+ sum += qlp_coeff[19] * (FLAC__int64)data[i - 20]; /* Falls through. */
+ case 19:
+ sum += qlp_coeff[18] * (FLAC__int64)data[i - 19]; /* Falls through. */
+ case 18:
+ sum += qlp_coeff[17] * (FLAC__int64)data[i - 18]; /* Falls through. */
+ case 17:
+ sum += qlp_coeff[16] * (FLAC__int64)data[i - 17]; /* Falls through. */
+ case 16:
+ sum += qlp_coeff[15] * (FLAC__int64)data[i - 16]; /* Falls through. */
+ case 15:
+ sum += qlp_coeff[14] * (FLAC__int64)data[i - 15]; /* Falls through. */
+ case 14:
+ sum += qlp_coeff[13] * (FLAC__int64)data[i - 14]; /* Falls through. */
+ 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] - (sum >> lp_quantization);
+ }
+ }
+
+ return;
+}
+
+#endif /* FLAC__CPU_ARM64 && FLAC__HAS_ARCH64INTRIN */
+#endif /* FLAC__NO_ASM */
+#endif /* FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/src/libFLAC/lpc_intrin_sse2.c b/src/libFLAC/lpc_intrin_sse2.c
new file mode 100644
index 0000000..d16a085
--- /dev/null
+++ b/src/libFLAC/lpc_intrin_sse2.c
@@ -0,0 +1,966 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "private/cpu.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#ifndef FLAC__NO_ASM
+#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
+#include "private/lpc.h"
+#ifdef FLAC__SSE2_SUPPORTED
+
+#include "FLAC/assert.h"
+#include "FLAC/format.h"
+
+#include <emmintrin.h> /* SSE2 */
+
+#define RESIDUAL32_RESULT(xmmN) residual[i] = data[i] - (_mm_cvtsi128_si32(xmmN) >> lp_quantization);
+#define DATA32_RESULT(xmmN) data[i] = residual[i] + (_mm_cvtsi128_si32(xmmN) >> lp_quantization);
+
+
+FLAC__SSE_TARGET("sse2")
+void FLAC__lpc_compute_autocorrelation_intrin_sse2_lag_8(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[])
+{
+#undef MAX_LAG
+#define MAX_LAG 8
+#include "deduplication/lpc_compute_autocorrelation_intrin_sse2.c"
+}
+
+FLAC__SSE_TARGET("sse2")
+void FLAC__lpc_compute_autocorrelation_intrin_sse2_lag_10(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[])
+{
+#undef MAX_LAG
+#define MAX_LAG 10
+#include "deduplication/lpc_compute_autocorrelation_intrin_sse2.c"
+}
+
+
+FLAC__SSE_TARGET("sse2")
+void FLAC__lpc_compute_autocorrelation_intrin_sse2_lag_14(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[])
+{
+#undef MAX_LAG
+#define MAX_LAG 14
+#include "deduplication/lpc_compute_autocorrelation_intrin_sse2.c"
+}
+
+FLAC__SSE_TARGET("sse2")
+void FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_sse2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[])
+{
+ int i;
+ FLAC__int32 sum;
+ const __m128i cnt = _mm_cvtsi32_si128(lp_quantization);
+
+ FLAC__ASSERT(order > 0);
+ FLAC__ASSERT(order <= 32);
+
+ if(order <= 12) {
+ if(order > 8) {
+ if(order > 10) {
+ if(order == 12) {
+ __m128i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11;
+ q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+ q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+ q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+ q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+ q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+ q5 = _mm_cvtsi32_si128(0xffff & qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
+ q6 = _mm_cvtsi32_si128(0xffff & qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
+ q7 = _mm_cvtsi32_si128(0xffff & qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
+ q8 = _mm_cvtsi32_si128(0xffff & qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0));
+ q9 = _mm_cvtsi32_si128(0xffff & qlp_coeff[9]); q9 = _mm_shuffle_epi32(q9, _MM_SHUFFLE(0,0,0,0));
+ q10 = _mm_cvtsi32_si128(0xffff & qlp_coeff[10]); q10 = _mm_shuffle_epi32(q10, _MM_SHUFFLE(0,0,0,0));
+ q11 = _mm_cvtsi32_si128(0xffff & qlp_coeff[11]); q11 = _mm_shuffle_epi32(q11, _MM_SHUFFLE(0,0,0,0));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m128i summ, mull;
+ summ = _mm_madd_epi16(q11, _mm_loadu_si128((const __m128i*)(const void*)(data+i-12)));
+ mull = _mm_madd_epi16(q10, _mm_loadu_si128((const __m128i*)(const void*)(data+i-11))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q9, _mm_loadu_si128((const __m128i*)(const void*)(data+i-10))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q8, _mm_loadu_si128((const __m128i*)(const void*)(data+i-9))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q7, _mm_loadu_si128((const __m128i*)(const void*)(data+i-8))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q6, _mm_loadu_si128((const __m128i*)(const void*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q5, _mm_loadu_si128((const __m128i*)(const void*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+ summ = _mm_sra_epi32(summ, cnt);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ));
+ }
+ }
+ else { /* order == 11 */
+ __m128i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10;
+ q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+ q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+ q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+ q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+ q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+ q5 = _mm_cvtsi32_si128(0xffff & qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
+ q6 = _mm_cvtsi32_si128(0xffff & qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
+ q7 = _mm_cvtsi32_si128(0xffff & qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
+ q8 = _mm_cvtsi32_si128(0xffff & qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0));
+ q9 = _mm_cvtsi32_si128(0xffff & qlp_coeff[9]); q9 = _mm_shuffle_epi32(q9, _MM_SHUFFLE(0,0,0,0));
+ q10 = _mm_cvtsi32_si128(0xffff & qlp_coeff[10]); q10 = _mm_shuffle_epi32(q10, _MM_SHUFFLE(0,0,0,0));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m128i summ, mull;
+ summ = _mm_madd_epi16(q10, _mm_loadu_si128((const __m128i*)(const void*)(data+i-11)));
+ mull = _mm_madd_epi16(q9, _mm_loadu_si128((const __m128i*)(const void*)(data+i-10))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q8, _mm_loadu_si128((const __m128i*)(const void*)(data+i-9))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q7, _mm_loadu_si128((const __m128i*)(const void*)(data+i-8))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q6, _mm_loadu_si128((const __m128i*)(const void*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q5, _mm_loadu_si128((const __m128i*)(const void*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+ summ = _mm_sra_epi32(summ, cnt);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ));
+ }
+ }
+ }
+ else {
+ if(order == 10) {
+ __m128i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9;
+ q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+ q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+ q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+ q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+ q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+ q5 = _mm_cvtsi32_si128(0xffff & qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
+ q6 = _mm_cvtsi32_si128(0xffff & qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
+ q7 = _mm_cvtsi32_si128(0xffff & qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
+ q8 = _mm_cvtsi32_si128(0xffff & qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0));
+ q9 = _mm_cvtsi32_si128(0xffff & qlp_coeff[9]); q9 = _mm_shuffle_epi32(q9, _MM_SHUFFLE(0,0,0,0));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m128i summ, mull;
+ summ = _mm_madd_epi16(q9, _mm_loadu_si128((const __m128i*)(const void*)(data+i-10)));
+ mull = _mm_madd_epi16(q8, _mm_loadu_si128((const __m128i*)(const void*)(data+i-9))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q7, _mm_loadu_si128((const __m128i*)(const void*)(data+i-8))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q6, _mm_loadu_si128((const __m128i*)(const void*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q5, _mm_loadu_si128((const __m128i*)(const void*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+ summ = _mm_sra_epi32(summ, cnt);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ));
+ }
+ }
+ else { /* order == 9 */
+ __m128i q0, q1, q2, q3, q4, q5, q6, q7, q8;
+ q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+ q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+ q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+ q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+ q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+ q5 = _mm_cvtsi32_si128(0xffff & qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
+ q6 = _mm_cvtsi32_si128(0xffff & qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
+ q7 = _mm_cvtsi32_si128(0xffff & qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
+ q8 = _mm_cvtsi32_si128(0xffff & qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m128i summ, mull;
+ summ = _mm_madd_epi16(q8, _mm_loadu_si128((const __m128i*)(const void*)(data+i-9)));
+ mull = _mm_madd_epi16(q7, _mm_loadu_si128((const __m128i*)(const void*)(data+i-8))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q6, _mm_loadu_si128((const __m128i*)(const void*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q5, _mm_loadu_si128((const __m128i*)(const void*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+ summ = _mm_sra_epi32(summ, cnt);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ));
+ }
+ }
+ }
+ }
+ else if(order > 4) {
+ if(order > 6) {
+ if(order == 8) {
+ __m128i q0, q1, q2, q3, q4, q5, q6, q7;
+ q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+ q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+ q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+ q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+ q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+ q5 = _mm_cvtsi32_si128(0xffff & qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
+ q6 = _mm_cvtsi32_si128(0xffff & qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
+ q7 = _mm_cvtsi32_si128(0xffff & qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m128i summ, mull;
+ summ = _mm_madd_epi16(q7, _mm_loadu_si128((const __m128i*)(const void*)(data+i-8)));
+ mull = _mm_madd_epi16(q6, _mm_loadu_si128((const __m128i*)(const void*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q5, _mm_loadu_si128((const __m128i*)(const void*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+ summ = _mm_sra_epi32(summ, cnt);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ));
+ }
+ }
+ else { /* order == 7 */
+ __m128i q0, q1, q2, q3, q4, q5, q6;
+ q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+ q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+ q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+ q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+ q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+ q5 = _mm_cvtsi32_si128(0xffff & qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
+ q6 = _mm_cvtsi32_si128(0xffff & qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m128i summ, mull;
+ summ = _mm_madd_epi16(q6, _mm_loadu_si128((const __m128i*)(const void*)(data+i-7)));
+ mull = _mm_madd_epi16(q5, _mm_loadu_si128((const __m128i*)(const void*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+ summ = _mm_sra_epi32(summ, cnt);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ));
+ }
+ }
+ }
+ else {
+ if(order == 6) {
+ __m128i q0, q1, q2, q3, q4, q5;
+ q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+ q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+ q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+ q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+ q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+ q5 = _mm_cvtsi32_si128(0xffff & qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m128i summ, mull;
+ summ = _mm_madd_epi16(q5, _mm_loadu_si128((const __m128i*)(const void*)(data+i-6)));
+ mull = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+ summ = _mm_sra_epi32(summ, cnt);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ));
+ }
+ }
+ else { /* order == 5 */
+ __m128i q0, q1, q2, q3, q4;
+ q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+ q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+ q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+ q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+ q4 = _mm_cvtsi32_si128(0xffff & qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m128i summ, mull;
+ summ = _mm_madd_epi16(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5)));
+ mull = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+ summ = _mm_sra_epi32(summ, cnt);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ));
+ }
+ }
+ }
+ }
+ else {
+ if(order > 2) {
+ if(order == 4) {
+ __m128i q0, q1, q2, q3;
+ q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+ q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+ q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+ q3 = _mm_cvtsi32_si128(0xffff & qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m128i summ, mull;
+ summ = _mm_madd_epi16(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4)));
+ mull = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+ summ = _mm_sra_epi32(summ, cnt);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ));
+ }
+ }
+ else { /* order == 3 */
+ __m128i q0, q1, q2;
+ q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+ q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+ q2 = _mm_cvtsi32_si128(0xffff & qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m128i summ, mull;
+ summ = _mm_madd_epi16(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3)));
+ mull = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+ summ = _mm_sra_epi32(summ, cnt);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ));
+ }
+ }
+ }
+ else {
+ if(order == 2) {
+ __m128i q0, q1;
+ q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+ q1 = _mm_cvtsi32_si128(0xffff & qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m128i summ, mull;
+ summ = _mm_madd_epi16(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2)));
+ mull = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+ summ = _mm_sra_epi32(summ, cnt);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ));
+ }
+ }
+ else { /* order == 1 */
+ __m128i q0;
+ q0 = _mm_cvtsi32_si128(0xffff & qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m128i summ;
+ summ = _mm_madd_epi16(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1)));
+ summ = _mm_sra_epi32(summ, cnt);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ));
+ }
+ }
+ }
+ }
+ for(; i < (int)data_len; i++) {
+ sum = 0;
+ switch(order) {
+ case 12: sum += qlp_coeff[11] * data[i-12]; /* Falls through. */
+ case 11: sum += qlp_coeff[10] * data[i-11]; /* Falls through. */
+ case 10: sum += qlp_coeff[ 9] * data[i-10]; /* Falls through. */
+ case 9: sum += qlp_coeff[ 8] * data[i- 9]; /* Falls through. */
+ case 8: sum += qlp_coeff[ 7] * data[i- 8]; /* Falls through. */
+ case 7: sum += qlp_coeff[ 6] * data[i- 7]; /* Falls through. */
+ case 6: sum += qlp_coeff[ 5] * data[i- 6]; /* Falls through. */
+ case 5: sum += qlp_coeff[ 4] * data[i- 5]; /* Falls through. */
+ case 4: sum += qlp_coeff[ 3] * data[i- 4]; /* Falls through. */
+ case 3: sum += qlp_coeff[ 2] * data[i- 3]; /* Falls through. */
+ case 2: sum += qlp_coeff[ 1] * data[i- 2]; /* Falls through. */
+ case 1: sum += qlp_coeff[ 0] * data[i- 1];
+ }
+ residual[i] = data[i] - (sum >> 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]; /* Falls through. */
+ case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */
+ case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */
+ case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */
+ case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */
+ case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */
+ case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */
+ case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */
+ case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */
+ case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */
+ case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */
+ case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */
+ case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */
+ case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */
+ case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */
+ case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */
+ case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */
+ case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */
+ case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */
+ 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);
+ }
+ }
+}
+
+#if defined FLAC__CPU_IA32 /* unused for x86_64 */
+
+FLAC__SSE_TARGET("sse2")
+void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[])
+{
+ int i;
+
+ FLAC__ASSERT(order > 0);
+ FLAC__ASSERT(order <= 32);
+
+ if(order <= 12) {
+ if(order > 8) { /* order == 9, 10, 11, 12 */
+ if(order > 10) { /* order == 11, 12 */
+ if(order == 12) {
+ __m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7;
+ xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0)); // 0 0 q[1] q[0]
+ xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2)); // 0 0 q[3] q[2]
+ xmm2 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+4)); // 0 0 q[5] q[4]
+ xmm3 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+6)); // 0 0 q[7] q[6]
+ xmm4 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+8)); // 0 0 q[9] q[8]
+ xmm5 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+10)); // 0 0 q[11] q[10]
+
+ xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0)); // 0 q[1] 0 q[0]
+ xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0)); // 0 q[3] 0 q[2]
+ xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0)); // 0 q[5] 0 q[4]
+ xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0)); // 0 q[7] 0 q[6]
+ xmm4 = _mm_shuffle_epi32(xmm4, _MM_SHUFFLE(3,1,2,0)); // 0 q[9] 0 q[8]
+ xmm5 = _mm_shuffle_epi32(xmm5, _MM_SHUFFLE(3,1,2,0)); // 0 q[11] 0 q[10]
+
+ for(i = 0; i < (int)data_len; i++) {
+ //sum = 0;
+ //sum += qlp_coeff[11] * data[i-12];
+ //sum += qlp_coeff[10] * data[i-11];
+ xmm7 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-12)); // 0 0 d[i-11] d[i-12]
+ xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1)); // 0 d[i-12] 0 d[i-11]
+ xmm7 = _mm_mul_epu32(xmm7, xmm5); /* we use _unsigned_ multiplication and discard high dword of the result values */
+
+ //sum += qlp_coeff[9] * data[i-10];
+ //sum += qlp_coeff[8] * data[i-9];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-10));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm4);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ //sum += qlp_coeff[7] * data[i-8];
+ //sum += qlp_coeff[6] * data[i-7];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-8));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm3);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ //sum += qlp_coeff[5] * data[i-6];
+ //sum += qlp_coeff[4] * data[i-5];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-6));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm2);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ //sum += qlp_coeff[3] * data[i-4];
+ //sum += qlp_coeff[2] * data[i-3];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm1);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ //sum += qlp_coeff[1] * data[i-2];
+ //sum += qlp_coeff[0] * data[i-1];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm0);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
+ RESIDUAL32_RESULT(xmm7);
+ }
+ }
+ else { /* order == 11 */
+ __m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7;
+ xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0));
+ xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2));
+ xmm2 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+4));
+ xmm3 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+6));
+ xmm4 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+8));
+ xmm5 = _mm_cvtsi32_si128(qlp_coeff[10]);
+
+ xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+ xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+ xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
+ xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0));
+ xmm4 = _mm_shuffle_epi32(xmm4, _MM_SHUFFLE(3,1,2,0));
+
+ for(i = 0; i < (int)data_len; i++) {
+ //sum = 0;
+ //sum = qlp_coeff[10] * data[i-11];
+ xmm7 = _mm_cvtsi32_si128(data[i-11]);
+ xmm7 = _mm_mul_epu32(xmm7, xmm5);
+
+ //sum += qlp_coeff[9] * data[i-10];
+ //sum += qlp_coeff[8] * data[i-9];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-10));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm4);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ //sum += qlp_coeff[7] * data[i-8];
+ //sum += qlp_coeff[6] * data[i-7];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-8));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm3);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ //sum += qlp_coeff[5] * data[i-6];
+ //sum += qlp_coeff[4] * data[i-5];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-6));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm2);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ //sum += qlp_coeff[3] * data[i-4];
+ //sum += qlp_coeff[2] * data[i-3];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm1);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ //sum += qlp_coeff[1] * data[i-2];
+ //sum += qlp_coeff[0] * data[i-1];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm0);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
+ RESIDUAL32_RESULT(xmm7);
+ }
+ }
+ }
+ else { /* order == 9, 10 */
+ if(order == 10) {
+ __m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm6, xmm7;
+ xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0));
+ xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2));
+ xmm2 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+4));
+ xmm3 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+6));
+ xmm4 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+8));
+
+ xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+ xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+ xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
+ xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0));
+ xmm4 = _mm_shuffle_epi32(xmm4, _MM_SHUFFLE(3,1,2,0));
+
+ for(i = 0; i < (int)data_len; i++) {
+ //sum = 0;
+ //sum += qlp_coeff[9] * data[i-10];
+ //sum += qlp_coeff[8] * data[i-9];
+ xmm7 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-10));
+ xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
+ xmm7 = _mm_mul_epu32(xmm7, xmm4);
+
+ //sum += qlp_coeff[7] * data[i-8];
+ //sum += qlp_coeff[6] * data[i-7];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-8));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm3);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ //sum += qlp_coeff[5] * data[i-6];
+ //sum += qlp_coeff[4] * data[i-5];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-6));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm2);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ //sum += qlp_coeff[3] * data[i-4];
+ //sum += qlp_coeff[2] * data[i-3];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm1);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ //sum += qlp_coeff[1] * data[i-2];
+ //sum += qlp_coeff[0] * data[i-1];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm0);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
+ RESIDUAL32_RESULT(xmm7);
+ }
+ }
+ else { /* order == 9 */
+ __m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm6, xmm7;
+ xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0));
+ xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2));
+ xmm2 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+4));
+ xmm3 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+6));
+ xmm4 = _mm_cvtsi32_si128(qlp_coeff[8]);
+
+ xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+ xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+ xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
+ xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0));
+
+ for(i = 0; i < (int)data_len; i++) {
+ //sum = 0;
+ //sum = qlp_coeff[8] * data[i-9];
+ xmm7 = _mm_cvtsi32_si128(data[i-9]);
+ xmm7 = _mm_mul_epu32(xmm7, xmm4);
+
+ //sum += qlp_coeff[7] * data[i-8];
+ //sum += qlp_coeff[6] * data[i-7];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-8));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm3);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ //sum += qlp_coeff[5] * data[i-6];
+ //sum += qlp_coeff[4] * data[i-5];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-6));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm2);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ //sum += qlp_coeff[3] * data[i-4];
+ //sum += qlp_coeff[2] * data[i-3];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm1);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ //sum += qlp_coeff[1] * data[i-2];
+ //sum += qlp_coeff[0] * data[i-1];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm0);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
+ RESIDUAL32_RESULT(xmm7);
+ }
+ }
+ }
+ }
+ else if(order > 4) { /* order == 5, 6, 7, 8 */
+ if(order > 6) { /* order == 7, 8 */
+ if(order == 8) {
+ __m128i xmm0, xmm1, xmm2, xmm3, xmm6, xmm7;
+ xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0));
+ xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2));
+ xmm2 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+4));
+ xmm3 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+6));
+
+ xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+ xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+ xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
+ xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0));
+
+ for(i = 0; i < (int)data_len; i++) {
+ //sum = 0;
+ //sum += qlp_coeff[7] * data[i-8];
+ //sum += qlp_coeff[6] * data[i-7];
+ xmm7 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-8));
+ xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
+ xmm7 = _mm_mul_epu32(xmm7, xmm3);
+
+ //sum += qlp_coeff[5] * data[i-6];
+ //sum += qlp_coeff[4] * data[i-5];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-6));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm2);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ //sum += qlp_coeff[3] * data[i-4];
+ //sum += qlp_coeff[2] * data[i-3];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm1);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ //sum += qlp_coeff[1] * data[i-2];
+ //sum += qlp_coeff[0] * data[i-1];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm0);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
+ RESIDUAL32_RESULT(xmm7);
+ }
+ }
+ else { /* order == 7 */
+ __m128i xmm0, xmm1, xmm2, xmm3, xmm6, xmm7;
+ xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0));
+ xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2));
+ xmm2 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+4));
+ xmm3 = _mm_cvtsi32_si128(qlp_coeff[6]);
+
+ xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+ xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+ xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
+
+ for(i = 0; i < (int)data_len; i++) {
+ //sum = 0;
+ //sum = qlp_coeff[6] * data[i-7];
+ xmm7 = _mm_cvtsi32_si128(data[i-7]);
+ xmm7 = _mm_mul_epu32(xmm7, xmm3);
+
+ //sum += qlp_coeff[5] * data[i-6];
+ //sum += qlp_coeff[4] * data[i-5];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-6));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm2);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ //sum += qlp_coeff[3] * data[i-4];
+ //sum += qlp_coeff[2] * data[i-3];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm1);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ //sum += qlp_coeff[1] * data[i-2];
+ //sum += qlp_coeff[0] * data[i-1];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm0);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
+ RESIDUAL32_RESULT(xmm7);
+ }
+ }
+ }
+ else { /* order == 5, 6 */
+ if(order == 6) {
+ __m128i xmm0, xmm1, xmm2, xmm6, xmm7;
+ xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0));
+ xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2));
+ xmm2 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+4));
+
+ xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+ xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+ xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
+
+ for(i = 0; i < (int)data_len; i++) {
+ //sum = 0;
+ //sum += qlp_coeff[5] * data[i-6];
+ //sum += qlp_coeff[4] * data[i-5];
+ xmm7 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-6));
+ xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
+ xmm7 = _mm_mul_epu32(xmm7, xmm2);
+
+ //sum += qlp_coeff[3] * data[i-4];
+ //sum += qlp_coeff[2] * data[i-3];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm1);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ //sum += qlp_coeff[1] * data[i-2];
+ //sum += qlp_coeff[0] * data[i-1];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm0);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
+ RESIDUAL32_RESULT(xmm7);
+ }
+ }
+ else { /* order == 5 */
+ __m128i xmm0, xmm1, xmm2, xmm6, xmm7;
+ xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0));
+ xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2));
+ xmm2 = _mm_cvtsi32_si128(qlp_coeff[4]);
+
+ xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+ xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+
+ for(i = 0; i < (int)data_len; i++) {
+ //sum = 0;
+ //sum = qlp_coeff[4] * data[i-5];
+ xmm7 = _mm_cvtsi32_si128(data[i-5]);
+ xmm7 = _mm_mul_epu32(xmm7, xmm2);
+
+ //sum += qlp_coeff[3] * data[i-4];
+ //sum += qlp_coeff[2] * data[i-3];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm1);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ //sum += qlp_coeff[1] * data[i-2];
+ //sum += qlp_coeff[0] * data[i-1];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm0);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
+ RESIDUAL32_RESULT(xmm7);
+ }
+ }
+ }
+ }
+ else { /* order == 1, 2, 3, 4 */
+ if(order > 2) { /* order == 3, 4 */
+ if(order == 4) {
+ __m128i xmm0, xmm1, xmm6, xmm7;
+ xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0));
+ xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2));
+
+ xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+ xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+
+ for(i = 0; i < (int)data_len; i++) {
+ //sum = 0;
+ //sum += qlp_coeff[3] * data[i-4];
+ //sum += qlp_coeff[2] * data[i-3];
+ xmm7 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4));
+ xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
+ xmm7 = _mm_mul_epu32(xmm7, xmm1);
+
+ //sum += qlp_coeff[1] * data[i-2];
+ //sum += qlp_coeff[0] * data[i-1];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm0);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
+ RESIDUAL32_RESULT(xmm7);
+ }
+ }
+ else { /* order == 3 */
+ __m128i xmm0, xmm1, xmm6, xmm7;
+ xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0));
+ xmm1 = _mm_cvtsi32_si128(qlp_coeff[2]);
+
+ xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+
+ for(i = 0; i < (int)data_len; i++) {
+ //sum = 0;
+ //sum = qlp_coeff[2] * data[i-3];
+ xmm7 = _mm_cvtsi32_si128(data[i-3]);
+ xmm7 = _mm_mul_epu32(xmm7, xmm1);
+
+ //sum += qlp_coeff[1] * data[i-2];
+ //sum += qlp_coeff[0] * data[i-1];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epu32(xmm6, xmm0);
+ xmm7 = _mm_add_epi32(xmm7, xmm6);
+
+ xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
+ RESIDUAL32_RESULT(xmm7);
+ }
+ }
+ }
+ else { /* order == 1, 2 */
+ if(order == 2) {
+ __m128i xmm0, xmm7;
+ xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0));
+ xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+
+ for(i = 0; i < (int)data_len; i++) {
+ //sum = 0;
+ //sum += qlp_coeff[1] * data[i-2];
+ //sum += qlp_coeff[0] * data[i-1];
+ xmm7 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2));
+ xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
+ xmm7 = _mm_mul_epu32(xmm7, xmm0);
+
+ xmm7 = _mm_add_epi32(xmm7, _mm_srli_si128(xmm7, 8));
+ RESIDUAL32_RESULT(xmm7);
+ }
+ }
+ 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 */
+ FLAC__int32 sum;
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ switch(order) {
+ case 32: sum += qlp_coeff[31] * data[i-32]; /* Falls through. */
+ case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */
+ case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */
+ case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */
+ case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */
+ case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */
+ case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */
+ case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */
+ case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */
+ case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */
+ case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */
+ case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */
+ case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */
+ case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */
+ case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */
+ case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */
+ case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */
+ case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */
+ case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */
+ 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 /* FLAC__CPU_IA32 */
+#endif /* FLAC__SSE2_SUPPORTED */
+#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
+#endif /* FLAC__NO_ASM */
+#endif /* FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/src/libFLAC/lpc_intrin_sse41.c b/src/libFLAC/lpc_intrin_sse41.c
new file mode 100644
index 0000000..756c5dd
--- /dev/null
+++ b/src/libFLAC/lpc_intrin_sse41.c
@@ -0,0 +1,950 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "private/cpu.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#ifndef FLAC__NO_ASM
+#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
+#include "private/lpc.h"
+#ifdef FLAC__SSE4_1_SUPPORTED
+
+#include "FLAC/assert.h"
+#include "FLAC/format.h"
+
+#include <smmintrin.h> /* SSE4.1 */
+
+#if defined FLAC__CPU_IA32 /* unused for x64 */
+
+#define RESIDUAL64_RESULT(xmmN) residual[i] = data[i] - _mm_cvtsi128_si32(_mm_srl_epi64(xmmN, cnt))
+#define RESIDUAL64_RESULT1(xmmN) residual[i] = data[i] - _mm_cvtsi128_si32(_mm_srli_epi64(xmmN, lp_quantization))
+
+FLAC__SSE_TARGET("sse4.1")
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_sse41(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[])
+{
+ int i;
+ const __m128i cnt = _mm_cvtsi32_si128(lp_quantization);
+
+ FLAC__ASSERT(order > 0);
+ FLAC__ASSERT(order <= 32);
+ FLAC__ASSERT(lp_quantization <= 32); /* there's no _mm_sra_epi64() so we have to use _mm_srl_epi64() */
+
+ if(order <= 12) {
+ if(order > 8) { /* order == 9, 10, 11, 12 */
+ if(order > 10) { /* order == 11, 12 */
+ if(order == 12) {
+ __m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7;
+ xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0)); // 0 0 q[1] q[0]
+ xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2)); // 0 0 q[3] q[2]
+ xmm2 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+4)); // 0 0 q[5] q[4]
+ xmm3 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+6)); // 0 0 q[7] q[6]
+ xmm4 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+8)); // 0 0 q[9] q[8]
+ xmm5 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+10)); // 0 0 q[11] q[10]
+
+ xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0)); // 0 q[1] 0 q[0]
+ xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0)); // 0 q[3] 0 q[2]
+ xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0)); // 0 q[5] 0 q[4]
+ xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0)); // 0 q[7] 0 q[6]
+ xmm4 = _mm_shuffle_epi32(xmm4, _MM_SHUFFLE(3,1,2,0)); // 0 q[9] 0 q[8]
+ xmm5 = _mm_shuffle_epi32(xmm5, _MM_SHUFFLE(3,1,2,0)); // 0 q[11] 0 q[10]
+
+ 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];
+ xmm7 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-12)); // 0 0 d[i-11] d[i-12]
+ xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1)); // 0 d[i-12] 0 d[i-11]
+ xmm7 = _mm_mul_epi32(xmm7, xmm5);
+
+ //sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+ //sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-10));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm4);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ //sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+ //sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-8));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm3);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ //sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ //sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-6));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm2);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ //sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ //sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm1);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ //sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ //sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm0);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
+ RESIDUAL64_RESULT1(xmm7);
+ }
+ }
+ else { /* order == 11 */
+ __m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7;
+ xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0));
+ xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2));
+ xmm2 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+4));
+ xmm3 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+6));
+ xmm4 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+8));
+ xmm5 = _mm_cvtsi32_si128(qlp_coeff[10]);
+
+ xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+ xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+ xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
+ xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0));
+ xmm4 = _mm_shuffle_epi32(xmm4, _MM_SHUFFLE(3,1,2,0));
+
+ for(i = 0; i < (int)data_len; i++) {
+ //sum = 0;
+ //sum = qlp_coeff[10] * (FLAC__int64)data[i-11];
+ xmm7 = _mm_cvtsi32_si128(data[i-11]);
+ xmm7 = _mm_mul_epi32(xmm7, xmm5);
+
+ //sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+ //sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-10));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm4);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ //sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+ //sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-8));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm3);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ //sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ //sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-6));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm2);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ //sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ //sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm1);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ //sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ //sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm0);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
+ RESIDUAL64_RESULT1(xmm7);
+ }
+ }
+ }
+ else { /* order == 9, 10 */
+ if(order == 10) {
+ __m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm6, xmm7;
+ xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0));
+ xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2));
+ xmm2 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+4));
+ xmm3 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+6));
+ xmm4 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+8));
+
+ xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+ xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+ xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
+ xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0));
+ xmm4 = _mm_shuffle_epi32(xmm4, _MM_SHUFFLE(3,1,2,0));
+
+ 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];
+ xmm7 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-10));
+ xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
+ xmm7 = _mm_mul_epi32(xmm7, xmm4);
+
+ //sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+ //sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-8));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm3);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ //sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ //sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-6));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm2);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ //sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ //sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm1);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ //sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ //sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm0);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
+ RESIDUAL64_RESULT(xmm7);
+ }
+ }
+ else { /* order == 9 */
+ __m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm6, xmm7;
+ xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0));
+ xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2));
+ xmm2 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+4));
+ xmm3 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+6));
+ xmm4 = _mm_cvtsi32_si128(qlp_coeff[8]);
+
+ xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+ xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+ xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
+ xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0));
+
+ for(i = 0; i < (int)data_len; i++) {
+ //sum = 0;
+ //sum = qlp_coeff[8] * (FLAC__int64)data[i-9];
+ xmm7 = _mm_cvtsi32_si128(data[i-9]);
+ xmm7 = _mm_mul_epi32(xmm7, xmm4);
+
+ //sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+ //sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-8));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm3);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ //sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ //sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-6));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm2);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ //sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ //sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm1);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ //sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ //sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm0);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
+ RESIDUAL64_RESULT(xmm7);
+ }
+ }
+ }
+ }
+ else if(order > 4) { /* order == 5, 6, 7, 8 */
+ if(order > 6) { /* order == 7, 8 */
+ if(order == 8) {
+ __m128i xmm0, xmm1, xmm2, xmm3, xmm6, xmm7;
+ xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0));
+ xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2));
+ xmm2 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+4));
+ xmm3 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+6));
+
+ xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+ xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+ xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
+ xmm3 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3,1,2,0));
+
+ 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];
+ xmm7 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-8));
+ xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
+ xmm7 = _mm_mul_epi32(xmm7, xmm3);
+
+ //sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ //sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-6));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm2);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ //sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ //sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm1);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ //sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ //sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm0);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
+ RESIDUAL64_RESULT(xmm7);
+ }
+ }
+ else { /* order == 7 */
+ __m128i xmm0, xmm1, xmm2, xmm3, xmm6, xmm7;
+ xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0));
+ xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2));
+ xmm2 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+4));
+ xmm3 = _mm_cvtsi32_si128(qlp_coeff[6]);
+
+ xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+ xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+ xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
+
+ for(i = 0; i < (int)data_len; i++) {
+ //sum = 0;
+ //sum = qlp_coeff[6] * (FLAC__int64)data[i-7];
+ xmm7 = _mm_cvtsi32_si128(data[i-7]);
+ xmm7 = _mm_mul_epi32(xmm7, xmm3);
+
+ //sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ //sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-6));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm2);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ //sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ //sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm1);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ //sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ //sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm0);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
+ RESIDUAL64_RESULT(xmm7);
+ }
+ }
+ }
+ else { /* order == 5, 6 */
+ if(order == 6) {
+ __m128i xmm0, xmm1, xmm2, xmm6, xmm7;
+ xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0));
+ xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2));
+ xmm2 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+4));
+
+ xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+ xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+ xmm2 = _mm_shuffle_epi32(xmm2, _MM_SHUFFLE(3,1,2,0));
+
+ 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];
+ xmm7 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-6));
+ xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
+ xmm7 = _mm_mul_epi32(xmm7, xmm2);
+
+ //sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ //sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm1);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ //sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ //sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm0);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
+ RESIDUAL64_RESULT(xmm7);
+ }
+ }
+ else { /* order == 5 */
+ __m128i xmm0, xmm1, xmm2, xmm6, xmm7;
+ xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0));
+ xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2));
+ xmm2 = _mm_cvtsi32_si128(qlp_coeff[4]);
+
+ xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+ xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+
+ for(i = 0; i < (int)data_len; i++) {
+ //sum = 0;
+ //sum = qlp_coeff[4] * (FLAC__int64)data[i-5];
+ xmm7 = _mm_cvtsi32_si128(data[i-5]);
+ xmm7 = _mm_mul_epi32(xmm7, xmm2);
+
+ //sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ //sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm1);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ //sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ //sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm0);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
+ RESIDUAL64_RESULT(xmm7);
+ }
+ }
+ }
+ }
+ else { /* order == 1, 2, 3, 4 */
+ if(order > 2) { /* order == 3, 4 */
+ if(order == 4) {
+ __m128i xmm0, xmm1, xmm6, xmm7;
+ xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0));
+ xmm1 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+2));
+
+ xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+ xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
+
+ 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];
+ xmm7 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-4));
+ xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
+ xmm7 = _mm_mul_epi32(xmm7, xmm1);
+
+ //sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ //sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm0);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
+ RESIDUAL64_RESULT(xmm7);
+ }
+ }
+ else { /* order == 3 */
+ __m128i xmm0, xmm1, xmm6, xmm7;
+ xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0));
+ xmm1 = _mm_cvtsi32_si128(qlp_coeff[2]);
+
+ xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+
+ for(i = 0; i < (int)data_len; i++) {
+ //sum = 0;
+ //sum = qlp_coeff[2] * (FLAC__int64)data[i-3];
+ xmm7 = _mm_cvtsi32_si128(data[i-3]);
+ xmm7 = _mm_mul_epi32(xmm7, xmm1);
+
+ //sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ //sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ xmm6 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2));
+ xmm6 = _mm_shuffle_epi32(xmm6, _MM_SHUFFLE(2,0,3,1));
+ xmm6 = _mm_mul_epi32(xmm6, xmm0);
+ xmm7 = _mm_add_epi64(xmm7, xmm6);
+
+ xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
+ RESIDUAL64_RESULT(xmm7);
+ }
+ }
+ }
+ else { /* order == 1, 2 */
+ if(order == 2) {
+ __m128i xmm0, xmm7;
+ xmm0 = _mm_loadl_epi64((const __m128i*)(const void*)(qlp_coeff+0));
+ xmm0 = _mm_shuffle_epi32(xmm0, _MM_SHUFFLE(3,1,2,0));
+
+ 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];
+ xmm7 = _mm_loadl_epi64((const __m128i*)(const void*)(data+i-2));
+ xmm7 = _mm_shuffle_epi32(xmm7, _MM_SHUFFLE(2,0,3,1));
+ xmm7 = _mm_mul_epi32(xmm7, xmm0);
+
+ xmm7 = _mm_add_epi64(xmm7, _mm_srli_si128(xmm7, 8));
+ RESIDUAL64_RESULT(xmm7);
+ }
+ }
+ else { /* order == 1 */
+ __m128i xmm0, xmm7;
+ xmm0 = _mm_cvtsi32_si128(qlp_coeff[0]);
+
+ for(i = 0; i < (int)data_len; i++) {
+ //sum = qlp_coeff[0] * (FLAC__int64)data[i-1];
+ xmm7 = _mm_cvtsi32_si128(data[i-1]);
+ xmm7 = _mm_mul_epi32(xmm7, xmm0);
+ RESIDUAL64_RESULT(xmm7);
+ }
+ }
+ }
+ }
+ }
+ else { /* order > 12 */
+ FLAC__int64 sum;
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ switch(order) {
+ case 32: sum += qlp_coeff[31] * (FLAC__int64)data[i-32]; /* Falls through. */
+ case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31]; /* Falls through. */
+ case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30]; /* Falls through. */
+ case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29]; /* Falls through. */
+ case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28]; /* Falls through. */
+ case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27]; /* Falls through. */
+ case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26]; /* Falls through. */
+ case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25]; /* Falls through. */
+ case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24]; /* Falls through. */
+ case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23]; /* Falls through. */
+ case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22]; /* Falls through. */
+ case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21]; /* Falls through. */
+ case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20]; /* Falls through. */
+ case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19]; /* Falls through. */
+ case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18]; /* Falls through. */
+ case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17]; /* Falls through. */
+ case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16]; /* Falls through. */
+ case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15]; /* Falls through. */
+ case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14]; /* Falls through. */
+ 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 /* defined FLAC__CPU_IA32 */
+
+FLAC__SSE_TARGET("sse4.1")
+void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse41(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[])
+{
+ int i;
+ FLAC__int32 sum;
+ const __m128i cnt = _mm_cvtsi32_si128(lp_quantization);
+
+ FLAC__ASSERT(order > 0);
+ FLAC__ASSERT(order <= 32);
+
+ if(order <= 12) {
+ if(order > 8) {
+ if(order > 10) {
+ if(order == 12) {
+ __m128i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11;
+ q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+ q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+ q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+ q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+ q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+ q5 = _mm_cvtsi32_si128(qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
+ q6 = _mm_cvtsi32_si128(qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
+ q7 = _mm_cvtsi32_si128(qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
+ q8 = _mm_cvtsi32_si128(qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0));
+ q9 = _mm_cvtsi32_si128(qlp_coeff[9]); q9 = _mm_shuffle_epi32(q9, _MM_SHUFFLE(0,0,0,0));
+ q10 = _mm_cvtsi32_si128(qlp_coeff[10]); q10 = _mm_shuffle_epi32(q10, _MM_SHUFFLE(0,0,0,0));
+ q11 = _mm_cvtsi32_si128(qlp_coeff[11]); q11 = _mm_shuffle_epi32(q11, _MM_SHUFFLE(0,0,0,0));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m128i summ, mull;
+ summ = _mm_mullo_epi32(q11, _mm_loadu_si128((const __m128i*)(const void*)(data+i-12)));
+ mull = _mm_mullo_epi32(q10, _mm_loadu_si128((const __m128i*)(const void*)(data+i-11))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q9, _mm_loadu_si128((const __m128i*)(const void*)(data+i-10))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q8, _mm_loadu_si128((const __m128i*)(const void*)(data+i-9))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q7, _mm_loadu_si128((const __m128i*)(const void*)(data+i-8))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q6, _mm_loadu_si128((const __m128i*)(const void*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q5, _mm_loadu_si128((const __m128i*)(const void*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+ summ = _mm_sra_epi32(summ, cnt);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ));
+ }
+ }
+ else { /* order == 11 */
+ __m128i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10;
+ q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+ q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+ q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+ q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+ q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+ q5 = _mm_cvtsi32_si128(qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
+ q6 = _mm_cvtsi32_si128(qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
+ q7 = _mm_cvtsi32_si128(qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
+ q8 = _mm_cvtsi32_si128(qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0));
+ q9 = _mm_cvtsi32_si128(qlp_coeff[9]); q9 = _mm_shuffle_epi32(q9, _MM_SHUFFLE(0,0,0,0));
+ q10 = _mm_cvtsi32_si128(qlp_coeff[10]); q10 = _mm_shuffle_epi32(q10, _MM_SHUFFLE(0,0,0,0));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m128i summ, mull;
+ summ = _mm_mullo_epi32(q10, _mm_loadu_si128((const __m128i*)(const void*)(data+i-11)));
+ mull = _mm_mullo_epi32(q9, _mm_loadu_si128((const __m128i*)(const void*)(data+i-10))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q8, _mm_loadu_si128((const __m128i*)(const void*)(data+i-9))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q7, _mm_loadu_si128((const __m128i*)(const void*)(data+i-8))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q6, _mm_loadu_si128((const __m128i*)(const void*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q5, _mm_loadu_si128((const __m128i*)(const void*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+ summ = _mm_sra_epi32(summ, cnt);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ));
+ }
+ }
+ }
+ else {
+ if(order == 10) {
+ __m128i q0, q1, q2, q3, q4, q5, q6, q7, q8, q9;
+ q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+ q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+ q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+ q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+ q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+ q5 = _mm_cvtsi32_si128(qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
+ q6 = _mm_cvtsi32_si128(qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
+ q7 = _mm_cvtsi32_si128(qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
+ q8 = _mm_cvtsi32_si128(qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0));
+ q9 = _mm_cvtsi32_si128(qlp_coeff[9]); q9 = _mm_shuffle_epi32(q9, _MM_SHUFFLE(0,0,0,0));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m128i summ, mull;
+ summ = _mm_mullo_epi32(q9, _mm_loadu_si128((const __m128i*)(const void*)(data+i-10)));
+ mull = _mm_mullo_epi32(q8, _mm_loadu_si128((const __m128i*)(const void*)(data+i-9))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q7, _mm_loadu_si128((const __m128i*)(const void*)(data+i-8))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q6, _mm_loadu_si128((const __m128i*)(const void*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q5, _mm_loadu_si128((const __m128i*)(const void*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+ summ = _mm_sra_epi32(summ, cnt);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ));
+ }
+ }
+ else { /* order == 9 */
+ __m128i q0, q1, q2, q3, q4, q5, q6, q7, q8;
+ q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+ q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+ q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+ q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+ q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+ q5 = _mm_cvtsi32_si128(qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
+ q6 = _mm_cvtsi32_si128(qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
+ q7 = _mm_cvtsi32_si128(qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
+ q8 = _mm_cvtsi32_si128(qlp_coeff[8]); q8 = _mm_shuffle_epi32(q8, _MM_SHUFFLE(0,0,0,0));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m128i summ, mull;
+ summ = _mm_mullo_epi32(q8, _mm_loadu_si128((const __m128i*)(const void*)(data+i-9)));
+ mull = _mm_mullo_epi32(q7, _mm_loadu_si128((const __m128i*)(const void*)(data+i-8))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q6, _mm_loadu_si128((const __m128i*)(const void*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q5, _mm_loadu_si128((const __m128i*)(const void*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+ summ = _mm_sra_epi32(summ, cnt);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ));
+ }
+ }
+ }
+ }
+ else if(order > 4) {
+ if(order > 6) {
+ if(order == 8) {
+ __m128i q0, q1, q2, q3, q4, q5, q6, q7;
+ q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+ q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+ q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+ q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+ q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+ q5 = _mm_cvtsi32_si128(qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
+ q6 = _mm_cvtsi32_si128(qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
+ q7 = _mm_cvtsi32_si128(qlp_coeff[7]); q7 = _mm_shuffle_epi32(q7, _MM_SHUFFLE(0,0,0,0));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m128i summ, mull;
+ summ = _mm_mullo_epi32(q7, _mm_loadu_si128((const __m128i*)(const void*)(data+i-8)));
+ mull = _mm_mullo_epi32(q6, _mm_loadu_si128((const __m128i*)(const void*)(data+i-7))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q5, _mm_loadu_si128((const __m128i*)(const void*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+ summ = _mm_sra_epi32(summ, cnt);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ));
+ }
+ }
+ else { /* order == 7 */
+ __m128i q0, q1, q2, q3, q4, q5, q6;
+ q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+ q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+ q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+ q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+ q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+ q5 = _mm_cvtsi32_si128(qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
+ q6 = _mm_cvtsi32_si128(qlp_coeff[6]); q6 = _mm_shuffle_epi32(q6, _MM_SHUFFLE(0,0,0,0));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m128i summ, mull;
+ summ = _mm_mullo_epi32(q6, _mm_loadu_si128((const __m128i*)(const void*)(data+i-7)));
+ mull = _mm_mullo_epi32(q5, _mm_loadu_si128((const __m128i*)(const void*)(data+i-6))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+ summ = _mm_sra_epi32(summ, cnt);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ));
+ }
+ }
+ }
+ else {
+ if(order == 6) {
+ __m128i q0, q1, q2, q3, q4, q5;
+ q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+ q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+ q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+ q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+ q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+ q5 = _mm_cvtsi32_si128(qlp_coeff[5]); q5 = _mm_shuffle_epi32(q5, _MM_SHUFFLE(0,0,0,0));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m128i summ, mull;
+ summ = _mm_mullo_epi32(q5, _mm_loadu_si128((const __m128i*)(const void*)(data+i-6)));
+ mull = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+ summ = _mm_sra_epi32(summ, cnt);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ));
+ }
+ }
+ else { /* order == 5 */
+ __m128i q0, q1, q2, q3, q4;
+ q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+ q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+ q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+ q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+ q4 = _mm_cvtsi32_si128(qlp_coeff[4]); q4 = _mm_shuffle_epi32(q4, _MM_SHUFFLE(0,0,0,0));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m128i summ, mull;
+ summ = _mm_mullo_epi32(q4, _mm_loadu_si128((const __m128i*)(const void*)(data+i-5)));
+ mull = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+ summ = _mm_sra_epi32(summ, cnt);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ));
+ }
+ }
+ }
+ }
+ else {
+ if(order > 2) {
+ if(order == 4) {
+ __m128i q0, q1, q2, q3;
+ q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+ q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+ q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+ q3 = _mm_cvtsi32_si128(qlp_coeff[3]); q3 = _mm_shuffle_epi32(q3, _MM_SHUFFLE(0,0,0,0));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m128i summ, mull;
+ summ = _mm_mullo_epi32(q3, _mm_loadu_si128((const __m128i*)(const void*)(data+i-4)));
+ mull = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+ summ = _mm_sra_epi32(summ, cnt);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ));
+ }
+ }
+ else { /* order == 3 */
+ __m128i q0, q1, q2;
+ q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+ q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+ q2 = _mm_cvtsi32_si128(qlp_coeff[2]); q2 = _mm_shuffle_epi32(q2, _MM_SHUFFLE(0,0,0,0));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m128i summ, mull;
+ summ = _mm_mullo_epi32(q2, _mm_loadu_si128((const __m128i*)(const void*)(data+i-3)));
+ mull = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2))); summ = _mm_add_epi32(summ, mull);
+ mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+ summ = _mm_sra_epi32(summ, cnt);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ));
+ }
+ }
+ }
+ else {
+ if(order == 2) {
+ __m128i q0, q1;
+ q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+ q1 = _mm_cvtsi32_si128(qlp_coeff[1]); q1 = _mm_shuffle_epi32(q1, _MM_SHUFFLE(0,0,0,0));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m128i summ, mull;
+ summ = _mm_mullo_epi32(q1, _mm_loadu_si128((const __m128i*)(const void*)(data+i-2)));
+ mull = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1))); summ = _mm_add_epi32(summ, mull);
+ summ = _mm_sra_epi32(summ, cnt);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ));
+ }
+ }
+ else { /* order == 1 */
+ __m128i q0;
+ q0 = _mm_cvtsi32_si128(qlp_coeff[0]); q0 = _mm_shuffle_epi32(q0, _MM_SHUFFLE(0,0,0,0));
+
+ for(i = 0; i < (int)data_len-3; i+=4) {
+ __m128i summ;
+ summ = _mm_mullo_epi32(q0, _mm_loadu_si128((const __m128i*)(const void*)(data+i-1)));
+ summ = _mm_sra_epi32(summ, cnt);
+ _mm_storeu_si128((__m128i*)(void*)(residual+i), _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(const void*)(data+i)), summ));
+ }
+ }
+ }
+ }
+ for(; i < (int)data_len; i++) {
+ sum = 0;
+ switch(order) {
+ case 12: sum += qlp_coeff[11] * data[i-12]; /* Falls through. */
+ case 11: sum += qlp_coeff[10] * data[i-11]; /* Falls through. */
+ case 10: sum += qlp_coeff[ 9] * data[i-10]; /* Falls through. */
+ case 9: sum += qlp_coeff[ 8] * data[i- 9]; /* Falls through. */
+ case 8: sum += qlp_coeff[ 7] * data[i- 8]; /* Falls through. */
+ case 7: sum += qlp_coeff[ 6] * data[i- 7]; /* Falls through. */
+ case 6: sum += qlp_coeff[ 5] * data[i- 6]; /* Falls through. */
+ case 5: sum += qlp_coeff[ 4] * data[i- 5]; /* Falls through. */
+ case 4: sum += qlp_coeff[ 3] * data[i- 4]; /* Falls through. */
+ case 3: sum += qlp_coeff[ 2] * data[i- 3]; /* Falls through. */
+ case 2: sum += qlp_coeff[ 1] * data[i- 2]; /* Falls through. */
+ case 1: sum += qlp_coeff[ 0] * data[i- 1];
+ }
+ residual[i] = data[i] - (sum >> 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]; /* Falls through. */
+ case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */
+ case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */
+ case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */
+ case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */
+ case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */
+ case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */
+ case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */
+ case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */
+ case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */
+ case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */
+ case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */
+ case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */
+ case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */
+ case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */
+ case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */
+ case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */
+ case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */
+ case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */
+ 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 /* FLAC__SSE4_1_SUPPORTED */
+#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
+#endif /* FLAC__NO_ASM */
+#endif /* FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/src/libFLAC/md5.c b/src/libFLAC/md5.c
new file mode 100644
index 0000000..09933d7
--- /dev/null
+++ b/src/libFLAC/md5.c
@@ -0,0 +1,517 @@
+#ifdef 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"
+#include "share/compat.h"
+#include "share/endswap.h"
+
+/*
+ * 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, uint32_t 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, uint32_t 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.p8 = 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);
+ if (0 != ctx->internal_buf.p8) {
+ free(ctx->internal_buf.p8);
+ ctx->internal_buf.p8 = 0;
+ ctx->capacity = 0;
+ }
+ memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
+}
+
+/*
+ * Convert the incoming audio signal to a byte stream
+ */
+static void format_input_(FLAC__multibyte *mbuf, const FLAC__int32 * const signal[], uint32_t channels, uint32_t samples, uint32_t bytes_per_sample)
+{
+ FLAC__byte *buf_ = mbuf->p8;
+ FLAC__int16 *buf16 = mbuf->p16;
+ FLAC__int32 *buf32 = mbuf->p32;
+ FLAC__int32 a_word;
+ uint32_t channel, sample;
+
+ /* Storage in the output buffer, buf, is little endian. */
+
+#define BYTES_CHANNEL_SELECTOR(bytes, channels) (bytes * 100 + channels)
+
+ /* First do the most commonly used combinations. */
+ switch (BYTES_CHANNEL_SELECTOR (bytes_per_sample, channels)) {
+ /* One byte per sample. */
+ case (BYTES_CHANNEL_SELECTOR (1, 1)):
+ for (sample = 0; sample < samples; sample++)
+ *buf_++ = signal[0][sample];
+ return;
+
+ case (BYTES_CHANNEL_SELECTOR (1, 2)):
+ for (sample = 0; sample < samples; sample++) {
+ *buf_++ = signal[0][sample];
+ *buf_++ = signal[1][sample];
+ }
+ return;
+
+ case (BYTES_CHANNEL_SELECTOR (1, 4)):
+ for (sample = 0; sample < samples; sample++) {
+ *buf_++ = signal[0][sample];
+ *buf_++ = signal[1][sample];
+ *buf_++ = signal[2][sample];
+ *buf_++ = signal[3][sample];
+ }
+ return;
+
+ case (BYTES_CHANNEL_SELECTOR (1, 6)):
+ for (sample = 0; sample < samples; sample++) {
+ *buf_++ = signal[0][sample];
+ *buf_++ = signal[1][sample];
+ *buf_++ = signal[2][sample];
+ *buf_++ = signal[3][sample];
+ *buf_++ = signal[4][sample];
+ *buf_++ = signal[5][sample];
+ }
+ return;
+
+ case (BYTES_CHANNEL_SELECTOR (1, 8)):
+ for (sample = 0; sample < samples; sample++) {
+ *buf_++ = signal[0][sample];
+ *buf_++ = signal[1][sample];
+ *buf_++ = signal[2][sample];
+ *buf_++ = signal[3][sample];
+ *buf_++ = signal[4][sample];
+ *buf_++ = signal[5][sample];
+ *buf_++ = signal[6][sample];
+ *buf_++ = signal[7][sample];
+ }
+ return;
+
+ /* Two bytes per sample. */
+ case (BYTES_CHANNEL_SELECTOR (2, 1)):
+ for (sample = 0; sample < samples; sample++)
+ *buf16++ = H2LE_16(signal[0][sample]);
+ return;
+
+ case (BYTES_CHANNEL_SELECTOR (2, 2)):
+ for (sample = 0; sample < samples; sample++) {
+ *buf16++ = H2LE_16(signal[0][sample]);
+ *buf16++ = H2LE_16(signal[1][sample]);
+ }
+ return;
+
+ case (BYTES_CHANNEL_SELECTOR (2, 4)):
+ for (sample = 0; sample < samples; sample++) {
+ *buf16++ = H2LE_16(signal[0][sample]);
+ *buf16++ = H2LE_16(signal[1][sample]);
+ *buf16++ = H2LE_16(signal[2][sample]);
+ *buf16++ = H2LE_16(signal[3][sample]);
+ }
+ return;
+
+ case (BYTES_CHANNEL_SELECTOR (2, 6)):
+ for (sample = 0; sample < samples; sample++) {
+ *buf16++ = H2LE_16(signal[0][sample]);
+ *buf16++ = H2LE_16(signal[1][sample]);
+ *buf16++ = H2LE_16(signal[2][sample]);
+ *buf16++ = H2LE_16(signal[3][sample]);
+ *buf16++ = H2LE_16(signal[4][sample]);
+ *buf16++ = H2LE_16(signal[5][sample]);
+ }
+ return;
+
+ case (BYTES_CHANNEL_SELECTOR (2, 8)):
+ for (sample = 0; sample < samples; sample++) {
+ *buf16++ = H2LE_16(signal[0][sample]);
+ *buf16++ = H2LE_16(signal[1][sample]);
+ *buf16++ = H2LE_16(signal[2][sample]);
+ *buf16++ = H2LE_16(signal[3][sample]);
+ *buf16++ = H2LE_16(signal[4][sample]);
+ *buf16++ = H2LE_16(signal[5][sample]);
+ *buf16++ = H2LE_16(signal[6][sample]);
+ *buf16++ = H2LE_16(signal[7][sample]);
+ }
+ return;
+
+ /* Three bytes per sample. */
+ case (BYTES_CHANNEL_SELECTOR (3, 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;
+ }
+ return;
+
+ case (BYTES_CHANNEL_SELECTOR (3, 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;
+ }
+ return;
+
+ /* Four bytes per sample. */
+ case (BYTES_CHANNEL_SELECTOR (4, 1)):
+ for (sample = 0; sample < samples; sample++)
+ *buf32++ = H2LE_32(signal[0][sample]);
+ return;
+
+ case (BYTES_CHANNEL_SELECTOR (4, 2)):
+ for (sample = 0; sample < samples; sample++) {
+ *buf32++ = H2LE_32(signal[0][sample]);
+ *buf32++ = H2LE_32(signal[1][sample]);
+ }
+ return;
+
+ case (BYTES_CHANNEL_SELECTOR (4, 4)):
+ for (sample = 0; sample < samples; sample++) {
+ *buf32++ = H2LE_32(signal[0][sample]);
+ *buf32++ = H2LE_32(signal[1][sample]);
+ *buf32++ = H2LE_32(signal[2][sample]);
+ *buf32++ = H2LE_32(signal[3][sample]);
+ }
+ return;
+
+ case (BYTES_CHANNEL_SELECTOR (4, 6)):
+ for (sample = 0; sample < samples; sample++) {
+ *buf32++ = H2LE_32(signal[0][sample]);
+ *buf32++ = H2LE_32(signal[1][sample]);
+ *buf32++ = H2LE_32(signal[2][sample]);
+ *buf32++ = H2LE_32(signal[3][sample]);
+ *buf32++ = H2LE_32(signal[4][sample]);
+ *buf32++ = H2LE_32(signal[5][sample]);
+ }
+ return;
+
+ case (BYTES_CHANNEL_SELECTOR (4, 8)):
+ for (sample = 0; sample < samples; sample++) {
+ *buf32++ = H2LE_32(signal[0][sample]);
+ *buf32++ = H2LE_32(signal[1][sample]);
+ *buf32++ = H2LE_32(signal[2][sample]);
+ *buf32++ = H2LE_32(signal[3][sample]);
+ *buf32++ = H2LE_32(signal[4][sample]);
+ *buf32++ = H2LE_32(signal[5][sample]);
+ *buf32++ = H2LE_32(signal[6][sample]);
+ *buf32++ = H2LE_32(signal[7][sample]);
+ }
+ return;
+
+ default:
+ break;
+ }
+
+ /* General version. */
+ switch (bytes_per_sample) {
+ case 1:
+ for (sample = 0; sample < samples; sample++)
+ for (channel = 0; channel < channels; channel++)
+ *buf_++ = signal[channel][sample];
+ return;
+
+ case 2:
+ for (sample = 0; sample < samples; sample++)
+ for (channel = 0; channel < channels; channel++)
+ *buf16++ = H2LE_16(signal[channel][sample]);
+ return;
+
+ case 3:
+ 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;
+ }
+ return;
+
+ case 4:
+ for (sample = 0; sample < samples; sample++)
+ for (channel = 0; channel < channels; channel++)
+ *buf32++ = H2LE_32(signal[channel][sample]);
+ return;
+
+ default:
+ break;
+ }
+}
+
+/*
+ * 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[], uint32_t channels, uint32_t samples, uint32_t 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) {
+ if (0 == (ctx->internal_buf.p8 = safe_realloc_(ctx->internal_buf.p8, bytes_needed))) {
+ if (0 == (ctx->internal_buf.p8 = safe_malloc_(bytes_needed))) {
+ ctx->capacity = 0;
+ return false;
+ }
+ }
+ ctx->capacity = bytes_needed;
+ }
+
+ format_input_(&ctx->internal_buf, signal, channels, samples, bytes_per_sample);
+
+ FLAC__MD5Update(ctx, ctx->internal_buf.p8, bytes_needed);
+
+ return true;
+}
diff --git a/src/libFLAC/memory.c b/src/libFLAC/memory.c
new file mode 100644
index 0000000..ad5371e
--- /dev/null
+++ b/src/libFLAC/memory.c
@@ -0,0 +1,219 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#include "private/memory.h"
+#include "FLAC/assert.h"
+#include "share/compat.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, /*+*/31L);
+ *aligned_address = (void*)(((uintptr_t)x + 31L) & -32L);
+#else
+ x = safe_malloc_(bytes);
+ *aligned_address = x;
+#endif
+ return x;
+}
+
+FLAC__bool FLAC__memory_alloc_aligned_int32_array(size_t 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(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */
+ return false;
+
+ pu = 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_uint32_array(size_t 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(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */
+ return false;
+
+ pu = 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_int64_array(size_t elements, FLAC__int64 **unaligned_pointer, FLAC__int64 **aligned_pointer)
+{
+ FLAC__int64 *pu; /* unaligned pointer */
+ union { /* union needed to comply with C99 pointer aliasing rules */
+ FLAC__int64 *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(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */
+ return false;
+
+ pu = 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(size_t 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(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */
+ return false;
+
+ pu = 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(size_t 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(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */
+ return false;
+
+ pu = 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
+
+void *safe_malloc_mul_2op_p(size_t size1, size_t size2)
+{
+ 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);
+}
diff --git a/src/libFLAC/metadata_iterators.c b/src/libFLAC/metadata_iterators.c
new file mode 100644
index 0000000..20e926b
--- /dev/null
+++ b/src/libFLAC/metadata_iterators.c
@@ -0,0 +1,3554 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#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"
+#include "share/compat.h"
+#include "share/macros.h"
+#include "private/macros.h"
+#include "private/memory.h"
+
+/* Alias the first (in share/alloc.h) to the second (in src/libFLAC/memory.c). */
+#define safe_malloc_mul_2op_ safe_malloc_mul_2op_p
+
+/****************************************************************************
+ *
+ * Local function declarations
+ *
+ ***************************************************************************/
+
+static void pack_uint32_(FLAC__uint32 val, FLAC__byte *b, uint32_t bytes);
+static void pack_uint32_little_endian_(FLAC__uint32 val, FLAC__byte *b, uint32_t bytes);
+static void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, uint32_t bytes);
+static FLAC__uint32 unpack_uint32_(FLAC__byte *b, uint32_t bytes);
+static FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, uint32_t bytes);
+static FLAC__uint64 unpack_uint64_(FLAC__byte *b, uint32_t 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, uint32_t *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, uint32_t block_length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Application *block, uint32_t block_length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_SeekTable *block, uint32_t 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, uint32_t max_length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_VorbisComment *block, uint32_t block_length);
+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, uint32_t 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, uint32_t block_length);
+static FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Application *block, uint32_t 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, uint32_t 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, uint32_t 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 uint32_t seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb);
+static uint32_t 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, FLAC__off_t fixup_is_last_flag_offset, FLAC__bool backup);
+
+static FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__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, FLAC__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 flac_stat_s *stats);
+static void set_file_stats_(const char *filename, struct flac_stat_s *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, uint32_t max_width, uint32_t max_height, uint32_t max_depth, uint32_t 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);
+ if(0 != obj) {
+ 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);
+ }
+ }
+ else
+ break;
+ }
+ } 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 flac_stat_s stats;
+ FLAC__bool has_stats;
+ FLAC__bool is_writable;
+ FLAC__Metadata_SimpleIteratorStatus status;
+ FLAC__off_t offset[SIMPLE_ITERATOR_MAX_PUSH_DEPTH];
+ FLAC__off_t first_offset; /* this is the offset to the STREAMINFO block */
+ uint32_t depth;
+ /* this is the metadata block header of the current block we are pointing to: */
+ FLAC__bool is_last;
+ FLAC__MetadataType type;
+ uint32_t 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 = 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)
+{
+ uint32_t ret;
+
+ FLAC__ASSERT(0 != iterator);
+
+ if(read_only || 0 == (iterator->file = flac_fopen(iterator->filename, "r+b"))) {
+ iterator->is_writable = false;
+ if(read_only || errno == EACCES) {
+ if(0 == (iterator->file = flac_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);
+ ret = read_metadata_block_header_(iterator);
+ /* The first metadata block must be a streaminfo. If this is not the
+ * case, the file is invalid and assumptions made elsewhere in the
+ * code are invalid */
+ if(iterator->type != FLAC__METADATA_TYPE_STREAMINFO) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA;
+ return false;
+ }
+ return ret;
+ 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 'flac_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);
+ FLAC__ASSERT(iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK);
+
+ 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)
+{
+ FLAC__off_t this_offset;
+
+ FLAC__ASSERT(0 != iterator);
+ FLAC__ASSERT(0 != iterator->file);
+ FLAC__ASSERT(iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK);
+
+ 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) + (FLAC__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);
+ FLAC__ASSERT(iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK);
+
+ 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);
+ FLAC__ASSERT(iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK);
+
+ return (off_t)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);
+ FLAC__ASSERT(iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK);
+
+ return iterator->type;
+}
+
+/*@@@@add to tests*/
+FLAC_API uint32_t FLAC__metadata_simple_iterator_get_block_length(const FLAC__Metadata_SimpleIterator *iterator)
+{
+ FLAC__ASSERT(0 != iterator);
+ FLAC__ASSERT(0 != iterator->file);
+ FLAC__ASSERT(iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK);
+
+ 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 uint32_t id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
+
+ FLAC__ASSERT(0 != iterator);
+ FLAC__ASSERT(0 != iterator->file);
+ FLAC__ASSERT(0 != id);
+ FLAC__ASSERT(iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK);
+
+ 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);
+ FLAC__ASSERT(iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK);
+
+ 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(FLAC__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);
+ FLAC__ASSERT(iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK);
+
+ 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 + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
+ return ret;
+ }
+ else {
+ if((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 + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
+ }
+ return ret;
+ }
+ }
+ else /* iterator->length < block->length */ {
+ uint32_t 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 uint32_t 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 + (FLAC__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 + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
+ return ret;
+ }
+ }
+ else {
+ if((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 + (FLAC__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)
+{
+ uint32_t padding_leftover = 0;
+ FLAC__bool padding_is_last = false;
+
+ FLAC__ASSERT_DECLARATION(FLAC__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);
+ FLAC__ASSERT(iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK);
+
+ if(!iterator->is_writable) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_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 + (FLAC__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 + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
+ return ret;
+ }
+ }
+ else {
+ if((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 + (FLAC__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(FLAC__off_t debug_target_offset = iterator->offset[iterator->depth];)
+ FLAC__bool ret;
+
+ FLAC__ASSERT(iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK);
+
+ if(!iterator->is_writable) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE;
+ return false;
+ }
+
+ 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] + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length == debug_target_offset);
+ FLAC__ASSERT(ftello(iterator->file) + (FLAC__off_t)iterator->length == debug_target_offset);
+ return true;
+ }
+ else {
+ if((ret = rewrite_whole_file_(iterator, 0, /*append=*/false))) {
+ FLAC__ASSERT(iterator->offset[iterator->depth] + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length == debug_target_offset);
+ FLAC__ASSERT(ftello(iterator->file) + (FLAC__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;
+ uint32_t nodes;
+ FLAC__Metadata_ChainStatus status;
+ FLAC__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.
+ */
+ FLAC__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 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 FLAC__off_t chain_calculate_length_(FLAC__Metadata_Chain *chain)
+{
+ const FLAC__Metadata_Node *node;
+ FLAC__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 uint32_t growth = FLAC__STREAM_METADATA_HEADER_LENGTH + node->next->data->length;
+ node->data->length += growth; /* new block size can be greater than max metadata block size, but it'll be fixed later in chain_prepare_for_write_() */
+
+ chain_delete_node_(chain, node->next);
+ return true;
+ }
+ else
+ return false;
+}
+
+#if defined(_MSC_VER)
+// silence three MSVC warnings 'conversion from 'conversion from 'const __int64' to 'uint32_t', possible loss of data'
+#pragma warning ( disable : 4244 )
+#endif
+
+/* 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 FLAC__off_t chain_prepare_for_write_(FLAC__Metadata_Chain *chain, FLAC__bool use_padding)
+{
+ FLAC__off_t current_length = chain_calculate_length_(chain);
+ FLAC__Metadata_Node * i;
+
+ /* Check all is_last settings on the blocks */
+ for(i = chain->head; i->next != NULL; i = i->next)
+ i->data->is_last = 0;
+ chain->tail->data->is_last = 1;
+
+ 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 FLAC__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 + (FLAC__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 FLAC__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((FLAC__off_t)chain->tail->data->length + (FLAC__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((FLAC__off_t)chain->tail->data->length >= delta) {
+ chain->tail->data->length -= delta;
+ current_length -= delta;
+ FLAC__ASSERT(current_length == chain->initial_length);
+ }
+ }
+ }
+ }
+
+ /* check sizes of all metadata blocks; reduce padding size if necessary */
+ {
+ FLAC__Metadata_Node *node;
+ for (node = chain->head; node; node = node->next) {
+ if(node->data->length >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) {
+ if(node->data->type == FLAC__METADATA_TYPE_PADDING) {
+ node->data->length = (1u << FLAC__STREAM_METADATA_LENGTH_LEN) - 1;
+ current_length = chain_calculate_length_(chain);
+ } else {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_BAD_METADATA;
+ return 0;
+ }
+ }
+ }
+ }
+
+ return current_length;
+}
+
+#if defined(_MSC_VER)
+#pragma warning ( default : 4244 )
+#endif
+
+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 = (FLAC__off_t)pos;
+ }
+
+ {
+ FLAC__bool is_last;
+ FLAC__MetadataType type;
+ uint32_t 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)) {
+ node_delete_(node);
+ 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 = (FLAC__off_t)pos;
+ }
+
+ if(chain->head->data->type != FLAC__METADATA_TYPE_STREAMINFO) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_BAD_METADATA;
+ return false;
+ }
+
+ 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);
+
+ if(chain->initial_length == 0 || chain->head->data->type != FLAC__METADATA_TYPE_STREAMINFO) {
+ /* Ogg FLAC file must have at least streaminfo and vorbis comment */
+ chain->status = FLAC__METADATA_CHAIN_STATUS_BAD_METADATA;
+ return false;
+ }
+
+ 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 = flac_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 = NULL;
+ 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 = flac_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);
+ goto err;
+ }
+ if(!copy_n_bytes_from_file_(f, tempfile, chain->first_offset, &status)) {
+ chain->status = get_equivalent_status_(status);
+ goto err;
+ }
+
+ /* 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);
+ goto err;
+ }
+ if(!write_metadata_block_data_(tempfile, &status, node->data)) {
+ chain->status = get_equivalent_status_(status);
+ goto err;
+ }
+ }
+ /*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/
+
+ /* copy the file postfix (everything after the metadata) */
+ if(0 != fseeko(f, chain->last_offset, SEEK_SET)) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+ goto err;
+ }
+ if(!copy_remaining_bytes_from_file_(f, tempfile, &status)) {
+ chain->status = get_equivalent_status_(status);
+ goto err;
+ }
+
+ /* move the tempfile on top of the original */
+ (void)fclose(f);
+ if(!transport_tempfile_(chain->filename, &tempfile, &tempfilename, &status))
+ return false;
+
+ return true;
+
+err:
+ (void)fclose(f);
+ cleanup_tempfile_(&tempfile, &tempfilename);
+ return false;
+}
+
+/* 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 = 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 = flac_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);
+}
+
+typedef enum {
+ LBS_NONE = 0,
+ LBS_SIZE_CHANGED,
+ LBS_BLOCK_ADDED,
+ LBS_BLOCK_REMOVED
+} LastBlockState;
+
+#if defined(_MSC_VER)
+// silence three MSVC warnings 'conversion from 'conversion from 'const __int64' to 'uint32_t', possible loss of data'
+#pragma warning ( disable : 4244 )
+#endif
+
+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.
+ */
+ FLAC__off_t current_length;
+ LastBlockState lbs_state = LBS_NONE;
+ uint32_t lbs_size = 0;
+
+ FLAC__ASSERT(0 != chain);
+
+ current_length = chain_calculate_length_(chain);
+
+ if(use_padding) {
+ const FLAC__Metadata_Node * const node = chain->tail;
+ /* if the metadata shrank and the last block is padding, we just extend the last padding block */
+ if(current_length < chain->initial_length && node->data->type == FLAC__METADATA_TYPE_PADDING) {
+ lbs_state = LBS_SIZE_CHANGED;
+ lbs_size = node->data->length + (chain->initial_length - current_length);
+ }
+ /* if the metadata shrank more than 4 bytes then there's room to add another padding block */
+ else if(current_length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH <= chain->initial_length) {
+ lbs_state = LBS_BLOCK_ADDED;
+ lbs_size = chain->initial_length - (current_length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_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 FLAC__off_t delta = current_length - chain->initial_length;
+ if(node->data->type == FLAC__METADATA_TYPE_PADDING) {
+ /* if the delta is exactly the size of the last padding block, remove the padding block */
+ if((FLAC__off_t)node->data->length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH == delta) {
+ lbs_state = LBS_BLOCK_REMOVED;
+ lbs_size = 0;
+ }
+ /* if there is at least 'delta' bytes of padding, trim the padding down */
+ else if((FLAC__off_t)node->data->length >= delta) {
+ lbs_state = LBS_SIZE_CHANGED;
+ lbs_size = node->data->length - delta;
+ }
+ }
+ }
+ }
+
+ current_length = 0;
+ /* check sizes of all metadata blocks; reduce padding size if necessary */
+ {
+ const FLAC__Metadata_Node *node;
+ for(node = chain->head; node; node = node->next) {
+ uint32_t block_len = node->data->length;
+ if(node == chain->tail) {
+ if(lbs_state == LBS_BLOCK_REMOVED)
+ continue;
+ else if(lbs_state == LBS_SIZE_CHANGED)
+ block_len = lbs_size;
+ }
+ if(block_len >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) {
+ if(node->data->type == FLAC__METADATA_TYPE_PADDING)
+ block_len = (1u << FLAC__STREAM_METADATA_LENGTH_LEN) - 1;
+ else
+ return false /* the return value doesn't matter */;
+ }
+ current_length += (FLAC__STREAM_METADATA_HEADER_LENGTH + block_len);
+ }
+
+ if(lbs_state == LBS_BLOCK_ADDED) {
+ /* test added padding block */
+ uint32_t block_len = lbs_size;
+ if(block_len >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN))
+ block_len = (1u << FLAC__STREAM_METADATA_LENGTH_LEN) - 1;
+ current_length += (FLAC__STREAM_METADATA_HEADER_LENGTH + block_len);
+ }
+ }
+
+ return (current_length != chain->initial_length);
+}
+
+#if defined(_MSC_VER)
+#pragma warning ( default : 4244 )
+#endif
+
+FLAC_API FLAC__bool FLAC__metadata_chain_write(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats)
+{
+ struct flac_stat_s stats;
+ const char *tempfile_path_prefix = 0;
+ FLAC__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)
+{
+ FLAC__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)
+{
+ FLAC__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;
+ uint32_t 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 = 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, uint32_t bytes)
+{
+ uint32_t 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, uint32_t bytes)
+{
+ uint32_t i;
+
+ for(i = 0; i < bytes; i++) {
+ *(b++) = (FLAC__byte)(val & 0xff);
+ val >>= 8;
+ }
+}
+
+void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, uint32_t bytes)
+{
+ uint32_t i;
+
+ b += bytes;
+
+ for(i = 0; i < bytes; i++) {
+ *(--b) = (FLAC__byte)(val & 0xff);
+ val >>= 8;
+ }
+}
+
+FLAC__uint32 unpack_uint32_(FLAC__byte *b, uint32_t bytes)
+{
+ FLAC__uint32 ret = 0;
+ uint32_t i;
+
+ for(i = 0; i < bytes; i++)
+ ret = (ret << 8) | (FLAC__uint32)(*b++);
+
+ return ret;
+}
+
+FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, uint32_t bytes)
+{
+ FLAC__uint32 ret = 0;
+ uint32_t i;
+
+ b += bytes;
+
+ for(i = 0; i < bytes; i++)
+ ret = (ret << 8) | (FLAC__uint32)(*--b);
+
+ return ret;
+}
+
+FLAC__uint64 unpack_uint64_(FLAC__byte *b, uint32_t bytes)
+{
+ FLAC__uint64 ret = 0;
+ uint32_t 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, uint32_t *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, seek_cb, &block->data.vorbis_comment, block->length);
+ 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) | ((uint32_t)(b[2] & 0xf0) >> 4);
+ block->channels = (uint32_t)((b[2] & 0x0e) >> 1) + 1;
+ block->bits_per_sample = ((((uint32_t)(b[2] & 0x01)) << 4) | (((uint32_t)(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, uint32_t 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, uint32_t block_length)
+{
+ const uint32_t 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 = 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, uint32_t block_length)
+{
+ uint32_t i;
+ FLAC__byte buffer[FLAC__STREAM_METADATA_SEEKPOINT_LENGTH];
+
+ if(block_length % FLAC__STREAM_METADATA_SEEKPOINT_LENGTH != 0)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA;
+
+ block->num_points = block_length / FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
+
+ if(block->num_points == 0)
+ block->points = 0;
+ else if(0 == (block->points = safe_malloc_mul_2op_p(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, uint32_t max_length)
+{
+ const uint32_t 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(max_length < entry_length_len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA;
+
+ max_length -= entry_length_len;
+ 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(max_length < entry->length) {
+ entry->length = 0;
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA;
+ }
+
+ if(0 != entry->entry)
+ free(entry->entry);
+
+ if(0 == (entry->entry = safe_malloc_add_2op_(entry->length, /*+*/1)))
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+ if(entry->length > 0 && 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__IOCallback_Seek seek_cb, FLAC__StreamMetadata_VorbisComment *block, uint32_t block_length)
+{
+ uint32_t i;
+ FLAC__Metadata_SimpleIteratorStatus status;
+ const uint32_t 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));
+
+ status = read_metadata_block_data_vorbis_comment_entry_cb_(handle, read_cb, &(block->vendor_string), block_length);
+ if(block_length >= 4)
+ block_length -= 4;
+ if(status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA)
+ goto skip;
+ else if(status != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK)
+ return status;
+ block_length -= block->vendor_string.length;
+
+ if(block_length < num_comments_len) goto skip; else block_length -= num_comments_len;
+ 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(block->num_comments > (block_length >> 2)) { /* each comment needs at least 4 byte */
+ block->num_comments = 0;
+ status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA;
+ goto skip;
+ }
+ else if(0 == (block->comments = calloc(block->num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry)))) {
+ block->num_comments = 0;
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+ }
+
+ for(i = 0; i < block->num_comments; i++) {
+ status = read_metadata_block_data_vorbis_comment_entry_cb_(handle, read_cb, block->comments + i, block_length);
+ if(block_length >= 4) block_length -= 4;
+ if(status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA) {
+ block->num_comments = i;
+ goto skip;
+ }
+ else if(status != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK) return status;
+ block_length -= block->comments[i].length;
+ }
+
+ skip:
+ if(block_length > 0) {
+ /* bad metadata */
+ if(0 != seek_cb(handle, block_length, SEEK_CUR))
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ }
+
+ return status;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_track_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet_Track *track)
+{
+ uint32_t 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 = 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)
+{
+ uint32_t 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) {
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA;
+ }
+ else if(0 == (block->tracks = 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(*length > (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) /* data cannot be larger than FLAC metadata block */
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA;
+
+ if(0 != *data)
+ free(*data);
+
+ if(0 == (*data = 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, uint32_t block_length)
+{
+ if(block_length == 0) {
+ block->data = 0;
+ }
+ else {
+ if(0 == (block->data = 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));
+ /* double protection */
+ if(block->length >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN))
+ return false;
+
+ 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 uint32_t channels1 = block->channels - 1;
+ const uint32_t 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, uint32_t block_length)
+{
+ uint32_t 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, uint32_t block_length)
+{
+ const uint32_t 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)
+{
+ uint32_t 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)
+{
+ uint32_t i;
+ const uint32_t entry_length_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8;
+ const uint32_t num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8;
+ FLAC__byte buffer[4]; /* magic number is asserted below */
+
+ FLAC__ASSERT(flac_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)
+{
+ uint32_t 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 *indx = 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_(indx->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_(indx->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)
+{
+ uint32_t 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, uint32_t 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, uint32_t 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 = NULL;
+ char *tempfilename = NULL;
+ int fixup_is_last_code = 0; /* 0 => no need to change any is_last flags */
+ FLAC__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
+ */
+uint32_t 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;
+ uint32_t 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)) {
+ uint32_t 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;
+}
+
+uint32_t 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 FLAC__off_t offset_end = append? iterator->offset[iterator->depth] + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__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, FLAC__off_t fixup_is_last_flag_offset, FLAC__bool backup)
+{
+ FLAC__off_t save_offset = iterator->offset[iterator->depth];
+ FLAC__ASSERT(0 != *tempfile);
+
+ if(0 != fseeko(iterator->file, save_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__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] + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__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, FLAC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+ FLAC__byte buffer[8192];
+ size_t n;
+
+ FLAC__ASSERT(bytes >= 0);
+ while(bytes > 0) {
+ n = flac_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, FLAC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+ FLAC__byte buffer[8192];
+ size_t n;
+
+ FLAC__ASSERT(bytes >= 0);
+ while(bytes > 0) {
+ n = flac_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;
+}
+
+static int
+local_snprintf(char *str, size_t size, const char *fmt, ...)
+{
+ va_list va;
+ int rc;
+
+#if defined _MSC_VER
+ if (size == 0)
+ return 1024;
+#endif
+
+ va_start (va, fmt);
+
+#if defined _MSC_VER
+ rc = vsnprintf_s (str, size, _TRUNCATE, fmt, va);
+ if (rc < 0)
+ rc = size - 1;
+#elif defined __MINGW32__
+ rc = __mingw_vsnprintf (str, size, fmt, va);
+#else
+ rc = vsnprintf (str, size, fmt, va);
+#endif
+ va_end (va);
+
+ return rc;
+}
+
+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) {
+ size_t dest_len = strlen(filename) + strlen(tempfile_suffix) + 1;
+ if(0 == (*tempfilename = safe_malloc_(dest_len))) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ local_snprintf(*tempfilename, dest_len, "%s%s", filename, tempfile_suffix);
+ }
+ else {
+ const char *p = strrchr(filename, '/');
+ size_t dest_len;
+ if(0 == p)
+ p = filename;
+ else
+ p++;
+
+ dest_len = strlen(tempfile_path_prefix) + strlen(p) + strlen(tempfile_suffix) + 2;
+
+ if(0 == (*tempfilename = safe_malloc_(dest_len))) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ local_snprintf(*tempfilename, dest_len, "%s/%s%s", tempfile_path_prefix, p, tempfile_suffix);
+ }
+
+ if(0 == (*tempfile = flac_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, flac_rename() will fail if the destination already exists */
+ if(flac_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 flac_rename(): */
+ if(0 != flac_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)flac_unlink(*tempfilename);
+ free(*tempfilename);
+ *tempfilename = 0;
+ }
+}
+
+FLAC__bool get_file_stats_(const char *filename, struct flac_stat_s *stats)
+{
+ FLAC__ASSERT(0 != filename);
+ FLAC__ASSERT(0 != stats);
+ return (0 == flac_stat(filename, stats));
+}
+
+void set_file_stats_(const char *filename, struct flac_stat_s *stats)
+{
+#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L) && !defined(_WIN32)
+ struct timespec srctime[2] = {};
+ srctime[0].tv_sec = stats->st_atime;
+ srctime[1].tv_sec = stats->st_mtime;
+#else
+ struct utimbuf srctime;
+ srctime.actime = stats->st_atime;
+ srctime.modtime = stats->st_mtime;
+#endif
+
+ FLAC__ASSERT(0 != filename);
+ FLAC__ASSERT(0 != stats);
+
+ (void)flac_chmod(filename, stats->st_mode);
+ (void)flac_utime(filename, &srctime);
+#if !defined _MSC_VER && !defined __BORLANDC__ && !defined __MINGW32__
+ FLAC_CHECK_RETURN(chown(filename, stats->st_uid, -1));
+ FLAC_CHECK_RETURN(chown(filename, -1, stats->st_gid));
+#endif
+}
+
+int fseek_wrapper_(FLAC__IOHandle handle, FLAC__int64 offset, int whence)
+{
+ return fseeko((FILE*)handle, (FLAC__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
index 0000000..73e7607
--- /dev/null
+++ b/src/libFLAC/metadata_object.c
@@ -0,0 +1,2018 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "private/metadata.h"
+#include "private/memory.h"
+#include "private/stream_encoder_framing.h"
+
+#include "FLAC/assert.h"
+#include "FLAC/stream_decoder.h"
+#include "share/alloc.h"
+#include "share/compat.h"
+
+/* Alias the first (in share/alloc.h) to the second (in src/libFLAC/memory.c). */
+#define safe_malloc_mul_2op_ safe_malloc_mul_2op_p
+
+
+/****************************************************************************
+ *
+ * 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, uint32_t bytes)
+{
+ FLAC__ASSERT(to != NULL);
+ if (bytes > 0 && from != NULL) {
+ FLAC__byte *x;
+ if ((x = safe_malloc_(bytes)) == NULL)
+ return false;
+ memcpy(x, from, bytes);
+ *to = x;
+ }
+ else {
+ *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, uint32_t bytes)
+{
+ FLAC__byte *copy;
+ FLAC__ASSERT(to != NULL);
+ if (copy_bytes_(&copy, from, bytes)) {
+ 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, uint32_t length)
+{
+ FLAC__byte *x = safe_realloc_nofree_add_2op_(*entry, length, /*+*/1);
+ if (x != NULL) {
+ 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 != NULL);
+ if (copy) {
+ 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 (from->entry == 0) {
+ FLAC__ASSERT(from->length == 0);
+ if ((to->entry = safe_malloc_(1)) == NULL)
+ return false;
+ to->entry[0] = '\0';
+ }
+ else {
+ FLAC__byte *x;
+ if ((x = safe_malloc_add_2op_(from->length, /*+*/1)) == NULL)
+ 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 (from->indices == 0) {
+ FLAC__ASSERT(from->num_indices == 0);
+ }
+ else {
+ FLAC__StreamMetadata_CueSheet_Index *x;
+ FLAC__ASSERT(from->num_indices > 0);
+ if ((x = safe_malloc_mul_2op_p(from->num_indices, /*times*/sizeof(FLAC__StreamMetadata_CueSheet_Index))) == NULL)
+ 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(object != NULL);
+ 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_(uint32_t num_points)
+{
+ FLAC__StreamMetadata_SeekPoint *object_array;
+
+ FLAC__ASSERT(num_points > 0);
+
+ object_array = safe_malloc_mul_2op_p(num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint));
+
+ if (object_array != NULL) {
+ uint32_t 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)
+{
+ uint32_t 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_(uint32_t num_comments)
+{
+ FLAC__ASSERT(num_comments > 0);
+
+ return safe_calloc_(num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry));
+}
+
+static void vorbiscomment_entry_array_delete_(FLAC__StreamMetadata_VorbisComment_Entry *object_array, uint32_t num_comments)
+{
+ uint32_t i;
+
+ FLAC__ASSERT(object_array != NULL);
+
+ for (i = 0; i < num_comments; i++)
+ free(object_array[i].entry);
+
+ free(object_array);
+}
+
+static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_copy_(const FLAC__StreamMetadata_VorbisComment_Entry *object_array, uint32_t num_comments)
+{
+ FLAC__StreamMetadata_VorbisComment_Entry *return_array;
+
+ FLAC__ASSERT(object_array != NULL);
+ FLAC__ASSERT(num_comments > 0);
+
+ return_array = vorbiscomment_entry_array_new_(num_comments);
+
+ if (return_array != NULL) {
+ uint32_t 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(object != NULL);
+ FLAC__ASSERT(dest != NULL);
+ FLAC__ASSERT(src != NULL);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+ FLAC__ASSERT((src->entry != NULL && src->length > 0) || (src->entry == NULL && src->length == 0));
+
+ save = dest->entry;
+
+ if (src->entry != NULL) {
+ 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;
+ }
+
+ free(save);
+
+ vorbiscomment_calculate_length_(object);
+ return true;
+}
+
+static int vorbiscomment_find_entry_from_(const FLAC__StreamMetadata *object, uint32_t offset, const char *field_name, uint32_t field_name_length)
+{
+ uint32_t i;
+
+ FLAC__ASSERT(object != NULL);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+ FLAC__ASSERT(field_name != NULL);
+
+ 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)
+{
+ uint32_t 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_(uint32_t num_indices)
+{
+ FLAC__ASSERT(num_indices > 0);
+
+ return safe_calloc_(num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index));
+}
+
+static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_new_(uint32_t num_tracks)
+{
+ FLAC__ASSERT(num_tracks > 0);
+
+ return safe_calloc_(num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track));
+}
+
+static void cuesheet_track_array_delete_(FLAC__StreamMetadata_CueSheet_Track *object_array, uint32_t num_tracks)
+{
+ uint32_t i;
+
+ FLAC__ASSERT(object_array != NULL && num_tracks > 0);
+
+ for (i = 0; i < num_tracks; i++) {
+ if (object_array[i].indices != 0) {
+ FLAC__ASSERT(object_array[i].num_indices > 0);
+ free(object_array[i].indices);
+ }
+ }
+
+ free(object_array);
+}
+
+static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_copy_(const FLAC__StreamMetadata_CueSheet_Track *object_array, uint32_t num_tracks)
+{
+ FLAC__StreamMetadata_CueSheet_Track *return_array;
+
+ FLAC__ASSERT(object_array != NULL);
+ FLAC__ASSERT(num_tracks > 0);
+
+ return_array = cuesheet_track_array_new_(num_tracks);
+
+ if (return_array != NULL) {
+ uint32_t 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(object != NULL);
+ FLAC__ASSERT(dest != NULL);
+ FLAC__ASSERT(src != NULL);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+ FLAC__ASSERT((src->indices != NULL && src->num_indices > 0) || (src->indices == NULL && 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;
+ }
+
+ 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)
+ return 0;
+
+ object = calloc(1, sizeof(FLAC__StreamMetadata));
+ if (object != NULL) {
+ 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 = (uint32_t)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), "")) {
+ 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(object != NULL);
+
+ if ((to = FLAC__metadata_object_new(object->type)) != NULL) {
+ 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 > UINT32_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 (to->data.vorbis_comment.vendor_string.entry != NULL) {
+ 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) {
+ to->data.vorbis_comment.comments = 0;
+ }
+ else {
+ to->data.vorbis_comment.comments = vorbiscomment_entry_array_copy_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments);
+ if (to->data.vorbis_comment.comments == NULL) {
+ to->data.vorbis_comment.num_comments = 0;
+ 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(object->data.cue_sheet.tracks == NULL);
+ }
+ else {
+ FLAC__ASSERT(object->data.cue_sheet.tracks != 0);
+ to->data.cue_sheet.tracks = cuesheet_track_array_copy_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks);
+ if (to->data.cue_sheet.tracks == NULL) {
+ 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(object != NULL);
+
+ switch(object->type) {
+ case FLAC__METADATA_TYPE_STREAMINFO:
+ case FLAC__METADATA_TYPE_PADDING:
+ break;
+ case FLAC__METADATA_TYPE_APPLICATION:
+ if (object->data.application.data != NULL) {
+ free(object->data.application.data);
+ object->data.application.data = NULL;
+ }
+ break;
+ case FLAC__METADATA_TYPE_SEEKTABLE:
+ if (object->data.seek_table.points != NULL) {
+ free(object->data.seek_table.points);
+ object->data.seek_table.points = NULL;
+ }
+ break;
+ case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+ if (object->data.vorbis_comment.vendor_string.entry != NULL) {
+ free(object->data.vorbis_comment.vendor_string.entry);
+ object->data.vorbis_comment.vendor_string.entry = 0;
+ }
+ if (object->data.vorbis_comment.comments != NULL) {
+ vorbiscomment_entry_array_delete_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments);
+ object->data.vorbis_comment.comments = NULL;
+ object->data.vorbis_comment.num_comments = 0;
+ }
+ break;
+ case FLAC__METADATA_TYPE_CUESHEET:
+ if (object->data.cue_sheet.tracks != NULL) {
+ FLAC__ASSERT(object->data.cue_sheet.num_tracks > 0);
+ cuesheet_track_array_delete_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks);
+ object->data.cue_sheet.tracks = NULL;
+ object->data.cue_sheet.num_tracks = 0;
+ }
+ break;
+ case FLAC__METADATA_TYPE_PICTURE:
+ if (object->data.picture.mime_type != NULL) {
+ free(object->data.picture.mime_type);
+ object->data.picture.mime_type = NULL;
+ }
+ if (object->data.picture.description != NULL) {
+ free(object->data.picture.description);
+ object->data.picture.description = NULL;
+ }
+ if (object->data.picture.data != NULL) {
+ free(object->data.picture.data);
+ object->data.picture.data = NULL;
+ }
+ break;
+ default:
+ if (object->data.unknown.data != NULL) {
+ free(object->data.unknown.data);
+ object->data.unknown.data = NULL;
+ }
+ 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 (memcmp(block1->md5sum, block2->md5sum, 16) != 0)
+ return false;
+ return true;
+}
+
+static FLAC__bool compare_block_data_application_(const FLAC__StreamMetadata_Application *block1, const FLAC__StreamMetadata_Application *block2, uint32_t block_length)
+{
+ FLAC__ASSERT(block1 != NULL);
+ FLAC__ASSERT(block2 != NULL);
+ FLAC__ASSERT(block_length >= sizeof(block1->id));
+
+ if (memcmp(block1->id, block2->id, sizeof(block1->id)) != 0)
+ return false;
+ if (block1->data != NULL && block2->data != NULL)
+ return memcmp(block1->data, block2->data, block_length - sizeof(block1->id)) == 0;
+ else
+ return block1->data == block2->data;
+}
+
+static FLAC__bool compare_block_data_seektable_(const FLAC__StreamMetadata_SeekTable *block1, const FLAC__StreamMetadata_SeekTable *block2)
+{
+ uint32_t i;
+
+ FLAC__ASSERT(block1 != NULL);
+ FLAC__ASSERT(block2 != NULL);
+
+ if (block1->num_points != block2->num_points)
+ return false;
+
+ if (block1->points != NULL && block2->points != NULL) {
+ 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)
+{
+ uint32_t i;
+
+ if (block1->vendor_string.length != block2->vendor_string.length)
+ return false;
+
+ if (block1->vendor_string.entry != NULL && block2->vendor_string.entry != NULL) {
+ if (memcmp(block1->vendor_string.entry, block2->vendor_string.entry, block1->vendor_string.length) != 0)
+ 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 (block1->comments[i].entry != NULL && block2->comments[i].entry != NULL) {
+ if (memcmp(block1->comments[i].entry, block2->comments[i].entry, block1->comments[i].length) != 0)
+ 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)
+{
+ uint32_t i, j;
+
+ if (strcmp(block1->media_catalog_number, block2->media_catalog_number) != 0)
+ 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 (block1->tracks != NULL && block2->tracks != NULL) {
+ 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 (memcmp(block1->tracks[i].isrc, block2->tracks[i].isrc, sizeof(block1->tracks[i].isrc)) != 0)
+ 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 (block1->tracks[i].indices != NULL && block2->tracks[i].indices != NULL) {
+ 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 && (block1->mime_type == 0 || block2->mime_type == 0 || strcmp(block1->mime_type, block2->mime_type)))
+ return false;
+ if (block1->description != block2->description && (block1->description == 0 || block2->description == 0 || 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 && (block1->data == NULL || block2->data == NULL || 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, uint32_t block_length)
+{
+ FLAC__ASSERT(block1 != NULL);
+ FLAC__ASSERT(block2 != NULL);
+
+ if (block1->data != NULL && block2->data != NULL)
+ return memcmp(block1->data, block2->data, block_length) == 0;
+ 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(block1 != NULL);
+ FLAC__ASSERT(block2 != NULL);
+
+ 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, uint32_t length, FLAC__bool copy)
+{
+ FLAC__byte *save;
+
+ FLAC__ASSERT(object != NULL);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_APPLICATION);
+ FLAC__ASSERT((data != NULL && length > 0) || (data == NULL && 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;
+ }
+
+ 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, uint32_t new_num_points)
+{
+ FLAC__ASSERT(object != NULL);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+ if((FLAC__uint64)(new_num_points) * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN))
+ return false;
+
+ if (object->data.seek_table.points == 0) {
+ FLAC__ASSERT(object->data.seek_table.num_points == 0);
+ if (new_num_points == 0)
+ return true;
+ else if ((object->data.seek_table.points = seekpoint_array_new_(new_num_points)) == 0)
+ 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 (new_num_points > UINT32_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 {
+ /* Leave object->data.seek_table.points untouched if realloc fails */
+ FLAC__StreamMetadata_SeekPoint *tmpptr;
+ if ((tmpptr = realloc(object->data.seek_table.points, new_size)) == NULL)
+ return false;
+ object->data.seek_table.points = tmpptr;
+ }
+
+ /* if growing, set new elements to placeholders */
+ if (new_size > old_size) {
+ uint32_t 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, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point)
+{
+ FLAC__ASSERT(object != NULL);
+ 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, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point)
+{
+ int i;
+
+ FLAC__ASSERT(object != NULL);
+ 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, uint32_t point_num)
+{
+ uint32_t i;
+
+ FLAC__ASSERT(object != NULL);
+ 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(object != NULL);
+ 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, uint32_t num)
+{
+ FLAC__ASSERT(object != NULL);
+ 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(object != NULL);
+ 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[], uint32_t num)
+{
+ FLAC__ASSERT(object != NULL);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+ FLAC__ASSERT(sample_numbers != 0 || num == 0);
+
+ if (num > 0) {
+ FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table;
+ uint32_t 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, uint32_t num, FLAC__uint64 total_samples)
+{
+ FLAC__ASSERT(object != NULL);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+ if (num > 0 && total_samples > 0) {
+ FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table;
+ uint32_t 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, uint32_t samples, FLAC__uint64 total_samples)
+{
+ FLAC__ASSERT(object != NULL);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+ if (samples > 0 && total_samples > 0) {
+ FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table;
+ uint32_t 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--;
+
+ /* Put a strict upper bound on the number of allowed seek points. */
+ if (num > 32768) {
+ /* Set the bound and recalculate samples accordingly. */
+ num = 32768;
+ samples = (uint32_t)(total_samples / num);
+ }
+
+ i = seek_table->num_points;
+
+ if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + (uint32_t)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)
+{
+ uint32_t unique;
+
+ FLAC__ASSERT(object != NULL);
+ 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, uint32_t new_num_comments)
+{
+ FLAC__ASSERT(object != NULL);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+ if (object->data.vorbis_comment.comments == NULL) {
+ FLAC__ASSERT(object->data.vorbis_comment.num_comments == 0);
+ if (new_num_comments == 0)
+ return true;
+ else {
+ uint32_t i;
+ if ((object->data.vorbis_comment.comments = vorbiscomment_entry_array_new_(new_num_comments)) == NULL)
+ return false;
+ for (i = 0; i < new_num_comments; i++) {
+ object->data.vorbis_comment.comments[i].length = 0;
+ if ((object->data.vorbis_comment.comments[i].entry = safe_malloc_(1)) == NULL) {
+ object->data.vorbis_comment.num_comments = i+1;
+ return false;
+ }
+ object->data.vorbis_comment.comments[i].entry[0] = '\0';
+ }
+ }
+ }
+ 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 (new_num_comments > UINT32_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) {
+ uint32_t i;
+ for (i = new_num_comments; i < object->data.vorbis_comment.num_comments; i++)
+ if (object->data.vorbis_comment.comments[i].entry != NULL)
+ 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 {
+ /* Leave object->data.vorbis_comment.comments untouched if realloc fails */
+ FLAC__StreamMetadata_VorbisComment_Entry *tmpptr;
+ if ((tmpptr = realloc(object->data.vorbis_comment.comments, new_size)) == NULL)
+ return false;
+ object->data.vorbis_comment.comments = tmpptr;
+ }
+
+ /* if growing, zero all the length/pointers of new elements */
+ if (new_size > old_size) {
+ uint32_t i;
+ for (i = object->data.vorbis_comment.num_comments; i < new_num_comments; i++) {
+ object->data.vorbis_comment.comments[i].length = 0;
+ if ((object->data.vorbis_comment.comments[i].entry = safe_malloc_(1)) == NULL) {
+ object->data.vorbis_comment.num_comments = i+1;
+ return false;
+ }
+ object->data.vorbis_comment.comments[i].entry[0] = '\0';
+ }
+ }
+ }
+
+ 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, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
+{
+ FLAC__ASSERT(object != NULL);
+ 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, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
+{
+ FLAC__StreamMetadata_VorbisComment *vc;
+ FLAC__StreamMetadata_VorbisComment_Entry temp;
+
+ FLAC__ASSERT(object != NULL);
+ 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 */
+ /* reuse newly added empty comment */
+ temp = vc->comments[vc->num_comments-1];
+ 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] = temp;
+
+ 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(object != NULL);
+ 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(entry.entry != NULL);
+
+ 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);
+
+ if (eq == NULL)
+ return false; /* double protection */
+
+ field_name_length = eq-entry.entry;
+
+ i = vorbiscomment_find_entry_from_(object, 0, (const char *)entry.entry, field_name_length);
+ if (i >= 0) {
+ uint32_t indx = (uint32_t)i;
+ if (!FLAC__metadata_object_vorbiscomment_set_comment(object, indx, entry, copy))
+ return false;
+ entry = object->data.vorbis_comment.comments[indx];
+ indx++; /* skip over replaced comment */
+ if (all && indx < object->data.vorbis_comment.num_comments) {
+ i = vorbiscomment_find_entry_from_(object, indx, (const char *)entry.entry, field_name_length);
+ while (i >= 0) {
+ indx = (uint32_t)i;
+ if (!FLAC__metadata_object_vorbiscomment_delete_comment(object, indx))
+ return false;
+ if (indx < object->data.vorbis_comment.num_comments)
+ i = vorbiscomment_find_entry_from_(object, indx, (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, uint32_t comment_num)
+{
+ FLAC__StreamMetadata_VorbisComment *vc;
+
+ FLAC__ASSERT(object != NULL);
+ 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 */
+ 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(entry != NULL);
+ FLAC__ASSERT(field_name != NULL);
+ FLAC__ASSERT(field_value != NULL);
+
+ 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, (uint32_t)(-1)))
+ return false;
+
+ {
+ const size_t nn = strlen(field_name);
+ const size_t nv = strlen(field_value);
+ entry->length = nn + 1 /*=*/ + nv;
+ if ((entry->entry = safe_malloc_add_4op_(nn, /*+*/1, /*+*/nv, /*+*/1)) == NULL)
+ 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(entry.entry != NULL);
+ FLAC__ASSERT(field_name != NULL);
+ FLAC__ASSERT(field_value != NULL);
+
+ 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 '=' */
+
+ if (eq == NULL)
+ return false; /* double protection */
+ if ((*field_name = safe_malloc_add_2op_(nn, /*+*/1)) == NULL)
+ return false;
+ if ((*field_value = safe_malloc_add_2op_(nv, /*+*/1)) == NULL) {
+ 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, uint32_t field_name_length)
+{
+ FLAC__ASSERT(entry.entry != NULL);
+ {
+ const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length);
+ return (eq != NULL && (uint32_t)(eq-entry.entry) == field_name_length && FLAC__STRNCASECMP(field_name, (const char *)entry.entry, field_name_length) == 0);
+ }
+}
+
+FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, uint32_t offset, const char *field_name)
+{
+ FLAC__ASSERT(field_name != NULL);
+
+ 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 uint32_t field_name_length = strlen(field_name);
+ uint32_t i;
+
+ FLAC__ASSERT(object != NULL);
+ 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;
+ uint32_t matching = 0;
+ const uint32_t field_name_length = strlen(field_name);
+ int i;
+
+ FLAC__ASSERT(object != NULL);
+ 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, (uint32_t)i);
+ }
+ }
+
+ return ok? (int)matching : -1;
+}
+
+FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new(void)
+{
+ return 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(object != NULL);
+
+ if ((to = FLAC__metadata_object_cuesheet_track_new()) != NULL) {
+ 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(object != NULL);
+
+ if (object->indices != NULL) {
+ 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, uint32_t track_num, uint32_t new_num_indices)
+{
+ FLAC__StreamMetadata_CueSheet_Track *track;
+ FLAC__ASSERT(object != NULL);
+ 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 (track->indices == NULL) {
+ FLAC__ASSERT(track->num_indices == 0);
+ if (new_num_indices == 0)
+ return true;
+ else if ((track->indices = cuesheet_track_index_array_new_(new_num_indices)) == NULL)
+ 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 (new_num_indices > UINT32_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 {
+ /* Leave track->indices untouched if realloc fails */
+ FLAC__StreamMetadata_CueSheet_Index *tmpptr;
+ if ((tmpptr = realloc(track->indices, new_size)) == NULL)
+ return false;
+ track->indices = tmpptr;
+ }
+
+ /* 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, uint32_t track_num, uint32_t index_num, FLAC__StreamMetadata_CueSheet_Index indx)
+{
+ FLAC__StreamMetadata_CueSheet_Track *track;
+
+ FLAC__ASSERT(object != NULL);
+ 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] = indx;
+ cuesheet_calculate_length_(object);
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num)
+{
+ FLAC__StreamMetadata_CueSheet_Index indx;
+ memset(&indx, 0, sizeof(indx));
+ return FLAC__metadata_object_cuesheet_track_insert_index(object, track_num, index_num, indx);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num)
+{
+ FLAC__StreamMetadata_CueSheet_Track *track;
+
+ FLAC__ASSERT(object != NULL);
+ 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, uint32_t new_num_tracks)
+{
+ FLAC__ASSERT(object != NULL);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+
+ if (object->data.cue_sheet.tracks == NULL) {
+ FLAC__ASSERT(object->data.cue_sheet.num_tracks == 0);
+ if (new_num_tracks == 0)
+ return true;
+ else if ((object->data.cue_sheet.tracks = cuesheet_track_array_new_(new_num_tracks)) == NULL)
+ 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 (new_num_tracks > UINT32_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) {
+ uint32_t i;
+ for (i = new_num_tracks; i < object->data.cue_sheet.num_tracks; i++)
+ 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 {
+ /* Leave object->data.cue_sheet.tracks untouched if realloc fails */
+ FLAC__StreamMetadata_CueSheet_Track *tmpptr;
+ if ((tmpptr = realloc(object->data.cue_sheet.tracks, new_size)) == NULL)
+ return false;
+ object->data.cue_sheet.tracks = tmpptr;
+ }
+
+ /* 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, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy)
+{
+ FLAC__ASSERT(object != NULL);
+ 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, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy)
+{
+ FLAC__StreamMetadata_CueSheet *cs;
+
+ FLAC__ASSERT(object != NULL);
+ 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, uint32_t 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, uint32_t track_num)
+{
+ FLAC__StreamMetadata_CueSheet *cs;
+
+ FLAC__ASSERT(object != NULL);
+ 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 */
+ 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(object != NULL);
+ 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, uint32_t 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(object != NULL);
+ 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(object != NULL);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
+ FLAC__ASSERT(mime_type != NULL);
+
+ 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;
+ }
+
+ 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(object != NULL);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
+ FLAC__ASSERT(description != NULL);
+
+ 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;
+ }
+
+ 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(object != NULL);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
+ FLAC__ASSERT((data != NULL && length > 0) || (data == NULL && 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;
+ }
+
+ 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(object != NULL);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
+
+ return FLAC__format_picture_is_legal(&object->data.picture, violation);
+}
+
+FLAC_API FLAC__byte * FLAC__metadata_object_get_raw(const FLAC__StreamMetadata *object)
+{
+ FLAC__BitWriter *bw;
+ const FLAC__byte * buffer;
+ FLAC__byte * output;
+ size_t bytes;
+
+ FLAC__ASSERT(object != NULL);
+
+ if((bw = FLAC__bitwriter_new()) == NULL)
+ return 0;
+ if(!FLAC__bitwriter_init(bw)) {
+ FLAC__bitwriter_delete(bw);
+ return 0;
+ }
+ if(!FLAC__add_metadata_block(object, bw, false)) {
+ FLAC__bitwriter_delete(bw);
+ return 0;
+ }
+
+ if(!FLAC__bitwriter_get_buffer(bw, &buffer, &bytes)) {
+ FLAC__bitwriter_delete(bw);
+ return 0;
+ }
+
+ /* Extra check whether length of bitwriter agrees with length of metadata block */
+ if(bytes != (object->length+FLAC__STREAM_METADATA_HEADER_LENGTH)) {
+ FLAC__bitwriter_delete(bw);
+ return 0;
+ }
+
+ output = safe_malloc_(bytes);
+ if(output == 0) {
+ FLAC__bitwriter_delete(bw);
+ return 0;
+ }
+
+ memcpy(output,buffer,bytes);
+ FLAC__bitwriter_delete(bw);
+ return output;
+}
+
+/* The following callbacks are for FLAC__metadata_object_set_raw */
+
+static FLAC__StreamDecoderReadStatus 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);
+
+typedef struct {
+ FLAC__StreamMetadata *object;
+ FLAC__bool got_error;
+ FLAC__byte *buffer;
+ FLAC__int32 length;
+ FLAC__int32 tell;
+} set_raw_client_data;
+
+FLAC_API FLAC__StreamMetadata * FLAC__metadata_object_set_raw(FLAC__byte *buffer, FLAC__uint32 length)
+{
+ set_raw_client_data cd;
+ FLAC__StreamDecoder * decoder;
+
+ cd.buffer = buffer;
+ cd.length = length;
+ cd.got_error = false;
+ cd.object = 0;
+ cd.tell = -4;
+
+ decoder = FLAC__stream_decoder_new();
+
+ if(0 == decoder)
+ return 0;
+
+ FLAC__stream_decoder_set_md5_checking(decoder, false);
+ FLAC__stream_decoder_set_metadata_respond_all(decoder);
+
+ if(FLAC__stream_decoder_init_stream(decoder, read_callback_, NULL, NULL, NULL, NULL, 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) && FLAC__stream_decoder_get_state(decoder) != FLAC__STREAM_DECODER_END_OF_STREAM) || 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__StreamDecoderReadStatus read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte *buffer, size_t *bytes, void *client_data)
+{
+ set_raw_client_data *cd = (set_raw_client_data *)client_data;
+ (void)decoder;
+
+ if(cd->tell == -4) {
+ if(*bytes < 4)
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ buffer[0] = 'f';
+ buffer[1] = 'L';
+ buffer[2] = 'a';
+ buffer[3] = 'C';
+ *bytes = 4;
+ cd->tell = 0;
+ return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+ }
+ else if(cd->tell < 0)
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ else if(cd->tell == cd->length) {
+ *bytes = 0;
+ return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+ }
+ else {
+ if((FLAC__int32)(*bytes) > (cd->length - cd->tell))
+ *bytes = cd->length - cd->tell;
+ memcpy(buffer, cd->buffer+cd->tell, *bytes);
+ cd->tell += *bytes;
+ return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+ }
+}
+
+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)
+{
+ set_raw_client_data *cd = (set_raw_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)
+{
+ set_raw_client_data *cd = (set_raw_client_data *)client_data;
+ (void)decoder;
+
+ if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC)
+ cd->got_error = true;
+}
diff --git a/src/libFLAC/ogg_decoder_aspect.c b/src/libFLAC/ogg_decoder_aspect.c
new file mode 100644
index 0000000..58a2934
--- /dev/null
+++ b/src/libFLAC/ogg_decoder_aspect.c
@@ -0,0 +1,251 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef 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"
+#include "private/macros.h"
+
+
+/***********************************************************************
+ *
+ * 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 accommodate 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 uint32_t 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 = (uint32_t)(*b);
+ b += FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH;
+ aspect->version_minor = (uint32_t)(*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 = flac_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
index 0000000..a88713b
--- /dev/null
+++ b/src/libFLAC/ogg_encoder_aspect.c
@@ -0,0 +1,228 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef 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, uint32_t 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, uint32_t samples, uint32_t 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 = (uint8_t *)synthetic_first_packet_body;
+ packet.bytes = sizeof(synthetic_first_packet_body);
+
+ packet.b_o_s = 1;
+ aspect->is_first_packet = false;
+ }
+ else {
+ packet.packet = (uint8_t *)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
index 0000000..a4be34d
--- /dev/null
+++ b/src/libFLAC/ogg_helper.c
@@ -0,0 +1,210 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2004-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef 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 uint32_t OGG_HEADER_FIXED_PORTION_LEN = 27;
+ static const uint32_t 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 = 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;
+
+ {
+ uint32_t i;
+
+ /* check to see that it specifies a single packet */
+ for(i = 0; i < (uint32_t)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 = 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
index 0000000..756c716
--- /dev/null
+++ b/src/libFLAC/ogg_mapping.c
@@ -0,0 +1,48 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2004-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "private/ogg_mapping.h"
+
+const uint32_t 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 uint32_t FLAC__OGG_MAPPING_VERSION_MAJOR_LEN = 8; /* bits */
+const uint32_t FLAC__OGG_MAPPING_VERSION_MINOR_LEN = 8; /* bits */
+
+const uint32_t FLAC__OGG_MAPPING_NUM_HEADERS_LEN = 16; /* bits */
diff --git a/src/libFLAC/stream_decoder.c b/src/libFLAC/stream_decoder.c
new file mode 100644
index 0000000..18d8dd3
--- /dev/null
+++ b/src/libFLAC/stream_decoder.c
@@ -0,0 +1,3731 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memset/memcpy() */
+#include <sys/types.h> /* for off_t */
+#include <sys/stat.h> /* for stat() */
+#include "share/compat.h"
+#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"
+#include "private/macros.h"
+
+
+/* technically this should be in an "export.c" but this is convenient enough */
+FLAC_API int FLAC_API_SUPPORTS_OGG_FLAC = FLAC__HAS_OGG;
+
+
+/***********************************************************************
+ *
+ * Private static data
+ *
+ ***********************************************************************/
+
+static const 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, uint32_t size, uint32_t channels, uint32_t bps);
+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, uint32_t length);
+static FLAC__bool read_metadata_seektable_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, uint32_t length);
+static FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj, uint32_t length);
+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, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, const uint32_t order, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, const uint32_t order, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode);
+static FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, uint32_t predictor_order, uint32_t 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 void undo_channel_coding(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 {
+ FLAC__bool is_ogg;
+ 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;
+ 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__int64 *side_subframe;
+ FLAC__bool side_subframe_in_use;
+ FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents[FLAC__MAX_CHANNELS];
+ uint32_t 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 decoded or seeked to */
+ FLAC__bool last_frame_is_set;
+ FLAC__uint64 first_frame_offset; /* hint to the seek routine of where in the stream the first audio frame starts */
+ FLAC__uint64 last_seen_framesync; /* if tell callback works, the location of the last seen frame sync code, to rewind to if needed */
+ FLAC__uint64 target_sample;
+ uint32_t unparseable_frame_count; /* used to tell whether we're decoding a future version of FLAC or just got a bad sync */
+ FLAC__bool got_a_frame; /* hack needed in Ogg FLAC seek routine to check when process_single() actually writes a frame */
+ FLAC__bool (*local_bitreader_read_rice_signed_block)(FLAC__BitReader *br, int vals[], uint32_t nvals, uint32_t parameter);
+} 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",
+ "FLAC__STREAM_DECODER_ERROR_STATUS_BAD_METADATA"
+};
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new(void)
+{
+ FLAC__StreamDecoder *decoder;
+ uint32_t i;
+
+ FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */
+
+ decoder = calloc(1, sizeof(FLAC__StreamDecoder));
+ if(decoder == 0) {
+ return 0;
+ }
+
+ decoder->protected_ = calloc(1, sizeof(FLAC__StreamDecoderProtected));
+ if(decoder->protected_ == 0) {
+ free(decoder);
+ return 0;
+ }
+
+ decoder->private_ = 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 = 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_->side_subframe = 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)
+{
+ uint32_t i;
+
+ if (decoder == NULL)
+ return ;
+
+ 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 == 0 && is_ogg)
+ return FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER;
+
+ 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_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE;
+#endif
+
+ FLAC__cpu_info(&decoder->private_->cpuinfo);
+ decoder->private_->local_bitreader_read_rice_signed_block = FLAC__bitreader_read_rice_signed_block;
+
+#ifdef FLAC__BMI2_SUPPORTED
+ if (decoder->private_->cpuinfo.x86.bmi2) {
+ decoder->private_->local_bitreader_read_rice_signed_block = FLAC__bitreader_read_rice_signed_block_bmi2;
+ }
+#endif
+
+ /* from here on, errors are fatal */
+
+ if(!FLAC__bitreader_init(decoder->private_->input, 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_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED;
+
+ if(0 == write_callback || 0 == error_callback)
+ return decoder->protected_->initstate = 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_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED;
+
+ if(0 == write_callback || 0 == error_callback)
+ return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS;
+
+ file = filename? flac_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;
+ uint32_t 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__stream_decoder_reset() as to why we
+ * always call FLAC__MD5Final()
+ */
+ FLAC__MD5Final(decoder->private_->computed_md5sum, &decoder->private_->md5context);
+
+ 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() and ..._intrin_sseN()
+ * require 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;
+ }
+ }
+ if(0 != decoder->private_->side_subframe) {
+ free(decoder->private_->side_subframe);
+ decoder->private_->side_subframe = 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((uint32_t)type <= FLAC__MAX_METADATA_TYPE_CODE);
+ /* double protection */
+ if((uint32_t)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 = 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)
+{
+ uint32_t 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((uint32_t)type <= FLAC__MAX_METADATA_TYPE_CODE);
+ /* double protection */
+ if((uint32_t)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 = 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 uint32_t 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 uint32_t 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 uint32_t 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 uint32_t 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 && decoder->private_->is_ogg)
+ return false;
+
+ 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 const void *FLAC__stream_decoder_get_client_data(FLAC__StreamDecoder *decoder)
+{
+ return decoder->private_->client_data;
+}
+
+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_);
+
+ if(!decoder->private_->internal_reset_hack && decoder->protected_->state == FLAC__STREAM_DECODER_UNINITIALIZED)
+ return false;
+
+ decoder->private_->samples_decoded = 0;
+ decoder->private_->do_md5_checking = false;
+ decoder->private_->last_seen_framesync = 0;
+ decoder->private_->last_frame_is_set = 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 */
+ }
+
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_METADATA;
+
+ decoder->private_->has_stream_info = false;
+
+ 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.
+ */
+ if(!decoder->private_->internal_reset_hack) {
+ /* Only finish MD5 context when it has been initialized
+ * (i.e. when internal_reset_hack is not set) */
+ FLAC__MD5Final(decoder->private_->computed_md5sum, &decoder->private_->md5context);
+ }
+ else
+ decoder->private_->internal_reset_hack = false;
+ FLAC__MD5Init(&decoder->private_->md5context);
+
+ decoder->private_->first_frame_offset = 0;
+ decoder->private_->unparseable_frame_count = 0;
+ decoder->private_->last_seen_framesync = 0;
+ decoder->private_->last_frame_is_set = false;
+
+ 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:
+ 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:
+ 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:
+ 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:
+ 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
+ *
+ ***********************************************************************/
+
+uint32_t 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)
+{
+ decoder->private_->is_ogg = false;
+ 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 __EMX__
+ setmode(fileno(stdin), O_BINARY);
+#endif
+
+ return stdin;
+}
+
+FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, uint32_t size, uint32_t channels, uint32_t bps)
+{
+ uint32_t i;
+ FLAC__int32 *tmp;
+
+ if(size <= decoder->private_->output_capacity && channels <= decoder->private_->output_channels &&
+ (bps < 32 || decoder->private_->side_subframe != 0))
+ 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;
+ }
+ }
+
+ if(0 != decoder->private_->side_subframe) {
+ free(decoder->private_->side_subframe);
+ decoder->private_->side_subframe = 0;
+ }
+
+ for(i = 0; i < channels; i++) {
+ /* WATCHOUT:
+ * FLAC__lpc_restore_signal_asm_ia32_mmx() and ..._intrin_sseN()
+ * require 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 = 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;
+
+ 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;
+ }
+ }
+
+ if(bps == 32) {
+ decoder->private_->side_subframe = safe_malloc_mul_2op_p(sizeof(FLAC__int64), /*times (*/size);
+ if(decoder->private_->side_subframe == NULL) {
+ 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;
+ uint32_t 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(id >= 3)
+ return false;
+
+ 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 >> 1 == 0x7c) { /* MAGIC NUMBER for the last 6 sync bits and reserved 7th bit */
+ 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) {
+ /* just in case we already have a seek table, and reading the next one fails: */
+ decoder->private_->has_seek_table = false;
+
+ if(length > 0) {
+ 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];
+ uint32_t real_length = length;
+ FLAC__StreamMetadata block;
+
+ memset(&block, 0, sizeof(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 {
+ FLAC__bool ok = true;
+ FLAC__bitreader_set_limit(decoder->private_->input, real_length*8);
+ 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))
+ ok = 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 = malloc(real_length))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ ok = false;
+ }
+ else if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.application.data, real_length))
+ ok = 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, real_length))
+ ok = false;
+ break;
+ case FLAC__METADATA_TYPE_CUESHEET:
+ if(!read_metadata_cuesheet_(decoder, &block.data.cue_sheet))
+ ok = false;
+ break;
+ case FLAC__METADATA_TYPE_PICTURE:
+ if(!read_metadata_picture_(decoder, &block.data.picture))
+ ok = 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 = malloc(real_length))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ ok = false;
+ }
+ else if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.unknown.data, real_length))
+ ok = false; /* read_callback_ sets the state for us */
+ }
+ else
+ block.data.unknown.data = 0;
+ break;
+ }
+ if(FLAC__bitreader_limit_remaining(decoder->private_->input) > 0) {
+ /* Content in metadata block didn't fit in block length
+ * We cannot know whether the length or the content was
+ * corrupt, so stop parsing metadata */
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_METADATA);
+ if(decoder->protected_->state == FLAC__STREAM_DECODER_READ_METADATA)
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ ok = false;
+ }
+ FLAC__bitreader_remove_limit(decoder->private_->input);
+ if(ok && !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 && 0 != block.data.cue_sheet.tracks)
+ 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(!ok) /* anything that unsets "ok" should also make sure decoder->protected_->state is updated */
+ return false;
+ }
+ }
+
+ 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, uint32_t length)
+{
+ FLAC__uint32 x;
+ uint32_t 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);
+ if (length < (used_bits / 8))
+ return false; /* read_callback_ sets the state for us */
+ 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, uint32_t 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;
+
+ if(length % FLAC__STREAM_METADATA_SEEKPOINT_LENGTH) {
+ FLAC__bitreader_limit_invalidate(decoder->private_->input);
+ return false;
+ }
+
+ 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 = 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);
+
+ FLAC__ASSERT(length == 0);
+
+ return true;
+}
+
+FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj, uint32_t length)
+{
+ FLAC__uint32 i;
+
+ FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
+
+ /* read vendor string */
+ if (length >= 8) {
+ length -= 8; /* vendor string length + num comments entries alone take 8 bytes */
+ 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 (length < obj->vendor_string.length) {
+ obj->vendor_string.length = 0;
+ obj->vendor_string.entry = 0;
+ goto skip;
+ }
+ else
+ length -= obj->vendor_string.length;
+ if (0 == (obj->vendor_string.entry = 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';
+
+ /* 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 > 100000) {
+ /* Possibly malicious file. */
+ obj->num_comments = 0;
+ return false;
+ }
+ if (obj->num_comments > 0) {
+ if (0 == (obj->comments = safe_malloc_mul_2op_p(obj->num_comments, /*times*/sizeof(FLAC__StreamMetadata_VorbisComment_Entry)))) {
+ obj->num_comments = 0;
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ for (i = 0; i < obj->num_comments; i++) {
+ /* Initialize here just to make sure. */
+ obj->comments[i].length = 0;
+ obj->comments[i].entry = 0;
+
+ FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN == 32);
+ if (length < 4) {
+ obj->num_comments = i;
+ goto skip;
+ }
+ else
+ length -= 4;
+ if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->comments[i].length)) {
+ obj->num_comments = i;
+ return false; /* read_callback_ sets the state for us */
+ }
+ if (length < obj->comments[i].length) {
+ obj->num_comments = i;
+ FLAC__bitreader_limit_invalidate(decoder->private_->input);
+ return false;
+ }
+ else
+ length -= obj->comments[i].length;
+ if (0 == (obj->comments[i].entry = safe_malloc_add_2op_(obj->comments[i].length, /*+*/1))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ obj->num_comments = i;
+ return false;
+ }
+ memset (obj->comments[i].entry, 0, obj->comments[i].length) ;
+ if (!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->comments[i].entry, obj->comments[i].length)) {
+ /* Current i-th entry is bad, so we delete it. */
+ free (obj->comments[i].entry) ;
+ obj->comments[i].entry = NULL ;
+ obj->num_comments = i;
+ goto skip;
+ }
+ obj->comments[i].entry[obj->comments[i].length] = '\0';
+ }
+ }
+ }
+ else {
+ FLAC__bitreader_limit_invalidate(decoder->private_->input);
+ return false;
+ }
+
+ skip:
+ if (length > 0) {
+ /* length > 0 can only happen on files with invalid data in comments */
+ if(obj->num_comments < 1) {
+ free(obj->comments);
+ obj->comments = NULL;
+ }
+ FLAC__bitreader_limit_invalidate(decoder->private_->input);
+ return false;
+ }
+
+ 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 = 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 = 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 *indx = &track->indices[j];
+ if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &indx->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 */
+ indx->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 */
+ }
+ }
+ }
+ }
+ else { /* obj->num_tracks == 0 */
+ FLAC__bitreader_limit_invalidate(decoder->private_->input);
+ return false;
+ }
+
+ 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 */
+ if(x < FLAC__STREAM_METADATA_PICTURE_TYPE_UNDEFINED)
+ obj->type = x;
+ else
+ obj->type = FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER;
+
+ /* 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(FLAC__bitreader_limit_remaining(decoder->private_->input) < x){
+ FLAC__bitreader_limit_invalidate(decoder->private_->input);
+ return false;
+ }
+ if(0 == (obj->mime_type = 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(FLAC__bitreader_limit_remaining(decoder->private_->input) < x){
+ FLAC__bitreader_limit_invalidate(decoder->private_->input);
+ return false;
+ }
+ if(0 == (obj->description = 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(FLAC__bitreader_limit_remaining(decoder->private_->input) < obj->data_length){
+ FLAC__bitreader_limit_invalidate(decoder->private_->input);
+ return false;
+ }
+ if(0 == (obj->data = 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;
+ uint32_t 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;
+
+ /* 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 >> 1 == 0x7c) { /* MAGIC NUMBER for the last 6 sync bits and reserved 7th bit */
+ decoder->private_->header_warmup[1] = (FLAC__byte)x;
+ decoder->protected_->state = FLAC__STREAM_DECODER_READ_FRAME;
+
+ /* Save location so we can rewind in case the frame turns
+ * out to be invalid after the header */
+ FLAC__bitreader_set_framesync_location(decoder->private_->input);
+ if(!FLAC__stream_decoder_get_decode_position(decoder, &decoder->private_->last_seen_framesync))
+ decoder->private_->last_seen_framesync = 0;
+ 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)
+{
+ uint32_t channel;
+ uint32_t i;
+ uint32_t frame_crc; /* the one we calculate from the input stream */
+ FLAC__uint32 x;
+
+ *got_a_frame = false;
+ decoder->private_->side_subframe_in_use = 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, decoder->private_->frame.header.bits_per_sample))
+ return false;
+ for(channel = 0; channel < decoder->private_->frame.header.channels; channel++) {
+ /*
+ * first figure the correct bits-per-sample of the subframe
+ */
+ uint32_t 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)){
+ /* read_callback_ sets the state for us */
+ if(decoder->protected_->state == FLAC__STREAM_DECODER_END_OF_STREAM)
+ break;
+ else
+ return false;
+ }
+ if(decoder->protected_->state != FLAC__STREAM_DECODER_READ_FRAME)
+ break;
+ }
+
+ if(decoder->protected_->state != FLAC__STREAM_DECODER_END_OF_STREAM)
+ if(!read_zero_padding_(decoder))
+ return false;
+
+ /*
+ * Read the frame CRC-16 from the footer and check
+ */
+ if(decoder->protected_->state == FLAC__STREAM_DECODER_READ_FRAME) {
+ 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)) {
+ /* read_callback_ sets the state for us */
+ if(decoder->protected_->state != FLAC__STREAM_DECODER_END_OF_STREAM)
+ return false;
+ }
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ }
+ if(decoder->protected_->state == FLAC__STREAM_DECODER_READ_FRAME && frame_crc == x) {
+#endif
+ if(do_full_decode) {
+ /* Undo any special channel coding */
+ undo_channel_coding(decoder);
+ /* Check whether decoded data actually fits bps */
+ for(channel = 0; channel < decoder->private_->frame.header.channels; channel++) {
+ for(i = 0; i < decoder->private_->frame.header.blocksize; i++) {
+ int shift_bits = 32 - decoder->private_->frame.header.bits_per_sample;
+ /* Check whether shift_bits MSBs are 'empty' by shifting up and down */
+ if((decoder->private_->output[channel][i] < (INT32_MIN >> shift_bits)) ||
+ (decoder->private_->output[channel][i] > (INT32_MAX >> shift_bits))) {
+ /* Bad frame, emit error */
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ break;
+ }
+ }
+ }
+ }
+ }
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ else if (decoder->protected_->state == FLAC__STREAM_DECODER_READ_FRAME) {
+ /* Bad frame, emit error */
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ }
+#endif
+
+ /* Check whether frames are missing, if so, add silence to compensate */
+ if(decoder->private_->last_frame_is_set && decoder->protected_->state == FLAC__STREAM_DECODER_READ_FRAME && !decoder->private_->is_seeking && do_full_decode) {
+ FLAC__ASSERT(decoder->private_->frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
+ FLAC__ASSERT(decoder->private_->last_frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
+ if(decoder->private_->last_frame.header.number.sample_number + decoder->private_->last_frame.header.blocksize < decoder->private_->frame.header.number.sample_number) {
+ uint32_t padding_samples_needed = decoder->private_->frame.header.number.sample_number - (decoder->private_->last_frame.header.number.sample_number + decoder->private_->last_frame.header.blocksize);
+
+ /* Do some extra validation to assure last frame an current frame
+ * header are both valid before adding silence inbetween
+ * Technically both frames could be valid with differing sample_rates,
+ * channels and bits_per_sample, but it is quite rare */
+ if(decoder->private_->last_frame.header.sample_rate == decoder->private_->frame.header.sample_rate &&
+ decoder->private_->last_frame.header.channels == decoder->private_->frame.header.channels &&
+ decoder->private_->last_frame.header.bits_per_sample == decoder->private_->frame.header.bits_per_sample &&
+ decoder->private_->last_frame.header.blocksize >= 16) {
+ FLAC__Frame empty_frame;
+ FLAC__int32 * empty_buffer[FLAC__MAX_CHANNELS] = {NULL};
+ empty_frame.header = decoder->private_->last_frame.header;
+ empty_frame.footer.crc = 0;
+ for(i = 0; i < empty_frame.header.channels; i++) {
+ empty_buffer[i] = safe_calloc_(empty_frame.header.blocksize, sizeof(FLAC__int32));
+ if(empty_buffer[i] == NULL) {
+ for(i = 0; i < empty_frame.header.channels; i++)
+ if(empty_buffer[i] != NULL)
+ free(empty_buffer[i]);
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ }
+ /* No repairs larger than 5 seconds or 50 frames are made, to not
+ * unexpectedly create enormous files when one of the headers was
+ * corrupt after all */
+ if(padding_samples_needed > (5*empty_frame.header.sample_rate))
+ padding_samples_needed = 5*empty_frame.header.sample_rate;
+ if(padding_samples_needed > (50*empty_frame.header.blocksize))
+ padding_samples_needed = 50*empty_frame.header.blocksize;
+ while(padding_samples_needed){
+ empty_frame.header.number.sample_number += empty_frame.header.blocksize;
+ if(padding_samples_needed < empty_frame.header.blocksize)
+ empty_frame.header.blocksize = padding_samples_needed;
+ padding_samples_needed -= empty_frame.header.blocksize;
+ decoder->protected_->blocksize = empty_frame.header.blocksize;
+
+ FLAC__ASSERT(empty_frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
+ decoder->private_->samples_decoded = empty_frame.header.number.sample_number + empty_frame.header.blocksize;
+
+ for(channel = 0; channel < empty_frame.header.channels; channel++) {
+ empty_frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_CONSTANT;
+ empty_frame.subframes[channel].data.constant.value = 0;
+ empty_frame.subframes[channel].wasted_bits = 0;
+ }
+
+ if(write_audio_frame_to_client_(decoder, &empty_frame, (const FLAC__int32 * const *)empty_buffer) != FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED;
+ for(i = 0; i < empty_frame.header.channels; i++)
+ if(empty_buffer[i] != NULL)
+ free(empty_buffer[i]);
+ return false;
+ }
+ }
+ for(i = 0; i < empty_frame.header.channels; i++)
+ if(empty_buffer[i] != NULL)
+ free(empty_buffer[i]);
+
+ }
+ }
+ }
+
+ if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC || decoder->protected_->state == FLAC__STREAM_DECODER_END_OF_STREAM) {
+ /* Got corruption, rewind if possible. Return value of seek
+ * isn't checked, if the seek fails the decoder will continue anyway */
+ if(!FLAC__bitreader_rewind_to_after_last_seen_framesync(decoder->private_->input)){
+#ifndef NDEBUG
+ fprintf(stderr, "Rewinding, seeking necessary\n");
+#endif
+ if(decoder->private_->seek_callback && decoder->private_->last_seen_framesync){
+ /* Last framesync isn't in bitreader anymore, rewind with seek if possible */
+#ifndef NDEBUG
+ FLAC__uint64 current_decode_position;
+ if(FLAC__stream_decoder_get_decode_position(decoder, &current_decode_position))
+ fprintf(stderr, "Bitreader was %" PRIu64 " bytes short\n", current_decode_position-decoder->private_->last_seen_framesync);
+#endif
+ if(decoder->private_->seek_callback(decoder, decoder->private_->last_seen_framesync, decoder->private_->client_data) == FLAC__STREAM_DECODER_SEEK_STATUS_ERROR) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+ return false;
+ }
+ if(!FLAC__bitreader_clear(decoder->private_->input)) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ }
+ }
+#ifndef NDEBUG
+ else{
+ fprintf(stderr, "Rewinding, seeking not necessary\n");
+ }
+#endif
+ }
+ else {
+ *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) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED;
+ 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;
+ uint32_t 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 */
+ uint32_t 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 = (uint32_t)(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 = (uint32_t)x + 1;
+ decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT;
+ }
+
+ switch(x = (uint32_t)(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 3:
+ is_unparseable = true;
+ 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 7:
+ decoder->private_->frame.header.bits_per_sample = 32;
+ break;
+ default:
+ FLAC__ASSERT(0);
+ break;
+ }
+
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ /* check to make sure that reserved bit is 0 */
+ if(raw_header[3] & 0x01) /* MAGIC NUMBER */
+ is_unparseable = true;
+#endif
+
+ /* 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(decoder->private_->frame.header.blocksize > 65535) { /* invalid blocksize (65536) specified */
+ 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;
+ }
+
+ }
+
+ 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;
+
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ 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;
+ }
+#endif
+
+ /* 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, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode)
+{
+ FLAC__uint32 x;
+ FLAC__bool wasted_bits;
+ uint32_t 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) {
+ uint32_t 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;
+ if (decoder->private_->frame.subframes[channel].wasted_bits >= bps) {
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+ 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) {
+ uint32_t predictor_order = (x>>1)&7;
+ 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;
+ }
+ if(!read_subframe_fixed_(decoder, channel, bps, predictor_order, 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 {
+ uint32_t predictor_order = ((x>>1)&31)+1;
+ 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;
+ }
+ if(!read_subframe_lpc_(decoder, channel, bps, predictor_order, 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;
+ if((bps + x) < 33) {
+ for(i = 0; i < decoder->private_->frame.header.blocksize; i++) {
+ uint32_t val = decoder->private_->output[channel][i];
+ decoder->private_->output[channel][i] = (val << x);
+ }
+ }
+ else {
+ /* When there are wasted bits, bps is never 33 and so
+ * side_subframe is never already in use */
+ FLAC__ASSERT(!decoder->private_->side_subframe_in_use);
+ decoder->private_->side_subframe_in_use = true;
+ for(i = 0; i < decoder->private_->frame.header.blocksize; i++) {
+ uint64_t val = decoder->private_->output[channel][i];
+ decoder->private_->side_subframe[i] = (val << x);
+ }
+ }
+ }
+
+ return true;
+}
+
+FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode)
+{
+ FLAC__Subframe_Constant *subframe = &decoder->private_->frame.subframes[channel].data.constant;
+ FLAC__int64 x;
+ uint32_t i;
+
+ decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_CONSTANT;
+
+ if(!FLAC__bitreader_read_raw_int64(decoder->private_->input, &x, bps))
+ return false; /* read_callback_ sets the state for us */
+
+ subframe->value = x;
+
+ /* decode the subframe */
+ if(do_full_decode) {
+ if(bps <= 32) {
+ FLAC__int32 *output = decoder->private_->output[channel];
+ for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
+ output[i] = x;
+ } else {
+ FLAC__int64 *output = decoder->private_->side_subframe;
+ decoder->private_->side_subframe_in_use = true;
+ for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
+ output[i] = x;
+ }
+ }
+
+ return true;
+}
+
+FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, const uint32_t order, FLAC__bool do_full_decode)
+{
+ FLAC__Subframe_Fixed *subframe = &decoder->private_->frame.subframes[channel].data.fixed;
+ FLAC__int64 i64;
+ FLAC__uint32 u32;
+ uint32_t 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_int64(decoder->private_->input, &i64, bps))
+ return false; /* read_callback_ sets the state for us */
+ subframe->warmup[u] = i64;
+ }
+
+ /* 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 */
+ if((decoder->private_->frame.header.blocksize >> u32 < order) ||
+ (decoder->private_->frame.header.blocksize % (1 << u32) > 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;
+ }
+ 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) {
+ if(bps < 33){
+ uint32_t i;
+ for(i = 0; i < order; i++)
+ decoder->private_->output[channel][i] = subframe->warmup[i];
+ if(bps+order <= 32)
+ FLAC__fixed_restore_signal(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, order, decoder->private_->output[channel]+order);
+ else
+ FLAC__fixed_restore_signal_wide(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, order, decoder->private_->output[channel]+order);
+ }
+ else {
+ decoder->private_->side_subframe_in_use = true;
+ memcpy(decoder->private_->side_subframe, subframe->warmup, sizeof(FLAC__int64) * order);
+ FLAC__fixed_restore_signal_wide_33bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, order, decoder->private_->side_subframe+order);
+ }
+ }
+
+ return true;
+}
+
+FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, const uint32_t order, FLAC__bool do_full_decode)
+{
+ FLAC__Subframe_LPC *subframe = &decoder->private_->frame.subframes[channel].data.lpc;
+ FLAC__int32 i32;
+ FLAC__int64 i64;
+ FLAC__uint32 u32;
+ uint32_t 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_int64(decoder->private_->input, &i64, bps))
+ return false; /* read_callback_ sets the state for us */
+ subframe->warmup[u] = i64;
+ }
+
+ /* 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 */
+ if(i32 < 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;
+ }
+ 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 */
+ if((decoder->private_->frame.header.blocksize >> u32 < order) ||
+ (decoder->private_->frame.header.blocksize % (1 << u32) > 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;
+ }
+ 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) {
+ if(bps <= 32) {
+ uint32_t i;
+ for(i = 0; i < order; i++)
+ decoder->private_->output[channel][i] = subframe->warmup[i];
+ if(FLAC__lpc_max_residual_bps(bps, subframe->qlp_coeff, order, subframe->quantization_level) <= 32 &&
+ FLAC__lpc_max_prediction_before_shift_bps(bps, subframe->qlp_coeff, order) <= 32)
+ FLAC__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
+ FLAC__lpc_restore_signal_wide(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_->side_subframe_in_use = true;
+ memcpy(decoder->private_->side_subframe, subframe->warmup, sizeof(FLAC__int64) * order);
+ FLAC__lpc_restore_signal_wide_33bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->side_subframe+order);
+ }
+ }
+
+ return true;
+}
+
+FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode)
+{
+ FLAC__Subframe_Verbatim *subframe = &decoder->private_->frame.subframes[channel].data.verbatim;
+ uint32_t i;
+
+ decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_VERBATIM;
+
+ if(bps < 33) {
+ FLAC__int32 x, *residual = decoder->private_->residual[channel];
+
+ subframe->data_type = FLAC__VERBATIM_SUBFRAME_DATA_TYPE_INT32;
+ subframe->data.int32 = 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.int32, sizeof(FLAC__int32) * decoder->private_->frame.header.blocksize);
+ }
+ else {
+ FLAC__int64 x, *side = decoder->private_->side_subframe;
+
+ subframe->data_type = FLAC__VERBATIM_SUBFRAME_DATA_TYPE_INT64;
+ subframe->data.int64 = side;
+ decoder->private_->side_subframe_in_use = true;
+
+ for(i = 0; i < decoder->private_->frame.header.blocksize; i++) {
+ if(!FLAC__bitreader_read_raw_int64(decoder->private_->input, &x, bps))
+ return false; /* read_callback_ sets the state for us */
+ side[i] = x;
+ }
+ }
+
+ return true;
+}
+
+FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, uint32_t predictor_order, uint32_t partition_order, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, FLAC__int32 *residual, FLAC__bool is_extended)
+{
+ FLAC__uint32 rice_parameter;
+ int i;
+ uint32_t partition, sample, u;
+ const uint32_t partitions = 1u << partition_order;
+ const uint32_t partition_samples = decoder->private_->frame.header.blocksize >> partition_order;
+ const uint32_t plen = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN;
+ const uint32_t pesc = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
+
+ /* invalid predictor and partition orders mush be handled in the callers */
+ FLAC__ASSERT(partition_order > 0? partition_samples >= predictor_order : decoder->private_->frame.header.blocksize >= predictor_order);
+
+ if(!FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(partitioned_rice_contents, flac_max(6u, 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 == 0) ? partition_samples - predictor_order : partition_samples;
+ if(!decoder->private_->local_bitreader_read_rice_signed_block(decoder->private_->input, residual + sample, u, rice_parameter)){
+ if(decoder->protected_->state == FLAC__STREAM_DECODER_READ_FRAME) {
+ /* no error was set, read_callback_ didn't set it, so
+ * invalid rice symbol was found */
+ 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
+ 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;
+ if(rice_parameter == 0) {
+ for(u = (partition == 0)? predictor_order : 0; u < partition_samples; u++, sample++)
+ residual[sample] = 0;
+ }
+ else{
+ for(u = (partition == 0)? predictor_order : 0; 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 */
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ 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;
+ }
+#endif
+ }
+ 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 defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && !defined(FUZZING_BUILD_MODE_FLAC_SANITIZE_SIGNED_INTEGER_OVERFLOW)
+/* The attribute below is to silence the undefined sanitizer of oss-fuzz.
+ * Because fuzzing feeds bogus predictors and residual samples to the
+ * decoder, having overflows in this section is unavoidable. Also,
+ * because the calculated values are audio path only, there is no
+ * potential for security problems */
+__attribute__((no_sanitize("signed-integer-overflow")))
+#endif
+void undo_channel_coding(FLAC__StreamDecoder *decoder) {
+ uint32_t i;
+ 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);
+ FLAC__ASSERT(decoder->private_->side_subframe_in_use != /* logical XOR */ (decoder->private_->frame.header.bits_per_sample < 32));
+ for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
+ if(decoder->private_->side_subframe_in_use)
+ decoder->private_->output[1][i] = decoder->private_->output[0][i] - decoder->private_->side_subframe[i];
+ else
+ 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);
+ FLAC__ASSERT(decoder->private_->side_subframe_in_use != /* logical XOR */ (decoder->private_->frame.header.bits_per_sample < 32));
+ for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
+ if(decoder->private_->side_subframe_in_use)
+ decoder->private_->output[0][i] = decoder->private_->output[1][i] + decoder->private_->side_subframe[i];
+ else
+ 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);
+ FLAC__ASSERT(decoder->private_->side_subframe_in_use != /* logical XOR */ (decoder->private_->frame.header.bits_per_sample < 32));
+ for(i = 0; i < decoder->private_->frame.header.blocksize; i++) {
+ if(!decoder->private_->side_subframe_in_use){
+ FLAC__int32 mid, side;
+ mid = decoder->private_->output[0][i];
+ side = decoder->private_->output[1][i];
+ mid = ((uint32_t) 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 { /* bps == 32 */
+ FLAC__int64 mid;
+ mid = ((uint64_t)decoder->private_->output[0][i]) << 1;
+ mid |= (decoder->private_->side_subframe[i] & 1); /* i.e. if 'side' is odd... */
+ decoder->private_->output[0][i] = (mid + decoder->private_->side_subframe[i]) >> 1;
+ decoder->private_->output[1][i] = (mid - decoder->private_->side_subframe[i]) >> 1;
+ }
+ }
+ break;
+ default:
+ FLAC__ASSERT(0);
+ break;
+ }
+}
+
+#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[])
+{
+ decoder->private_->last_frame = *frame; /* save the frame */
+ decoder->private_->last_frame_is_set = true;
+ 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
+ if(this_frame_sample <= target_sample && target_sample < next_frame_sample) { /* we hit our target frame */
+ uint32_t delta = (uint32_t)(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) {
+ uint32_t 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.subframes[channel].type = FLAC__SUBFRAME_TYPE_VERBATIM;
+ decoder->private_->last_frame.subframes[channel].data.verbatim.data_type = FLAC__VERBATIM_SUBFRAME_DATA_TYPE_INT32;
+ decoder->private_->last_frame.subframes[channel].data.verbatim.data.int32 = newbuffer[channel];
+ }
+ 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;
+ uint32_t approx_bytes_per_frame;
+ FLAC__bool first_seek = true, seek_from_lower_bound = false;
+ const FLAC__uint64 total_samples = FLAC__stream_decoder_get_total_samples(decoder);
+ const uint32_t min_blocksize = decoder->private_->stream_info.data.stream_info.min_blocksize;
+ const uint32_t max_blocksize = decoder->private_->stream_info.data.stream_info.max_blocksize;
+ const uint32_t max_framesize = decoder->private_->stream_info.data.stream_info.max_framesize;
+ const uint32_t min_framesize = decoder->private_->stream_info.data.stream_info.min_framesize;
+ /* take these from the current frame in case they've changed mid-stream */
+ uint32_t channels = FLAC__stream_decoder_get_channels(decoder);
+ uint32_t 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 calculation */
+ 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 take the current position
+ * as one bound and, depending on where the target position lies,
+ * the beginning of the first frame or the end of the stream as
+ * the other bound.
+ */
+ 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*/;
+
+ if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC &&
+ decoder->private_->samples_decoded != 0) {
+ if(target_sample < decoder->private_->samples_decoded) {
+ if(FLAC__stream_decoder_get_decode_position(decoder, &upper_bound))
+ upper_bound_sample = decoder->private_->samples_decoded;
+ } else {
+ if(FLAC__stream_decoder_get_decode_position(decoder, &lower_bound))
+ lower_bound_sample = decoder->private_->samples_decoded;
+ }
+ }
+
+ /*
+ * 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. Also,
+ * because math is limited to 64-bit ints, seekpoints with an offset
+ * larger than 2^63 (8 exbibyte) are rejected.
+ */
+ 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 whether decoder is still valid so bad state isn't overwritten
+ * with seek error */
+ if(decoder->protected_->state == FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR ||
+ decoder->protected_->state == FLAC__STREAM_DECODER_ABORTED)
+ return false;
+ /* check if the bounds are still ok */
+ if (lower_bound_sample >= upper_bound_sample ||
+ lower_bound > upper_bound ||
+ upper_bound >= INT64_MAX) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+ return false;
+ }
+ if(seek_from_lower_bound) {
+ pos = lower_bound;
+ }
+ else {
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+ pos = (FLAC__int64)lower_bound + (FLAC__int64)((double)(target_sample - lower_bound_sample) / (double)(upper_bound_sample - lower_bound_sample) * (double)(upper_bound - lower_bound)) - approx_bytes_per_frame;
+#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 */
+ FLAC__uint64 ratio = (1<<16) / (upper_bound_sample - lower_bound_sample);
+ pos = (FLAC__int64)lower_bound + (FLAC__int64)((((target_sample - lower_bound_sample)>>8) * ((upper_bound - lower_bound)>>8) * ratio)) - 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_ABORTED || 0 == decoder->private_->samples_decoded) {
+ /* No frame could be decoded */
+ if(decoder->protected_->state != FLAC__STREAM_DECODER_ABORTED && decoder->private_->eof_callback(decoder, decoder->private_->client_data) && !seek_from_lower_bound){
+ /* decoder has hit end of stream while processing corrupt
+ * frame. To remedy this, try decoding a frame at the lower
+ * bound so the seek after that hopefully ends up somewhere
+ * else */
+ seek_from_lower_bound = true;
+ continue;
+ }
+ else {
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+ return false;
+ }
+ }
+ seek_from_lower_bound = 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(!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(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 = (uint32_t)(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 = (uint32_t)(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;
+ uint32_t 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.
+ */
+ uint32_t 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++) {
+ /* Do sanity checks on bounds */
+ if(right_pos <= left_pos || right_pos - left_pos < 9) {
+ /* FLAC frame is at least 9 byte in size */
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+ return false;
+ }
+ 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
+ pos = (FLAC__uint64)((double)(target_sample - left_sample) / (double)(right_sample - left_sample) * (double)(right_pos - left_pos));
+#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_ABORTED) {
+ 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 {
+ 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, (FLAC__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)
+{
+ FLAC__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 flac_stat_s filestats;
+ (void)client_data;
+
+ if(decoder->private_->file == stdin)
+ return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED;
+
+#ifndef FLAC__USE_FILELENGTHI64
+ if(flac_fstat(fileno(decoder->private_->file), &filestats) != 0)
+#else
+ filestats.st_size = _filelengthi64(fileno(decoder->private_->file));
+ if(filestats.st_size < 0)
+#endif
+ 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
index 0000000..c1c03e4
--- /dev/null
+++ b/src/libFLAC/stream_encoder.c
@@ -0,0 +1,4738 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcpy() */
+#include <sys/types.h> /* for off_t */
+#ifdef _WIN32
+#include <windows.h> /* for GetFileType() */
+#include <io.h> /* for _get_osfhandle() */
+#endif
+#include "share/compat.h"
+#include "FLAC/assert.h"
+#include "FLAC/stream_decoder.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"
+#include "private/macros.h"
+#if FLAC__HAS_OGG
+#include "private/ogg_helper.h"
+#include "private/ogg_mapping.h"
+#endif
+#include "private/stream_encoder.h"
+#include "private/stream_encoder_framing.h"
+#include "private/window.h"
+#include "share/alloc.h"
+#include "share/private.h"
+
+
+/* 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];
+ uint32_t size; /* of each data[] in samples */
+ uint32_t tail;
+} verify_input_fifo;
+
+typedef struct {
+ const FLAC__byte *data;
+ uint32_t capacity;
+ uint32_t bytes;
+} verify_output;
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+typedef struct {
+ uint32_t a, b, c;
+ FLAC__ApodizationSpecification * current_apodization;
+ double autoc_root[FLAC__MAX_LPC_ORDER+1];
+ double autoc[FLAC__MAX_LPC_ORDER+1];
+} apply_apodization_state_struct;
+#endif
+
+typedef enum {
+ ENCODER_IN_MAGIC = 0,
+ ENCODER_IN_METADATA = 1,
+ ENCODER_IN_AUDIO = 2
+} EncoderStateHint;
+
+static const struct CompressionLevels {
+ FLAC__bool do_mid_side_stereo;
+ FLAC__bool loose_mid_side_stereo;
+ uint32_t max_lpc_order;
+ uint32_t qlp_coeff_precision;
+ FLAC__bool do_qlp_coeff_prec_search;
+ FLAC__bool do_escape_coding;
+ FLAC__bool do_exhaustive_model_search;
+ uint32_t min_residual_partition_order;
+ uint32_t max_residual_partition_order;
+ uint32_t rice_parameter_search_dist;
+ const char *apodization;
+} compression_levels_[] = {
+ { false, false, 0, 0, false, false, false, 0, 3, 0, "tukey(5e-1)" },
+ { true , true , 0, 0, false, false, false, 0, 3, 0, "tukey(5e-1)" },
+ { true , false, 0, 0, false, false, false, 0, 3, 0, "tukey(5e-1)" },
+ { false, false, 6, 0, false, false, false, 0, 4, 0, "tukey(5e-1)" },
+ { true , true , 8, 0, false, false, false, 0, 4, 0, "tukey(5e-1)" },
+ { true , false, 8, 0, false, false, false, 0, 5, 0, "tukey(5e-1)" },
+ { true , false, 8, 0, false, false, false, 0, 6, 0, "subdivide_tukey(2)" },
+ { true , false, 12, 0, false, false, false, 0, 6, 0, "subdivide_tukey(2)" },
+ { true , false, 12, 0, false, false, false, 0, 6, 0, "subdivide_tukey(3)" }
+ /* here we use locale-independent 5e-1 instead of 0.5 or 0,5 */
+};
+
+
+/***********************************************************************
+ *
+ * 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, uint32_t new_blocksize);
+static FLAC__bool write_bitbuffer_(FLAC__StreamEncoder *encoder, uint32_t samples, FLAC__bool is_last_block);
+static FLAC__StreamEncoderWriteStatus write_frame_(FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t 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_last_block);
+static FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder);
+
+static FLAC__bool process_subframe_(
+ FLAC__StreamEncoder *encoder,
+ uint32_t min_partition_order,
+ uint32_t max_partition_order,
+ const FLAC__FrameHeader *frame_header,
+ uint32_t subframe_bps,
+ const void *integer_signal,
+ FLAC__Subframe *subframe[2],
+ FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents[2],
+ FLAC__int32 *residual[2],
+ uint32_t *best_subframe,
+ uint32_t *best_bits
+);
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+static FLAC__bool apply_apodization_(
+ FLAC__StreamEncoder *encoder,
+ apply_apodization_state_struct *apply_apodization_state,
+ uint32_t blocksize,
+ double *lpc_error,
+ uint32_t *max_lpc_order_this_apodization,
+ uint32_t subframe_bps,
+ const void *integer_signal,
+ uint32_t *guess_lpc_order
+);
+#endif
+
+static FLAC__bool add_subframe_(
+ FLAC__StreamEncoder *encoder,
+ uint32_t blocksize,
+ uint32_t subframe_bps,
+ const FLAC__Subframe *subframe,
+ FLAC__BitWriter *frame
+);
+
+static uint32_t evaluate_constant_subframe_(
+ FLAC__StreamEncoder *encoder,
+ const FLAC__int64 signal,
+ uint32_t blocksize,
+ uint32_t subframe_bps,
+ FLAC__Subframe *subframe
+);
+
+static uint32_t evaluate_fixed_subframe_(
+ FLAC__StreamEncoder *encoder,
+ const void *signal,
+ FLAC__int32 residual[],
+ FLAC__uint64 abs_residual_partition_sums[],
+ uint32_t raw_bits_per_partition[],
+ uint32_t blocksize,
+ uint32_t subframe_bps,
+ uint32_t order,
+ uint32_t rice_parameter_limit,
+ uint32_t min_partition_order,
+ uint32_t max_partition_order,
+ FLAC__bool do_escape_coding,
+ uint32_t rice_parameter_search_dist,
+ FLAC__Subframe *subframe,
+ FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents
+);
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+static uint32_t evaluate_lpc_subframe_(
+ FLAC__StreamEncoder *encoder,
+ const void *signal,
+ FLAC__int32 residual[],
+ FLAC__uint64 abs_residual_partition_sums[],
+ uint32_t raw_bits_per_partition[],
+ const FLAC__real lp_coeff[],
+ uint32_t blocksize,
+ uint32_t subframe_bps,
+ uint32_t order,
+ uint32_t qlp_coeff_precision,
+ uint32_t rice_parameter_limit,
+ uint32_t min_partition_order,
+ uint32_t max_partition_order,
+ FLAC__bool do_escape_coding,
+ uint32_t rice_parameter_search_dist,
+ FLAC__Subframe *subframe,
+ FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents
+);
+#endif
+
+static uint32_t evaluate_verbatim_subframe_(
+ FLAC__StreamEncoder *encoder,
+ const void *signal,
+ uint32_t blocksize,
+ uint32_t subframe_bps,
+ FLAC__Subframe *subframe
+);
+
+static uint32_t find_best_partition_order_(
+ struct FLAC__StreamEncoderPrivate *private_,
+ const FLAC__int32 residual[],
+ FLAC__uint64 abs_residual_partition_sums[],
+ uint32_t raw_bits_per_partition[],
+ uint32_t residual_samples,
+ uint32_t predictor_order,
+ uint32_t rice_parameter_limit,
+ uint32_t min_partition_order,
+ uint32_t max_partition_order,
+ uint32_t bps,
+ FLAC__bool do_escape_coding,
+ uint32_t rice_parameter_search_dist,
+ FLAC__EntropyCodingMethod *best_ecm
+);
+
+static void precompute_partition_info_sums_(
+ const FLAC__int32 residual[],
+ FLAC__uint64 abs_residual_partition_sums[],
+ uint32_t residual_samples,
+ uint32_t predictor_order,
+ uint32_t min_partition_order,
+ uint32_t max_partition_order,
+ uint32_t bps
+);
+
+static void precompute_partition_info_escapes_(
+ const FLAC__int32 residual[],
+ uint32_t raw_bits_per_partition[],
+ uint32_t residual_samples,
+ uint32_t predictor_order,
+ uint32_t min_partition_order,
+ uint32_t 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 uint32_t raw_bits_per_partition[],
+ const uint32_t residual_samples,
+ const uint32_t predictor_order,
+ const uint32_t rice_parameter_limit,
+ const uint32_t rice_parameter_search_dist,
+ const uint32_t partition_order,
+ const FLAC__bool search_for_escapes,
+ FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents,
+ uint32_t *bits
+);
+
+static uint32_t get_wasted_bits_(FLAC__int32 signal[], uint32_t samples);
+static uint32_t get_wasted_bits_wide_(FLAC__int64 signal_wide[], FLAC__int32 signal[], uint32_t samples);
+
+/* verify-related routines: */
+static void append_to_verify_fifo_(
+ verify_input_fifo *fifo,
+ const FLAC__int32 * const input[],
+ uint32_t input_offset,
+ uint32_t channels,
+ uint32_t wide_samples
+);
+
+static void append_to_verify_fifo_interleaved_(
+ verify_input_fifo *fifo,
+ const FLAC__int32 input[],
+ uint32_t input_offset,
+ uint32_t channels,
+ uint32_t 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, uint32_t samples, uint32_t current_frame, void *client_data);
+static FILE *get_binary_stdout_(void);
+
+
+/***********************************************************************
+ *
+ * Private class data
+ *
+ ***********************************************************************/
+
+typedef struct FLAC__StreamEncoderPrivate {
+ uint32_t 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) */
+ FLAC__int64 *integer_signal_33bit_side; /* 33-bit side for 32-bit stereo decorrelation */
+#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
+ uint32_t subframe_bps[FLAC__MAX_CHANNELS]; /* the effective bits per sample of the input signal (stream bps - wasted bits) */
+ uint32_t 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];
+ uint32_t best_subframe[FLAC__MAX_CHANNELS]; /* index (0 or 1) into 2nd dimension of the above workspaces */
+ uint32_t best_subframe_mid_side[2];
+ uint32_t best_subframe_bits[FLAC__MAX_CHANNELS]; /* size in bits of the best subframe for each channel */
+ uint32_t 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 */
+ uint32_t *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 */
+ uint32_t loose_mid_side_stereo_frames; /* rounded number of frames the encoder will use before trying both independent and mid/side frames again */
+ uint32_t 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 */
+ uint32_t current_sample_number;
+ uint32_t current_frame_number;
+ FLAC__MD5Context md5context;
+ FLAC__CPUInfo cpuinfo;
+ void (*local_precompute_partition_info_sums)(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[], uint32_t residual_samples, uint32_t predictor_order, uint32_t min_partition_order, uint32_t max_partition_order, uint32_t bps);
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+ uint32_t (*local_fixed_compute_best_predictor)(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+ uint32_t (*local_fixed_compute_best_predictor_wide)(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+ uint32_t (*local_fixed_compute_best_predictor_limit_residual)(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+#else
+ uint32_t (*local_fixed_compute_best_predictor)(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+ uint32_t (*local_fixed_compute_best_predictor_wide)(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+ uint32_t (*local_fixed_compute_best_predictor_limit_residual)(const FLAC__int32 data[], uint32_t 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[], uint32_t data_len, uint32_t lag, double autoc[]);
+ void (*local_lpc_compute_residual_from_qlp_coefficients)(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+ void (*local_lpc_compute_residual_from_qlp_coefficients_64bit)(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+ void (*local_lpc_compute_residual_from_qlp_coefficients_16bit)(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+#endif
+ FLAC__bool disable_mmx;
+ FLAC__bool disable_sse2;
+ FLAC__bool disable_ssse3;
+ FLAC__bool disable_sse41;
+ FLAC__bool disable_sse42;
+ FLAC__bool disable_avx2;
+ FLAC__bool disable_fma;
+ FLAC__bool disable_constant_subframes;
+ FLAC__bool disable_fixed_subframes;
+ FLAC__bool disable_verbatim_subframes;
+ FLAC__bool is_ogg;
+ 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;
+ uint32_t first_seekpoint_to_check;
+ FILE *file; /* only used when encoding to a file */
+ FLAC__uint64 bytes_written;
+ FLAC__uint64 samples_written;
+ uint32_t frames_written;
+ uint32_t 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];
+ FLAC__int64 *integer_signal_33bit_side_unaligned;
+#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;
+ uint32_t *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;
+ uint32_t frame_number;
+ uint32_t channel;
+ uint32_t 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__StreamEncoderReadStatusString[] = {
+ "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 uint32_t OVERREAD_ = 1;
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ */
+FLAC_API FLAC__StreamEncoder *FLAC__stream_encoder_new(void)
+{
+ FLAC__StreamEncoder *encoder;
+ uint32_t i;
+
+ FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */
+
+ encoder = calloc(1, sizeof(FLAC__StreamEncoder));
+ if(encoder == 0) {
+ return 0;
+ }
+
+ encoder->protected_ = calloc(1, sizeof(FLAC__StreamEncoderProtected));
+ if(encoder->protected_ == 0) {
+ free(encoder);
+ return 0;
+ }
+
+ encoder->private_ = 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;
+
+ encoder->protected_->state = FLAC__STREAM_ENCODER_UNINITIALIZED;
+
+ 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]);
+
+ return encoder;
+}
+
+FLAC_API void FLAC__stream_encoder_delete(FLAC__StreamEncoder *encoder)
+{
+ uint32_t i;
+
+ if (encoder == NULL)
+ return ;
+
+ 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
+)
+{
+ uint32_t 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 == 0 && is_ogg)
+ return FLAC__STREAM_ENCODER_INIT_STATUS_UNSUPPORTED_CONTAINER;
+
+ 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 < FLAC__MIN_BITS_PER_SAMPLE || encoder->protected_->bits_per_sample > FLAC__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 = flac_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(!FLAC__format_blocksize_is_subset(encoder->protected_->blocksize, encoder->protected_->sample_rate))
+ 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 &&
+ encoder->protected_->bits_per_sample != 32
+ )
+ 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
+ /* drop any seektable for ogg */
+ if(is_ogg && 0 != encoder->protected_->metadata && encoder->protected_->num_metadata_blocks > 0) {
+ uint32_t i1;
+ for(i1 = 0; i1 < encoder->protected_->num_metadata_blocks; i1++) {
+ if(0 != encoder->protected_->metadata[i1] && encoder->protected_->metadata[i1]->type == FLAC__METADATA_TYPE_SEEKTABLE) {
+ encoder->protected_->num_metadata_blocks--;
+ for( ; i1 < encoder->protected_->num_metadata_blocks; i1++)
+ encoder->protected_->metadata[i1] = encoder->protected_->metadata[i1+1];
+ break;
+ }
+ }
+ }
+ /* 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) {
+ uint32_t i1;
+ for(i1 = 1; i1 < encoder->protected_->num_metadata_blocks; i1++) {
+ if(0 != encoder->protected_->metadata[i1] && encoder->protected_->metadata[i1]->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
+ FLAC__StreamMetadata *vc = encoder->protected_->metadata[i1];
+ for( ; i1 > 0; i1--)
+ encoder->protected_->metadata[i1] = encoder->protected_->metadata[i1-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) {
+ uint32_t i2;
+ for(i2 = 0; i2 < encoder->protected_->num_metadata_blocks; i2++) {
+ if(0 != encoder->protected_->metadata[i2] && encoder->protected_->metadata[i2]->type == FLAC__METADATA_TYPE_SEEKTABLE) {
+ encoder->private_->seek_table = &encoder->protected_->metadata[i2]->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
+ }
+ encoder->private_->integer_signal_33bit_side_unaligned = encoder->private_->integer_signal_33bit_side = 0;
+#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 = (uint32_t)((double)encoder->protected_->sample_rate * 0.4 / (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 1048575 Hz, and thus use 20 bits, so we do the multiply&divide by hand */
+ FLAC__ASSERT(FLAC__MAX_SAMPLE_RATE <= 1048575);
+ FLAC__ASSERT(FLAC__MAX_BLOCK_SIZE <= 65535);
+ FLAC__ASSERT(encoder->protected_->sample_rate <= 1048575);
+ FLAC__ASSERT(encoder->protected_->blocksize <= 65535);
+ encoder->private_->loose_mid_side_stereo_frames = (uint32_t)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;
+
+ /*
+ * get the CPU info and set the function pointers
+ */
+ FLAC__cpu_info(&encoder->private_->cpuinfo);
+ /* remove cpu info as requested by
+ * FLAC__stream_encoder_disable_instruction_set */
+ if(encoder->private_->disable_mmx)
+ encoder->private_->cpuinfo.x86.mmx = false;
+ if(encoder->private_->disable_sse2)
+ encoder->private_->cpuinfo.x86.sse2 = false;
+ if(encoder->private_->disable_ssse3)
+ encoder->private_->cpuinfo.x86.ssse3 = false;
+ if(encoder->private_->disable_sse41)
+ encoder->private_->cpuinfo.x86.sse41 = false;
+ if(encoder->private_->disable_sse42)
+ encoder->private_->cpuinfo.x86.sse42 = false;
+ if(encoder->private_->disable_avx2)
+ encoder->private_->cpuinfo.x86.avx2 = false;
+ if(encoder->private_->disable_fma)
+ encoder->private_->cpuinfo.x86.fma = false;
+ /* 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_precompute_partition_info_sums = precompute_partition_info_sums_;
+ encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor;
+ encoder->private_->local_fixed_compute_best_predictor_wide = FLAC__fixed_compute_best_predictor_wide;
+ encoder->private_->local_fixed_compute_best_predictor_limit_residual = FLAC__fixed_compute_best_predictor_limit_residual;
+#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 defined FLAC__CPU_ARM64 && FLAC__HAS_NEONINTRIN
+#if FLAC__HAS_A64NEONINTRIN
+ if(encoder->protected_->max_lpc_order < 8)
+ encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_neon_lag_8;
+ else if(encoder->protected_->max_lpc_order < 10)
+ encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_neon_lag_10;
+ else if(encoder->protected_->max_lpc_order < 14)
+ encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_neon_lag_14;
+ else
+ encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation;
+#endif
+ encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_neon;
+ encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_neon;
+ encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_neon;
+#endif /* defined FLAC__CPU_ARM64 && FLAC__HAS_NEONINTRIN */
+
+ if(encoder->private_->cpuinfo.use_asm) {
+# ifdef FLAC__CPU_IA32
+ FLAC__ASSERT(encoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_IA32);
+# if FLAC__HAS_X86INTRIN
+# ifdef FLAC__SSE2_SUPPORTED
+ if (encoder->private_->cpuinfo.x86.sse2) {
+ if(encoder->protected_->max_lpc_order < 8)
+ encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse2_lag_8;
+ else if(encoder->protected_->max_lpc_order < 10)
+ encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse2_lag_10;
+ else if(encoder->protected_->max_lpc_order < 14)
+ encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse2_lag_14;
+
+ encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse2;
+ encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_sse2;
+ }
+# endif
+# ifdef FLAC__SSE4_1_SUPPORTED
+ if (encoder->private_->cpuinfo.x86.sse41) {
+ encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse41;
+ encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_sse41;
+ }
+# endif
+# ifdef FLAC__AVX2_SUPPORTED
+ if (encoder->private_->cpuinfo.x86.avx2) {
+ encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_avx2;
+ encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_avx2;
+ encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_avx2;
+ }
+# endif
+
+# ifdef FLAC__SSE2_SUPPORTED
+ if (encoder->private_->cpuinfo.x86.sse2) {
+ encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_intrin_sse2;
+ }
+# endif
+# ifdef FLAC__SSSE3_SUPPORTED
+ if (encoder->private_->cpuinfo.x86.ssse3) {
+ encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_intrin_ssse3;
+ }
+# endif
+# ifdef FLAC__SSE4_2_SUPPORTED
+ if (encoder->private_->cpuinfo.x86.sse42) {
+ encoder->private_->local_fixed_compute_best_predictor_limit_residual = FLAC__fixed_compute_best_predictor_limit_residual_intrin_sse42;
+ }
+# endif
+# ifdef FLAC__AVX2_SUPPORTED
+ if (encoder->private_->cpuinfo.x86.avx2) {
+ encoder->private_->local_fixed_compute_best_predictor_wide = FLAC__fixed_compute_best_predictor_wide_intrin_avx2;
+ encoder->private_->local_fixed_compute_best_predictor_limit_residual = FLAC__fixed_compute_best_predictor_limit_residual_intrin_avx2;
+ }
+# endif
+# endif /* FLAC__HAS_X86INTRIN */
+# elif defined FLAC__CPU_X86_64
+ FLAC__ASSERT(encoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_X86_64);
+# if FLAC__HAS_X86INTRIN
+# ifdef FLAC__SSE2_SUPPORTED
+ if(encoder->private_->cpuinfo.x86.sse2) { /* For fuzzing */
+ if(encoder->protected_->max_lpc_order < 8)
+ encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse2_lag_8;
+ else if(encoder->protected_->max_lpc_order < 10)
+ encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse2_lag_10;
+ else if(encoder->protected_->max_lpc_order < 14)
+ encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse2_lag_14;
+
+ encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_sse2;
+ }
+# endif
+# ifdef FLAC__SSE4_1_SUPPORTED
+ if(encoder->private_->cpuinfo.x86.sse41) {
+ encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse41;
+ }
+# endif
+# ifdef FLAC__AVX2_SUPPORTED
+ if(encoder->private_->cpuinfo.x86.avx2) {
+ encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_avx2;
+ encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_avx2;
+ encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_avx2;
+ }
+# endif
+# ifdef FLAC__FMA_SUPPORTED
+ if(encoder->private_->cpuinfo.x86.fma) {
+ if(encoder->protected_->max_lpc_order < 8)
+ encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_fma_lag_8;
+ else if(encoder->protected_->max_lpc_order < 12)
+ encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_fma_lag_12;
+ else if(encoder->protected_->max_lpc_order < 16)
+ encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_fma_lag_16;
+ }
+# endif
+
+
+# ifdef FLAC__SSE2_SUPPORTED
+ if(encoder->private_->cpuinfo.x86.sse2) { /* For fuzzing */
+ encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_intrin_sse2;
+ }
+# endif
+# ifdef FLAC__SSSE3_SUPPORTED
+ if (encoder->private_->cpuinfo.x86.ssse3) {
+ encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_intrin_ssse3;
+ }
+# endif
+# ifdef FLAC__SSE4_2_SUPPORTED
+ if (encoder->private_->cpuinfo.x86.sse42) {
+ encoder->private_->local_fixed_compute_best_predictor_limit_residual = FLAC__fixed_compute_best_predictor_limit_residual_intrin_sse42;
+ }
+# endif
+# ifdef FLAC__AVX2_SUPPORTED
+ if (encoder->private_->cpuinfo.x86.avx2) {
+ encoder->private_->local_fixed_compute_best_predictor_wide = FLAC__fixed_compute_best_predictor_wide_intrin_avx2;
+ encoder->private_->local_fixed_compute_best_predictor_limit_residual = FLAC__fixed_compute_best_predictor_limit_residual_intrin_avx2;
+ }
+# endif
+# endif /* FLAC__HAS_X86INTRIN */
+# endif /* FLAC__CPU_... */
+ }
+# endif /* !FLAC__NO_ASM */
+
+#endif /* !FLAC__INTEGER_ONLY_LIBRARY */
+#if !defined FLAC__NO_ASM && FLAC__HAS_X86INTRIN
+ if(encoder->private_->cpuinfo.use_asm) {
+# if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64)
+# ifdef FLAC__SSE2_SUPPORTED
+ if (encoder->private_->cpuinfo.x86.sse2)
+ encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_sse2;
+# endif
+# ifdef FLAC__SSSE3_SUPPORTED
+ if (encoder->private_->cpuinfo.x86.ssse3)
+ encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_ssse3;
+# endif
+# ifdef FLAC__AVX2_SUPPORTED
+ if (encoder->private_->cpuinfo.x86.avx2)
+ encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_avx2;
+# endif
+# endif /* FLAC__CPU_... */
+ }
+#endif /* !FLAC__NO_ASM && FLAC__HAS_X86INTRIN */
+
+ /* 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] = safe_malloc_mul_2op_p(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
+ */
+ if(0 == encoder->private_->verify.decoder) {
+ 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, true)) {
+ 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, true)) {
+ 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, true)) {
+ 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 */
+
+#ifdef _WIN32
+ /*
+ * Windows can suffer quite badly from disk fragmentation. This can be
+ * reduced significantly by setting the output buffer size to be 10MB.
+ */
+ if(GetFileType((HANDLE)_get_osfhandle(_fileno(file))) == FILE_TYPE_DISK)
+ setvbuf(file, NULL, _IOFBF, 10*1024*1024);
+#endif
+ 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;
+ }
+
+ {
+ uint32_t blocksize = FLAC__stream_encoder_get_blocksize(encoder);
+
+ FLAC__ASSERT(blocksize != 0);
+ encoder->private_->total_frames_estimate = (uint32_t)((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? flac_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;
+
+ if (encoder == NULL)
+ return false;
+
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+
+ if(encoder->protected_->state == FLAC__STREAM_ENCODER_UNINITIALIZED){
+ if(encoder->protected_->metadata){ // True in case FLAC__stream_encoder_set_metadata was used but init failed
+ free(encoder->protected_->metadata);
+ encoder->protected_->metadata = 0;
+ encoder->protected_->num_metadata_blocks = 0;
+ }
+ if(0 != encoder->private_->file) {
+ if(encoder->private_->file != stdout)
+ fclose(encoder->private_->file);
+ encoder->private_->file = 0;
+ }
+ return true;
+ }
+
+ if(encoder->protected_->state == FLAC__STREAM_ENCODER_OK && !encoder->private_->is_being_deleted) {
+ if(encoder->private_->current_sample_number != 0) {
+ encoder->protected_->blocksize = encoder->private_->current_sample_number;
+ 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(!process_frame_(encoder, /*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;
+}
+
+/*
+ * The following routine was intended as debug routine and is not in the
+ * public headers, but SHOULD NOT CHANGE! It is known is is used in
+ * some non-audio projects needing every last bit of performance.
+ * See https://github.com/xiph/flac/issues/547 for details. These projects
+ * provide their own prototype, so changing the signature of this function
+ * would break building.
+ */
+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, uint32_t 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, uint32_t 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, uint32_t 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, uint32_t 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 1
+ ok &= FLAC__stream_encoder_set_apodization (encoder, compression_levels_[value].apodization);
+#else
+ /* equivalent to -A tukey(0.5) */
+ 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, uint32_t 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>15 && 0 == strncmp("partial_tukey(", specification, 14)) {
+ FLAC__int32 tukey_parts = (FLAC__int32)strtod(specification+14, 0);
+ const char *si_1 = strchr(specification, '/');
+ FLAC__real overlap = si_1?flac_min((FLAC__real)strtod(si_1+1, 0),0.99f):0.1f;
+ FLAC__real overlap_units = 1.0f/(1.0f - overlap) - 1.0f;
+ const char *si_2 = strchr((si_1?(si_1+1):specification), '/');
+ FLAC__real tukey_p = si_2?(FLAC__real)strtod(si_2+1, 0):0.2f;
+
+ if (tukey_parts <= 1) {
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.tukey.p = tukey_p;
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TUKEY;
+ }else if (encoder->protected_->num_apodizations + tukey_parts < 32){
+ FLAC__int32 m;
+ for(m = 0; m < tukey_parts; m++){
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.p = tukey_p;
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.start = m/(tukey_parts+overlap_units);
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.end = (m+1+overlap_units)/(tukey_parts+overlap_units);
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_PARTIAL_TUKEY;
+ }
+ }
+ }
+ else if(n>16 && 0 == strncmp("punchout_tukey(", specification, 15)) {
+ FLAC__int32 tukey_parts = (FLAC__int32)strtod(specification+15, 0);
+ const char *si_1 = strchr(specification, '/');
+ FLAC__real overlap = si_1?flac_min((FLAC__real)strtod(si_1+1, 0),0.99f):0.2f;
+ FLAC__real overlap_units = 1.0f/(1.0f - overlap) - 1.0f;
+ const char *si_2 = strchr((si_1?(si_1+1):specification), '/');
+ FLAC__real tukey_p = si_2?(FLAC__real)strtod(si_2+1, 0):0.2f;
+
+ if (tukey_parts <= 1) {
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.tukey.p = tukey_p;
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TUKEY;
+ }else if (encoder->protected_->num_apodizations + tukey_parts < 32){
+ FLAC__int32 m;
+ for(m = 0; m < tukey_parts; m++){
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.p = tukey_p;
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.start = m/(tukey_parts+overlap_units);
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.end = (m+1+overlap_units)/(tukey_parts+overlap_units);
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_PUNCHOUT_TUKEY;
+ }
+ }
+ }
+ else if(n>17 && 0 == strncmp("subdivide_tukey(", specification, 16)){
+ FLAC__int32 parts = (FLAC__int32)strtod(specification+16, 0);
+ if(parts > 1){
+ const char *si_1 = strchr(specification, '/');
+ FLAC__real p = si_1?(FLAC__real)strtod(si_1+1, 0):5e-1;
+ if(p > 1)
+ p = 1;
+ else if(p < 0)
+ p = 0;
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.subdivide_tukey.parts = parts;
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.subdivide_tukey.p = p/parts;
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_SUBDIVIDE_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, uint32_t 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, uint32_t 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;
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ /* was deprecated since FLAC 1.0.4 (24-Sep-2002), but is needed for
+ * full spec coverage, so this should be reenabled at some point.
+ * For now only enable while fuzzing */
+ 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, uint32_t 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, uint32_t 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, uint32_t 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;
+ value = flac_min(value, (FLAC__U64L(1) << FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN) - 1);
+ encoder->protected_->total_samples_estimate = value;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_metadata(FLAC__StreamEncoder *encoder, FLAC__StreamMetadata **metadata, uint32_t 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 = safe_malloc_mul_2op_p(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;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_limit_min_bitrate(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_->limit_min_bitrate = value;
+ return true;
+}
+
+/*
+ * These four functions are not static, but not publicly exposed in
+ * include/FLAC/ either. They are used by the test suite and in fuzzing
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_disable_instruction_set(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_mmx = value & 1;
+ encoder->private_->disable_sse2 = value & 2;
+ encoder->private_->disable_ssse3 = value & 4;
+ encoder->private_->disable_sse41 = value & 8;
+ encoder->private_->disable_avx2 = value & 16;
+ encoder->private_->disable_fma = value & 32;
+ encoder->private_->disable_sse42 = value & 64;
+ return true;
+}
+
+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, uint32_t *frame_number, uint32_t *channel, uint32_t *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 uint32_t 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 uint32_t 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 uint32_t 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 uint32_t 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 uint32_t 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 uint32_t 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 uint32_t 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 uint32_t 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 uint32_t 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_get_limit_min_bitrate(const FLAC__StreamEncoder *encoder)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ return encoder->protected_->limit_min_bitrate;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC__int32 * const buffer[], uint32_t samples)
+{
+ uint32_t i, j = 0, k = 0, channel;
+ const uint32_t channels = encoder->protected_->channels, blocksize = encoder->protected_->blocksize;
+ const FLAC__int32 sample_max = INT32_MAX >> (32 - encoder->protected_->bits_per_sample);
+ const FLAC__int32 sample_min = INT32_MIN >> (32 - encoder->protected_->bits_per_sample);
+
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+
+ if(encoder->protected_->state != FLAC__STREAM_ENCODER_OK)
+ return false;
+
+ do {
+ const uint32_t n = flac_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++) {
+ if (buffer[channel] == NULL) {
+ return false;
+ }
+ for(i = encoder->private_->current_sample_number, k = j; i <= blocksize && k < samples; i++, k++) {
+ if(buffer[channel][k] < sample_min || buffer[channel][k] > sample_max){
+ encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+ return false;
+ }
+ }
+ memcpy(&encoder->private_->integer_signal[channel][encoder->private_->current_sample_number], &buffer[channel][j], sizeof(buffer[channel][0]) * n);
+ }
+ 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_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];
+ 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[], uint32_t samples)
+{
+ uint32_t i, j, k, channel;
+ const uint32_t channels = encoder->protected_->channels, blocksize = encoder->protected_->blocksize;
+ const FLAC__int32 sample_max = INT32_MAX >> (32 - encoder->protected_->bits_per_sample);
+ const FLAC__int32 sample_min = INT32_MIN >> (32 - encoder->protected_->bits_per_sample);
+
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+
+ if(encoder->protected_->state != FLAC__STREAM_ENCODER_OK)
+ return false;
+
+ j = k = 0;
+ do {
+ if(encoder->protected_->verify)
+ append_to_verify_fifo_interleaved_(&encoder->private_->verify.input_fifo, buffer, j, channels, flac_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++){
+ if(buffer[k] < sample_min || buffer[k] > sample_max){
+ encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+ return false;
+ }
+ 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_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_->limit_min_bitrate = false;
+ encoder->protected_->metadata = 0;
+ encoder->protected_->num_metadata_blocks = 0;
+
+ encoder->private_->seek_table = 0;
+ encoder->private_->disable_mmx = false;
+ encoder->private_->disable_sse2 = false;
+ encoder->private_->disable_ssse3 = false;
+ encoder->private_->disable_sse41 = false;
+ encoder->private_->disable_sse42 = false;
+ encoder->private_->disable_avx2 = false;
+ encoder->private_->disable_constant_subframes = false;
+ encoder->private_->disable_fixed_subframes = false;
+ encoder->private_->disable_verbatim_subframes = false;
+ encoder->private_->is_ogg = false;
+ 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
+
+ FLAC__stream_encoder_set_compression_level(encoder, 5);
+}
+
+void free_(FLAC__StreamEncoder *encoder)
+{
+ uint32_t 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
+ }
+ if(0 != encoder->private_->integer_signal_33bit_side_unaligned){
+ free(encoder->private_->integer_signal_33bit_side_unaligned);
+ encoder->private_->integer_signal_33bit_side_unaligned = 0;
+ }
+#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, uint32_t new_blocksize)
+{
+ FLAC__bool ok;
+ uint32_t i, channel;
+
+ FLAC__ASSERT(new_blocksize > 0);
+ FLAC__ASSERT(encoder->protected_->state == FLAC__STREAM_ENCODER_OK);
+
+ ok = true;
+
+ /* To avoid excessive malloc'ing, we only grow the buffer; no shrinking. */
+ if(new_blocksize > encoder->private_->input_capacity) {
+
+ /* WATCHOUT: FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx() and ..._intrin_sse2()
+ * require 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]);
+ if(ok) {
+ memset(encoder->private_->integer_signal[i], 0, sizeof(FLAC__int32)*4);
+ encoder->private_->integer_signal[i] += 4;
+ }
+ }
+ 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]);
+ if(ok) {
+ memset(encoder->private_->integer_signal_mid_side[i], 0, sizeof(FLAC__int32)*4);
+ encoder->private_->integer_signal_mid_side[i] += 4;
+ }
+ }
+ ok = ok && FLAC__memory_alloc_aligned_int64_array(new_blocksize+4+OVERREAD_, &encoder->private_->integer_signal_33bit_side_unaligned, &encoder->private_->integer_signal_33bit_side);
+#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 < encoder->protected_->channels; channel++) {
+ for(i = 0; ok && i < 2; i++) {
+ ok = ok && FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(&encoder->private_->partitioned_rice_contents_workspace[channel][i], encoder->protected_->max_residual_partition_order);
+ ok = ok && FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(&encoder->private_->partitioned_rice_contents_workspace[channel][i], encoder->protected_->max_residual_partition_order);
+ }
+ }
+
+ 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]);
+ }
+ }
+
+ for(channel = 0; ok && channel < 2; channel++) {
+ for(i = 0; ok && i < 2; i++) {
+ ok = ok && FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(&encoder->private_->partitioned_rice_contents_workspace_mid_side[channel][i], encoder->protected_->max_residual_partition_order);
+ }
+ }
+
+ for(i = 0; ok && i < 2; i++) {
+ ok = ok && FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(&encoder->private_->partitioned_rice_contents_extra[i], encoder->protected_->max_residual_partition_order);
+ }
+
+
+ /* 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_uint32_array(new_blocksize * 2, &encoder->private_->raw_bits_per_partition_unaligned, &encoder->private_->raw_bits_per_partition);
+}
+ if(ok)
+ encoder->private_->input_capacity = new_blocksize;
+ else {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+ return ok;
+ }
+
+
+ /* now adjust the windows if the blocksize has changed */
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+ if(encoder->protected_->max_lpc_order > 0 && new_blocksize > 1) {
+ for(i = 0; 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_PARTIAL_TUKEY:
+ FLAC__window_partial_tukey(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.multiple_tukey.p, encoder->protected_->apodizations[i].parameters.multiple_tukey.start, encoder->protected_->apodizations[i].parameters.multiple_tukey.end);
+ break;
+ case FLAC__APODIZATION_PUNCHOUT_TUKEY:
+ FLAC__window_punchout_tukey(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.multiple_tukey.p, encoder->protected_->apodizations[i].parameters.multiple_tukey.start, encoder->protected_->apodizations[i].parameters.multiple_tukey.end);
+ break;
+ case FLAC__APODIZATION_SUBDIVIDE_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;
+ }
+ }
+ }
+ if (new_blocksize <= FLAC__MAX_LPC_ORDER) {
+ /* intrinsics autocorrelation routines do not all handle cases in which lag might be
+ * larger than data_len. Lag is one larger than the LPC order */
+ encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation;
+ }
+#endif
+
+ return true;
+}
+
+FLAC__bool write_bitbuffer_(FLAC__StreamEncoder *encoder, uint32_t 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)
+ || (!is_last_block
+ && (FLAC__stream_encoder_get_verify_decoder_state(encoder) == FLAC__STREAM_DECODER_END_OF_STREAM))
+ || encoder->protected_->state == FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR /* Happens when error callback was used */) {
+ 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 = flac_min(bytes, encoder->private_->streaminfo.data.stream_info.min_framesize);
+ encoder->private_->streaminfo.data.stream_info.max_framesize = flac_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, uint32_t samples, FLAC__bool is_last_block)
+{
+ FLAC__StreamEncoderWriteStatus status;
+ FLAC__uint64 output_position = 0;
+
+#if FLAC__HAS_OGG == 0
+ (void)is_last_block;
+#endif
+
+ /* 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 uint32_t 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;
+ uint32_t 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 = flac_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[flac_max(6u, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)];
+ const FLAC__StreamMetadata *metadata = &encoder->private_->streaminfo;
+ FLAC__uint64 samples = metadata->data.stream_info.total_samples;
+ const uint32_t min_framesize = metadata->data.stream_info.min_framesize;
+ const uint32_t max_framesize = metadata->data.stream_info.max_framesize;
+ const uint32_t 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 uint32_t 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 uint32_t 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;
+ if(samples > (FLAC__U64L(1) << FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN))
+ samples = 0;
+
+ 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 uint32_t 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) {
+ uint32_t 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;
+ uint32_t 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 uint32_t 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[flac_max(6u, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)];
+ const FLAC__StreamMetadata *metadata = &encoder->private_->streaminfo;
+ const FLAC__uint64 samples = metadata->data.stream_info.total_samples;
+ const uint32_t min_framesize = metadata->data.stream_info.min_framesize;
+ const uint32_t 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 uint32_t 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 > (uint32_t)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 uint32_t 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 > (uint32_t)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 uint32_t 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 > (uint32_t)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);
+}
+#endif
+
+FLAC__bool process_frame_(FLAC__StreamEncoder *encoder, 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)) {
+ /* 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__FrameHeader frame_header;
+ uint32_t channel, min_partition_order = encoder->protected_->min_residual_partition_order, max_partition_order;
+ FLAC__bool do_independent, do_mid_side, backup_disable_constant_subframes = encoder->private_->disable_constant_subframes, all_subframes_constant = true;
+
+ /*
+ * Calculate the min,max Rice partition orders
+ */
+
+ max_partition_order = FLAC__format_get_max_rice_partition_order_from_blocksize(encoder->protected_->blocksize);
+ max_partition_order = flac_min(max_partition_order, encoder->protected_->max_residual_partition_order);
+ min_partition_order = flac_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);
+
+ /*
+ * Prepare mid-side signals if applicable
+ */
+ if(do_mid_side) {
+ uint32_t i;
+ FLAC__ASSERT(encoder->protected_->channels == 2);
+ if(encoder->protected_->bits_per_sample < 32)
+ for(i = 0; i < encoder->protected_->blocksize; i++) {
+ encoder->private_->integer_signal_mid_side[1][i] = encoder->private_->integer_signal[0][i] - encoder->private_->integer_signal[1][i];
+ encoder->private_->integer_signal_mid_side[0][i] = (encoder->private_->integer_signal[0][i] + encoder->private_->integer_signal[1][i]) >> 1; /* NOTE: not the same as 'mid = (signal[0][j] + signal[1][j]) / 2' ! */
+ }
+ else
+ for(i = 0; i <= encoder->protected_->blocksize; i++) {
+ encoder->private_->integer_signal_33bit_side[i] = (FLAC__int64)encoder->private_->integer_signal[0][i] - (FLAC__int64)encoder->private_->integer_signal[1][i];
+ encoder->private_->integer_signal_mid_side[0][i] = ((FLAC__int64)encoder->private_->integer_signal[0][i] + (FLAC__int64)encoder->private_->integer_signal[1][i]) >> 1; /* NOTE: not the same as 'mid = (signal[0][j] + signal[1][j]) / 2' ! */
+ }
+ }
+
+
+ /*
+ * Check for wasted bits; set effective bps for each subframe
+ */
+ if(do_independent) {
+ for(channel = 0; channel < encoder->protected_->channels; channel++) {
+ uint32_t w = get_wasted_bits_(encoder->private_->integer_signal[channel], encoder->protected_->blocksize);
+ if (w > encoder->protected_->bits_per_sample) {
+ w = encoder->protected_->bits_per_sample;
+ }
+ 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++) {
+ uint32_t w;
+ if(encoder->protected_->bits_per_sample < 32 || channel == 0)
+ w = get_wasted_bits_(encoder->private_->integer_signal_mid_side[channel], encoder->protected_->blocksize);
+ else
+ w = get_wasted_bits_wide_(encoder->private_->integer_signal_33bit_side, encoder->private_->integer_signal_mid_side[channel], encoder->protected_->blocksize);
+
+ if (w > encoder->protected_->bits_per_sample) {
+ w = encoder->protected_->bits_per_sample;
+ }
+ 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(encoder->protected_->limit_min_bitrate && all_subframes_constant && (channel + 1) == encoder->protected_->channels){
+ /* This frame contains only constant subframes at this point.
+ * To prevent the frame from becoming too small, make sure
+ * the last subframe isn't constant */
+ encoder->private_->disable_constant_subframes = true;
+ }
+ 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;
+ if(encoder->private_->subframe_workspace[channel][encoder->private_->best_subframe[channel]].type != FLAC__SUBFRAME_TYPE_CONSTANT)
+ all_subframes_constant = 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++) {
+ void *integer_signal_;
+ if(encoder->private_->subframe_bps_mid_side[channel] <= 32)
+ integer_signal_ = encoder->private_->integer_signal_mid_side[channel];
+ else
+ integer_signal_ = encoder->private_->integer_signal_33bit_side;
+ if(!
+ process_subframe_(
+ encoder,
+ min_partition_order,
+ max_partition_order,
+ &frame_header,
+ encoder->private_->subframe_bps_mid_side[channel],
+ integer_signal_,
+ 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) {
+ uint32_t 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 {
+ uint32_t bits[4]; /* WATCHOUT - indexed by FLAC__ChannelAssignment */
+ uint32_t 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];
+
+ /* When doing loose mid-side stereo, ignore left-side
+ * and right-side options */
+ ca = encoder->protected_->loose_mid_side_stereo ? 3 : 1;
+ for( ; 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;
+ encoder->private_->disable_constant_subframes = backup_disable_constant_subframes;
+
+ return true;
+}
+
+FLAC__bool process_subframe_(
+ FLAC__StreamEncoder *encoder,
+ uint32_t min_partition_order,
+ uint32_t max_partition_order,
+ const FLAC__FrameHeader *frame_header,
+ uint32_t subframe_bps,
+ const void *integer_signal,
+ FLAC__Subframe *subframe[2],
+ FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents[2],
+ FLAC__int32 *residual[2],
+ uint32_t *best_subframe,
+ uint32_t *best_bits
+)
+{
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+ 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
+ double lpc_residual_bits_per_sample;
+ apply_apodization_state_struct apply_apodization_state;
+ double lpc_error[FLAC__MAX_LPC_ORDER];
+ uint32_t min_lpc_order, max_lpc_order, lpc_order, guess_lpc_order;
+ uint32_t min_qlp_coeff_precision, max_qlp_coeff_precision, qlp_coeff_precision;
+#endif
+ uint32_t min_fixed_order, max_fixed_order, guess_fixed_order, fixed_order;
+ uint32_t _candidate_bits, _best_bits;
+ uint32_t _best_subframe;
+ /* only use RICE2 partitions if stream bps > 16 */
+ const uint32_t 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 = UINT32_MAX;
+ else
+ _best_bits = evaluate_verbatim_subframe_(encoder, integer_signal, frame_header->blocksize, subframe_bps, subframe[_best_subframe]);
+ *best_bits = _best_bits;
+
+ if(frame_header->blocksize > FLAC__MAX_FIXED_ORDER) {
+ uint32_t signal_is_constant = false;
+ /* The next formula determines when to use a 64-bit accumulator
+ * for the error of a fixed predictor, and when a 32-bit one. As
+ * the error of a 4th order predictor for a given sample is the
+ * sum of 17 sample values (1+4+6+4+1) and there are blocksize -
+ * order error values to be summed, the maximum total error is
+ * maximum_sample_value * (blocksize - order) * 17. As ilog2(x)
+ * calculates floor(2log(x)), the result must be 31 or lower
+ */
+ if(subframe_bps < 28){
+ if(subframe_bps + FLAC__bitmath_ilog2((frame_header->blocksize-FLAC__MAX_FIXED_ORDER)*17) < 32)
+ guess_fixed_order = encoder->private_->local_fixed_compute_best_predictor(((FLAC__int32 *)integer_signal)+FLAC__MAX_FIXED_ORDER, frame_header->blocksize-FLAC__MAX_FIXED_ORDER, fixed_residual_bits_per_sample);
+ else
+ guess_fixed_order = encoder->private_->local_fixed_compute_best_predictor_wide(((FLAC__int32 *)integer_signal)+FLAC__MAX_FIXED_ORDER, frame_header->blocksize-FLAC__MAX_FIXED_ORDER, fixed_residual_bits_per_sample);
+ }
+ else
+ if(subframe_bps <= 32)
+ guess_fixed_order = encoder->private_->local_fixed_compute_best_predictor_limit_residual(((FLAC__int32 *)integer_signal+FLAC__MAX_FIXED_ORDER),frame_header->blocksize-FLAC__MAX_FIXED_ORDER, fixed_residual_bits_per_sample);
+ else
+ guess_fixed_order = FLAC__fixed_compute_best_predictor_limit_residual_33bit(((FLAC__int64 *)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: */
+ uint32_t i;
+ signal_is_constant = true;
+ if(subframe_bps <= 32){
+ const FLAC__int32 *integer_signal_ = integer_signal;
+ for(i = 1; i < frame_header->blocksize; i++) {
+ if(integer_signal_[0] != integer_signal_[i]) {
+ signal_is_constant = false;
+ break;
+ }
+ }
+ }
+ else {
+ const FLAC__int64 *integer_signal_ = integer_signal;
+ for(i = 1; i < frame_header->blocksize; i++) {
+ if(integer_signal_[0] != integer_signal_[i]) {
+ signal_is_constant = false;
+ break;
+ }
+ }
+ }
+ }
+ if(signal_is_constant) {
+ if(subframe_bps <= 32)
+ _candidate_bits = evaluate_constant_subframe_(encoder, ((FLAC__int32 *)integer_signal)[0], frame_header->blocksize, subframe_bps, subframe[!_best_subframe]);
+ else
+ _candidate_bits = evaluate_constant_subframe_(encoder, ((FLAC__int64 *)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] >= (float)subframe_bps)
+ continue; /* don't even try */
+#else
+ if(FLAC__fixedpoint_trunc(fixed_residual_bits_per_sample[fixed_order]) >= (int)subframe_bps)
+ continue; /* don't even try */
+#endif
+ _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_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) {
+ apply_apodization_state.a = 0;
+ apply_apodization_state.b = 1;
+ apply_apodization_state.c = 0;
+ while (apply_apodization_state.a < encoder->protected_->num_apodizations) {
+ uint32_t max_lpc_order_this_apodization = max_lpc_order;
+
+ if(!apply_apodization_(encoder, &apply_apodization_state,
+ frame_header->blocksize, lpc_error,
+ &max_lpc_order_this_apodization,
+ subframe_bps, integer_signal,
+ &guess_lpc_order))
+ /* If apply_apodization_ fails, try next apodization */
+ continue;
+
+ if(encoder->protected_->do_exhaustive_model_search) {
+ min_lpc_order = 1;
+ }
+ else {
+ min_lpc_order = max_lpc_order_this_apodization = guess_lpc_order;
+ }
+ for(lpc_order = min_lpc_order; lpc_order <= max_lpc_order_this_apodization; 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 >= (double)subframe_bps)
+ continue; /* don't even try */
+ if(encoder->protected_->do_qlp_coeff_prec_search) {
+ min_qlp_coeff_precision = FLAC__MIN_QLP_COEFF_PRECISION;
+ /* try to keep qlp coeff precision such that only 32-bit math is required for decode of <=16bps(+1bps for side channel) streams */
+ if(subframe_bps <= 17) {
+ max_qlp_coeff_precision = flac_min(32 - subframe_bps - FLAC__bitmath_ilog2(lpc_order), FLAC__MAX_QLP_COEFF_PRECISION);
+ max_qlp_coeff_precision = flac_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_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 == UINT32_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;
+}
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+static inline void set_next_subdivide_tukey(FLAC__int32 parts, uint32_t * apodizations, uint32_t * current_depth, uint32_t * current_part){
+ // current_part is interleaved: even are partial, odd are punchout
+ if(*current_depth == 2){
+ // For depth 2, we only do partial, no punchout as that is almost redundant
+ if(*current_part == 0){
+ *current_part = 2;
+ }else{ /* *current_path == 2 */
+ *current_part = 0;
+ (*current_depth)++;
+ }
+ }else if((*current_part) < (2*(*current_depth)-1)){
+ (*current_part)++;
+ }else{ /* (*current_part) >= (2*(*current_depth)-1) */
+ *current_part = 0;
+ (*current_depth)++;
+ }
+
+ /* Now check if we are done with this SUBDIVIDE_TUKEY apodization */
+ if(*current_depth > (uint32_t) parts){
+ (*apodizations)++;
+ *current_depth = 1;
+ *current_part = 0;
+ }
+}
+
+FLAC__bool apply_apodization_(FLAC__StreamEncoder *encoder,
+ apply_apodization_state_struct *apply_apodization_state,
+ uint32_t blocksize,
+ double *lpc_error,
+ uint32_t *max_lpc_order_this_apodization,
+ uint32_t subframe_bps,
+ const void *integer_signal,
+ uint32_t *guess_lpc_order)
+{
+ apply_apodization_state->current_apodization = &encoder->protected_->apodizations[apply_apodization_state->a];
+
+ if(apply_apodization_state->b == 1) {
+ /* window full subblock */
+ if(subframe_bps <= 32)
+ FLAC__lpc_window_data(integer_signal, encoder->private_->window[apply_apodization_state->a], encoder->private_->windowed_signal, blocksize);
+ else
+ FLAC__lpc_window_data_wide(integer_signal, encoder->private_->window[apply_apodization_state->a], encoder->private_->windowed_signal, blocksize);
+ encoder->private_->local_lpc_compute_autocorrelation(encoder->private_->windowed_signal, blocksize, (*max_lpc_order_this_apodization)+1, apply_apodization_state->autoc);
+ if(apply_apodization_state->current_apodization->type == FLAC__APODIZATION_SUBDIVIDE_TUKEY){
+ uint32_t i;
+ for(i = 0; i < *max_lpc_order_this_apodization; i++)
+ memcpy(apply_apodization_state->autoc_root, apply_apodization_state->autoc, *max_lpc_order_this_apodization*sizeof(apply_apodization_state->autoc[0]));
+
+ (apply_apodization_state->b)++;
+ }else{
+ (apply_apodization_state->a)++;
+ }
+ }
+ else {
+ /* window part of subblock */
+ if(blocksize/apply_apodization_state->b <= FLAC__MAX_LPC_ORDER) {
+ /* intrinsics autocorrelation routines do not all handle cases in which lag might be
+ * larger than data_len, and some routines round lag up to the nearest multiple of 4
+ * As little gain is expected from using LPC on part of a signal as small as 32 samples
+ * and to enable widening this rounding up to larger values in the future, windowing
+ * parts smaller than or equal to FLAC__MAX_LPC_ORDER (which is 32) samples is not supported */
+ set_next_subdivide_tukey(apply_apodization_state->current_apodization->parameters.subdivide_tukey.parts, &apply_apodization_state->a, &apply_apodization_state->b, &apply_apodization_state->c);
+ return false;
+ }
+ if(!(apply_apodization_state->c % 2)) {
+ /* on even c, evaluate the (c/2)th partial window of size blocksize/b */
+ if(subframe_bps <= 32)
+ FLAC__lpc_window_data_partial(integer_signal, encoder->private_->window[apply_apodization_state->a], encoder->private_->windowed_signal, blocksize, blocksize/apply_apodization_state->b/2, (apply_apodization_state->c/2*blocksize)/apply_apodization_state->b);
+ else
+ FLAC__lpc_window_data_partial_wide(integer_signal, encoder->private_->window[apply_apodization_state->a], encoder->private_->windowed_signal, blocksize, blocksize/apply_apodization_state->b/2, (apply_apodization_state->c/2*blocksize)/apply_apodization_state->b);
+ encoder->private_->local_lpc_compute_autocorrelation(encoder->private_->windowed_signal, blocksize/apply_apodization_state->b, (*max_lpc_order_this_apodization)+1, apply_apodization_state->autoc);
+ }
+ else {
+ /* on uneven c, evaluate the root window (over the whole block) minus the previous partial window
+ * similar to tukey_punchout apodization but more efficient */
+ uint32_t i;
+ for(i = 0; i < *max_lpc_order_this_apodization; i++)
+ apply_apodization_state->autoc[i] = apply_apodization_state->autoc_root[i] - apply_apodization_state->autoc[i];
+ }
+ /* Next function sets a, b and c appropriate for next iteration */
+ set_next_subdivide_tukey(apply_apodization_state->current_apodization->parameters.subdivide_tukey.parts, &apply_apodization_state->a, &apply_apodization_state->b, &apply_apodization_state->c);
+ }
+
+ if(apply_apodization_state->autoc[0] == 0.0) /* Signal seems to be constant, so we can't do lp. Constant detection is probably disabled */
+ return false;
+ FLAC__lpc_compute_lp_coefficients(apply_apodization_state->autoc, max_lpc_order_this_apodization, encoder->private_->lp_coeff, lpc_error);
+ *guess_lpc_order =
+ FLAC__lpc_compute_best_order(
+ lpc_error,
+ *max_lpc_order_this_apodization,
+ 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
+ )
+ );
+ return true;
+}
+#endif
+
+FLAC__bool add_subframe_(
+ FLAC__StreamEncoder *encoder,
+ uint32_t blocksize,
+ uint32_t 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,
+ uint32_t blocksize,
+ uint32_t subframe_bps,
+ const FLAC__Subframe *subframe,
+ uint32_t 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 uint32_t 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
+
+uint32_t evaluate_constant_subframe_(
+ FLAC__StreamEncoder *encoder,
+ const FLAC__int64 signal,
+ uint32_t blocksize,
+ uint32_t subframe_bps,
+ FLAC__Subframe *subframe
+)
+{
+ uint32_t 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;
+}
+
+uint32_t evaluate_fixed_subframe_(
+ FLAC__StreamEncoder *encoder,
+ const void *signal,
+ FLAC__int32 residual[],
+ FLAC__uint64 abs_residual_partition_sums[],
+ uint32_t raw_bits_per_partition[],
+ uint32_t blocksize,
+ uint32_t subframe_bps,
+ uint32_t order,
+ uint32_t rice_parameter_limit,
+ uint32_t min_partition_order,
+ uint32_t max_partition_order,
+ FLAC__bool do_escape_coding,
+ uint32_t rice_parameter_search_dist,
+ FLAC__Subframe *subframe,
+ FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents
+)
+{
+ uint32_t i, residual_bits, estimate;
+ const uint32_t residual_samples = blocksize - order;
+
+ if((subframe_bps + order) <= 32)
+ FLAC__fixed_compute_residual(((FLAC__int32 *)signal)+order, residual_samples, order, residual);
+ else if(subframe_bps <= 32)
+ FLAC__fixed_compute_residual_wide(((FLAC__int32 *)signal)+order, residual_samples, order, residual);
+ else
+ FLAC__fixed_compute_residual_wide_33bit(((FLAC__int64 *)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_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;
+ if(subframe_bps <= 32)
+ for(i = 0; i < order; i++)
+ subframe->data.fixed.warmup[i] = ((FLAC__int32 *)signal)[i];
+ else
+ for(i = 0; i < order; i++)
+ subframe->data.fixed.warmup[i] = ((FLAC__int64 *)signal)[i];
+
+ estimate = FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + subframe->wasted_bits + (order * subframe_bps);
+ if(residual_bits < UINT32_MAX - estimate) // To make sure estimate doesn't overflow
+ estimate += residual_bits;
+ else
+ estimate = UINT32_MAX;
+
+#if SPOTCHECK_ESTIMATE
+ spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate);
+#endif
+
+ return estimate;
+}
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+uint32_t evaluate_lpc_subframe_(
+ FLAC__StreamEncoder *encoder,
+ const void *signal,
+ FLAC__int32 residual[],
+ FLAC__uint64 abs_residual_partition_sums[],
+ uint32_t raw_bits_per_partition[],
+ const FLAC__real lp_coeff[],
+ uint32_t blocksize,
+ uint32_t subframe_bps,
+ uint32_t order,
+ uint32_t qlp_coeff_precision,
+ uint32_t rice_parameter_limit,
+ uint32_t min_partition_order,
+ uint32_t max_partition_order,
+ FLAC__bool do_escape_coding,
+ uint32_t rice_parameter_search_dist,
+ FLAC__Subframe *subframe,
+ FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents
+)
+{
+ FLAC__int32 qlp_coeff[FLAC__MAX_LPC_ORDER]; /* WATCHOUT: the size is important; some x86 intrinsic routines need more than lpc order elements */
+ uint32_t i, residual_bits, estimate;
+ int quantization, ret;
+ const uint32_t residual_samples = blocksize - order;
+
+ /* try to keep qlp coeff precision such that only 32-bit math is required for decode of <=16bps(+1bps for side channel) streams */
+ if(subframe_bps <= 17) {
+ FLAC__ASSERT(order > 0);
+ FLAC__ASSERT(order <= FLAC__MAX_LPC_ORDER);
+ qlp_coeff_precision = flac_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(FLAC__lpc_max_residual_bps(subframe_bps, qlp_coeff, order, quantization) > 32) {
+ if(subframe_bps <= 32){
+ if(!FLAC__lpc_compute_residual_from_qlp_coefficients_limit_residual(((FLAC__int32 *)signal)+order, residual_samples, qlp_coeff, order, quantization, residual))
+ return 0;
+ }
+ else
+ if(!FLAC__lpc_compute_residual_from_qlp_coefficients_limit_residual_33bit(((FLAC__int64 *)signal)+order, residual_samples, qlp_coeff, order, quantization, residual))
+ return 0;
+ }
+ else
+ if(FLAC__lpc_max_prediction_before_shift_bps(subframe_bps, qlp_coeff, order) <= 32)
+ if(subframe_bps <= 16 && qlp_coeff_precision <= 16)
+ encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit(((FLAC__int32 *)signal)+order, residual_samples, qlp_coeff, order, quantization, residual);
+ else
+ encoder->private_->local_lpc_compute_residual_from_qlp_coefficients(((FLAC__int32 *)signal)+order, residual_samples, qlp_coeff, order, quantization, residual);
+ else
+ encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit(((FLAC__int32 *)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_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);
+ if(subframe_bps <= 32)
+ for(i = 0; i < order; i++)
+ subframe->data.lpc.warmup[i] = ((FLAC__int32 *)signal)[i];
+ else
+ for(i = 0; i < order; i++)
+ subframe->data.lpc.warmup[i] = ((FLAC__int64 *)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));
+ if(residual_bits < UINT32_MAX - estimate) // To make sure estimate doesn't overflow
+ estimate += residual_bits;
+ else
+ estimate = UINT32_MAX;
+
+#if SPOTCHECK_ESTIMATE
+ spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate);
+#endif
+
+ return estimate;
+}
+#endif
+
+uint32_t evaluate_verbatim_subframe_(
+ FLAC__StreamEncoder *encoder,
+ const void *signal,
+ uint32_t blocksize,
+ uint32_t subframe_bps,
+ FLAC__Subframe *subframe
+)
+{
+ uint32_t estimate;
+
+ subframe->type = FLAC__SUBFRAME_TYPE_VERBATIM;
+
+ if(subframe_bps <= 32){
+ subframe->data.verbatim.data_type = FLAC__VERBATIM_SUBFRAME_DATA_TYPE_INT32;
+ subframe->data.verbatim.data.int32 = signal;
+ }
+ else {
+ subframe->data.verbatim.data_type = FLAC__VERBATIM_SUBFRAME_DATA_TYPE_INT64;
+ subframe->data.verbatim.data.int64 = 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;
+}
+
+uint32_t find_best_partition_order_(
+ FLAC__StreamEncoderPrivate *private_,
+ const FLAC__int32 residual[],
+ FLAC__uint64 abs_residual_partition_sums[],
+ uint32_t raw_bits_per_partition[],
+ uint32_t residual_samples,
+ uint32_t predictor_order,
+ uint32_t rice_parameter_limit,
+ uint32_t min_partition_order,
+ uint32_t max_partition_order,
+ uint32_t bps,
+ FLAC__bool do_escape_coding,
+ uint32_t rice_parameter_search_dist,
+ FLAC__EntropyCodingMethod *best_ecm
+)
+{
+ uint32_t residual_bits, best_residual_bits = 0;
+ uint32_t best_parameters_index = 0;
+ uint32_t best_partition_order = 0;
+ const uint32_t 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 = flac_min(min_partition_order, max_partition_order);
+
+ private_->local_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;
+ uint32_t 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_limit,
+ rice_parameter_search_dist,
+ (uint32_t)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;
+ uint32_t partition;
+
+ /* save best parameters and raw_bits */
+ memcpy(prc->parameters, private_->partitioned_rice_contents_extra[best_parameters_index].parameters, (uint32_t)sizeof(uint32_t)*(1<<(best_partition_order)));
+ if(do_escape_coding)
+ memcpy(prc->raw_bits, private_->partitioned_rice_contents_extra[best_parameters_index].raw_bits, (uint32_t)sizeof(uint32_t)*(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;
+}
+
+void precompute_partition_info_sums_(
+ const FLAC__int32 residual[],
+ FLAC__uint64 abs_residual_partition_sums[],
+ uint32_t residual_samples,
+ uint32_t predictor_order,
+ uint32_t min_partition_order,
+ uint32_t max_partition_order,
+ uint32_t bps
+)
+{
+ const uint32_t default_partition_samples = (residual_samples + predictor_order) >> max_partition_order;
+ uint32_t partitions = 1u << max_partition_order;
+
+ FLAC__ASSERT(default_partition_samples > predictor_order);
+
+ /* first do max_partition_order */
+ {
+ const uint32_t threshold = 32 - FLAC__bitmath_ilog2(default_partition_samples);
+ uint32_t partition, residual_sample, end = (uint32_t)(-(int)predictor_order);
+ /* WATCHOUT: "bps + FLAC__MAX_EXTRA_RESIDUAL_BPS" is the maximum assumed size of the average residual magnitude */
+ if(bps + FLAC__MAX_EXTRA_RESIDUAL_BPS < threshold) {
+ for(partition = residual_sample = 0; partition < partitions; partition++) {
+ FLAC__uint32 abs_residual_partition_sum = 0;
+ end += default_partition_samples;
+ 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 */
+ for(partition = residual_sample = 0; partition < partitions; partition++) {
+ FLAC__uint64 abs_residual_partition_sum64 = 0;
+ end += default_partition_samples;
+ for( ; residual_sample < end; residual_sample++)
+ abs_residual_partition_sum64 += 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_sum64;
+ }
+ }
+ }
+
+ /* now merge partitions for lower orders */
+ {
+ uint32_t 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--) {
+ uint32_t 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[],
+ uint32_t raw_bits_per_partition[],
+ uint32_t residual_samples,
+ uint32_t predictor_order,
+ uint32_t min_partition_order,
+ uint32_t max_partition_order
+)
+{
+ int partition_order;
+ uint32_t from_partition, to_partition = 0;
+ const uint32_t 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;
+ uint32_t partition, partition_sample, partition_samples, residual_sample;
+ const uint32_t partitions = 1u << partition_order;
+ const uint32_t 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--) {
+ uint32_t m;
+ uint32_t i;
+ const uint32_t 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] = flac_max(m, raw_bits_per_partition[from_partition]);
+ from_partition++;
+ to_partition++;
+ }
+ }
+}
+
+#ifdef EXACT_RICE_BITS_CALCULATION
+static inline uint32_t count_rice_bits_in_partition_(
+ const uint32_t rice_parameter,
+ const uint32_t partition_samples,
+ const FLAC__int32 *residual
+)
+{
+ uint32_t i;
+ uint64_t 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 (uint32_t)(flac_min(partition_bits,UINT32_MAX)); // To make sure the return value doesn't overflow
+}
+#else
+static inline uint32_t count_rice_bits_in_partition_(
+ const uint32_t rice_parameter,
+ const uint32_t partition_samples,
+ const FLAC__uint64 abs_residual_partition_sum
+)
+{
+ return (uint32_t)(flac_min( // To make sure the return value doesn't overflow
+ 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?
+ (abs_residual_partition_sum >> (rice_parameter-1)) /* rice_parameter-1 because the real coder sign-folds instead of using a sign bit */
+ : (abs_residual_partition_sum << 1) /* can't shift by negative number, so reverse */
+ )
+ - (partition_samples >> 1),UINT32_MAX));
+ /* -(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 uint32_t raw_bits_per_partition[],
+ const uint32_t residual_samples,
+ const uint32_t predictor_order,
+ const uint32_t rice_parameter_limit,
+ const uint32_t rice_parameter_search_dist,
+ const uint32_t partition_order,
+ const FLAC__bool search_for_escapes,
+ FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents,
+ uint32_t *bits
+)
+{
+ uint32_t rice_parameter, partition_bits;
+ uint32_t best_partition_bits, best_rice_parameter = 0;
+ uint32_t bits_ = FLAC__ENTROPY_CODING_METHOD_TYPE_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN;
+ uint32_t *parameters, *raw_bits;
+ uint32_t partition, residual_sample;
+ uint32_t partition_samples, partition_samples_base;
+ uint32_t partition_samples_fixed_point_divisor, partition_samples_fixed_point_divisor_base;
+ const uint32_t partitions = 1u << partition_order;
+ FLAC__uint64 mean;
+#ifdef ENABLE_RICE_PARAMETER_SEARCH
+ uint32_t min_rice_parameter, max_rice_parameter;
+#else
+ (void)rice_parameter_search_dist;
+#endif
+
+ FLAC__ASSERT(rice_parameter_limit <= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER);
+
+ parameters = partitioned_rice_contents->parameters;
+ raw_bits = partitioned_rice_contents->raw_bits;
+
+ partition_samples_base = (residual_samples+predictor_order) >> partition_order;
+
+ /* Integer division is slow. To speed up things, precalculate a fixed point
+ * divisor, as all partitions except the first are the same size. 18 bits
+ * are taken because maximum block size is 65535, max partition size for
+ * partitions other than 0 is 32767 (15 bit), max abs residual is 2^31,
+ * which leaves 18 bit */
+ partition_samples_fixed_point_divisor_base = 0x40000 / partition_samples_base;
+
+ for(partition = residual_sample = 0; partition < partitions; partition++) {
+ partition_samples = partition_samples_base;
+ if(partition > 0) {
+ partition_samples_fixed_point_divisor = partition_samples_fixed_point_divisor_base;
+ }
+ else {
+ if(partition_samples <= predictor_order)
+ return false;
+ else
+ partition_samples -= predictor_order;
+ partition_samples_fixed_point_divisor = 0x40000 / partition_samples;
+ }
+ mean = abs_residual_partition_sums[partition];
+ /* '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
+ */
+ if(mean < 2 || (((mean - 1)*partition_samples_fixed_point_divisor)>>18) == 0)
+ rice_parameter = 0;
+ else
+ rice_parameter = FLAC__bitmath_ilog2_wide(((mean - 1)*partition_samples_fixed_point_divisor)>>18) + 1;
+
+ if(rice_parameter >= rice_parameter_limit) {
+#ifndef NDEBUG
+ 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 = UINT32_MAX;
+#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) {
+#ifndef NDEBUG
+ 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_per_partition[partition] < 32) {
+ 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;
+ if(best_partition_bits < UINT32_MAX - bits_) // To make sure _bits doesn't overflow
+ bits_ += best_partition_bits;
+ else
+ bits_ = UINT32_MAX;
+ residual_sample += partition_samples;
+ }
+
+ *bits = bits_;
+ return true;
+}
+
+uint32_t get_wasted_bits_(FLAC__int32 signal[], uint32_t samples)
+{
+ uint32_t 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;
+}
+
+uint32_t get_wasted_bits_wide_(FLAC__int64 signal_wide[], FLAC__int32 signal[], uint32_t samples)
+{
+ uint32_t i, shift;
+ FLAC__int64 x = 0;
+
+ for(i = 0; i < samples && !(x&1); i++)
+ x |= signal_wide[i];
+
+ if(x == 0) {
+ shift = 1;
+ }
+ else {
+ for(shift = 0; !(x&1); shift++)
+ x >>= 1;
+ }
+
+ if(shift > 0) {
+ for(i = 0; i < samples; i++)
+ signal[i] = (FLAC__int32)(signal_wide[i] >> shift);
+ }
+
+ return shift;
+}
+
+
+void append_to_verify_fifo_(verify_input_fifo *fifo, const FLAC__int32 * const input[], uint32_t input_offset, uint32_t channels, uint32_t wide_samples)
+{
+ uint32_t 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[], uint32_t input_offset, uint32_t channels, uint32_t wide_samples)
+{
+ uint32_t channel;
+ uint32_t sample, wide_sample;
+ uint32_t 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;
+ uint32_t channel;
+ const uint32_t channels = frame->header.channels;
+ const uint32_t blocksize = frame->header.blocksize;
+ const uint32_t bytes_per_block = sizeof(FLAC__int32) * blocksize;
+
+ (void)decoder;
+
+ if(encoder->protected_->state == FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR) {
+ /* This is set when verify_error_callback_ was called */
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+ }
+
+ for(channel = 0; channel < channels; channel++) {
+ if(0 != memcmp(buffer[channel], encoder->private_->verify.input_fifo.data[channel], bytes_per_block)) {
+ uint32_t 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 = (uint32_t)(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, (FLAC__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)
+{
+ FLAC__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, uint32_t samples, uint32_t 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 __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
index 0000000..0e07a31
--- /dev/null
+++ b/src/libFLAC/stream_encoder_framing.c
@@ -0,0 +1,594 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef 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"
+#include "share/compat.h"
+
+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 uint32_t residual_samples, const uint32_t predictor_order, const uint32_t rice_parameters[], const uint32_t raw_bits[], const uint32_t partition_order, const FLAC__bool is_extended);
+
+FLAC__bool FLAC__add_metadata_block(const FLAC__StreamMetadata *metadata, FLAC__BitWriter *bw, FLAC__bool update_vendor_string)
+{
+ uint32_t i, j, metadata_length;
+ const uint32_t vendor_string_length = (uint32_t)strlen(FLAC__VENDOR_STRING);
+ const uint32_t start_bits = FLAC__bitwriter_get_input_bits_unconsumed(bw);
+
+ FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(bw));
+
+ 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
+ */
+ metadata_length = metadata->length;
+ if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT && update_vendor_string) {
+ FLAC__ASSERT(metadata->data.vorbis_comment.vendor_string.length == 0 || 0 != metadata->data.vorbis_comment.vendor_string.entry);
+ metadata_length -= metadata->data.vorbis_comment.vendor_string.length;
+ metadata_length += vendor_string_length;
+ }
+ FLAC__ASSERT(metadata_length < (1u << FLAC__STREAM_METADATA_LENGTH_LEN));
+ /* double protection */
+ if(metadata_length >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN))
+ return false;
+ if(!FLAC__bitwriter_write_raw_uint32(bw, metadata_length, 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(metadata->data.stream_info.total_samples >= (FLAC__U64L(1) << FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN)){
+ if(!FLAC__bitwriter_write_raw_uint64(bw, 0, FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN))
+ return false;
+ }else{
+ 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(update_vendor_string) {
+ 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;
+ }
+ else {
+ if(!FLAC__bitwriter_write_raw_uint32_little_endian(bw, metadata->data.vorbis_comment.vendor_string.length))
+ return false;
+ if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.vorbis_comment.vendor_string.entry, metadata->data.vorbis_comment.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 *indx = track->indices + j;
+
+ if(!FLAC__bitwriter_write_raw_uint64(bw, indx->offset, FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN))
+ return false;
+ if(!FLAC__bitwriter_write_raw_uint32(bw, indx->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;
+ }
+
+ /* Now check whether metadata block length was correct */
+ {
+ uint32_t length_in_bits = FLAC__bitwriter_get_input_bits_unconsumed(bw);
+ if(length_in_bits < start_bits)
+ return false;
+ length_in_bits -= start_bits;
+ if(length_in_bits % 8 != 0 || length_in_bits != (metadata_length*8+32))
+ return false;
+ }
+
+ FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(bw));
+ return true;
+}
+
+FLAC__bool FLAC__frame_add_header(const FLAC__FrameHeader *header, FLAC__BitWriter *bw)
+{
+ uint32_t 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 <= 655350 && 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;
+ case 32: u = 7; 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, uint32_t subframe_bps, uint32_t 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_int64(bw, subframe->value, subframe_bps)
+ ;
+
+ return ok;
+}
+
+FLAC__bool FLAC__subframe_add_fixed(const FLAC__Subframe_Fixed *subframe, uint32_t residual_samples, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw)
+{
+ uint32_t 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_int64(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, uint32_t residual_samples, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw)
+{
+ uint32_t 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_int64(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, uint32_t samples, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw)
+{
+ uint32_t i;
+
+ 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;
+
+ if(subframe->data_type == FLAC__VERBATIM_SUBFRAME_DATA_TYPE_INT32) {
+ const FLAC__int32 *signal = subframe->data.int32;
+
+ FLAC__ASSERT(subframe_bps < 33);
+
+ for(i = 0; i < samples; i++)
+ if(!FLAC__bitwriter_write_raw_int32(bw, signal[i], subframe_bps))
+ return false;
+ }
+ else {
+ const FLAC__int64 *signal = subframe->data.int64;
+
+ FLAC__ASSERT(subframe_bps == 33);
+
+ for(i = 0; i < samples; i++)
+ if(!FLAC__bitwriter_write_raw_int64(bw, (FLAC__int64)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 uint32_t residual_samples, const uint32_t predictor_order, const uint32_t rice_parameters[], const uint32_t raw_bits[], const uint32_t partition_order, const FLAC__bool is_extended)
+{
+ const uint32_t plen = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN;
+ const uint32_t pesc = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
+
+ if(partition_order == 0) {
+ uint32_t 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 {
+ uint32_t i, j, k = 0, k_last = 0;
+ uint32_t partition_samples;
+ const uint32_t 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/stream_encoder_intrin_avx2.c b/src/libFLAC/stream_encoder_intrin_avx2.c
new file mode 100644
index 0000000..b37efb3
--- /dev/null
+++ b/src/libFLAC/stream_encoder_intrin_avx2.c
@@ -0,0 +1,146 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "private/cpu.h"
+
+#ifndef FLAC__NO_ASM
+#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
+#include "private/stream_encoder.h"
+#include "private/bitmath.h"
+#ifdef FLAC__AVX2_SUPPORTED
+
+#include <stdlib.h> /* for abs() */
+#include <immintrin.h> /* AVX2 */
+#include "FLAC/assert.h"
+
+FLAC__SSE_TARGET("avx2")
+void FLAC__precompute_partition_info_sums_intrin_avx2(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[],
+ uint32_t residual_samples, uint32_t predictor_order, uint32_t min_partition_order, uint32_t max_partition_order, uint32_t bps)
+{
+ const uint32_t default_partition_samples = (residual_samples + predictor_order) >> max_partition_order;
+ uint32_t partitions = 1u << max_partition_order;
+
+ FLAC__ASSERT(default_partition_samples > predictor_order);
+
+ /* first do max_partition_order */
+ {
+ const uint32_t threshold = 32 - FLAC__bitmath_ilog2(default_partition_samples);
+ uint32_t partition, residual_sample, end = (uint32_t)(-(int32_t)predictor_order);
+
+ if(bps + FLAC__MAX_EXTRA_RESIDUAL_BPS < threshold) {
+ for(partition = residual_sample = 0; partition < partitions; partition++) {
+ __m256i sum256 = _mm256_setzero_si256();
+ __m128i sum128;
+ end += default_partition_samples;
+
+ for( ; (int)residual_sample < (int)end-7; residual_sample+=8) {
+ __m256i res256 = _mm256_abs_epi32(_mm256_loadu_si256((const __m256i*)(const void*)(residual+residual_sample)));
+ sum256 = _mm256_add_epi32(sum256, res256);
+ }
+
+ sum128 = _mm_add_epi32(_mm256_extracti128_si256(sum256, 1), _mm256_castsi256_si128(sum256));
+
+ for( ; (int)residual_sample < (int)end-3; residual_sample+=4) {
+ __m128i res128 = _mm_abs_epi32(_mm_loadu_si128((const __m128i*)(const void*)(residual+residual_sample)));
+ sum128 = _mm_add_epi32(sum128, res128);
+ }
+
+ for( ; residual_sample < end; residual_sample++) {
+ __m128i res128 = _mm_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample]));
+ sum128 = _mm_add_epi32(sum128, res128);
+ }
+
+ sum128 = _mm_add_epi32(sum128, _mm_shuffle_epi32(sum128, _MM_SHUFFLE(1,0,3,2)));
+ sum128 = _mm_add_epi32(sum128, _mm_shufflelo_epi16(sum128, _MM_SHUFFLE(1,0,3,2)));
+ abs_residual_partition_sums[partition] = (FLAC__uint32)_mm_cvtsi128_si32(sum128);
+/* workaround for MSVC bugs (at least versions 2015 and 2017 are affected) */
+#if (defined _MSC_VER) && (defined FLAC__CPU_X86_64)
+ abs_residual_partition_sums[partition] &= 0xFFFFFFFF; /**/
+#endif
+ }
+ }
+ else { /* have to pessimistically use 64 bits for accumulator */
+ for(partition = residual_sample = 0; partition < partitions; partition++) {
+ __m256i sum256 = _mm256_setzero_si256();
+ __m128i sum128;
+ end += default_partition_samples;
+
+ for( ; (int)residual_sample < (int)end-3; residual_sample+=4) {
+ __m128i res128 = _mm_abs_epi32(_mm_loadu_si128((const __m128i*)(const void*)(residual+residual_sample)));
+ __m256i res256 = _mm256_cvtepu32_epi64(res128);
+ sum256 = _mm256_add_epi64(sum256, res256);
+ }
+
+ sum128 = _mm_add_epi64(_mm256_extracti128_si256(sum256, 1), _mm256_castsi256_si128(sum256));
+
+ for( ; (int)residual_sample < (int)end-1; residual_sample+=2) {
+ __m128i res128 = _mm_abs_epi32(_mm_loadl_epi64((const __m128i*)(const void*)(residual+residual_sample)));
+ res128 = _mm_cvtepu32_epi64(res128);
+ sum128 = _mm_add_epi64(sum128, res128);
+ }
+
+ for( ; residual_sample < end; residual_sample++) {
+ __m128i res128 = _mm_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample]));
+ sum128 = _mm_add_epi64(sum128, res128);
+ }
+
+ sum128 = _mm_add_epi64(sum128, _mm_srli_si128(sum128, 8));
+ _mm_storel_epi64((__m128i*)(void*)(abs_residual_partition_sums+partition), sum128);
+ }
+ }
+ }
+
+ /* now merge partitions for lower orders */
+ {
+ uint32_t 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--) {
+ uint32_t 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;
+ }
+ }
+ }
+ _mm256_zeroupper();
+}
+
+#endif /* FLAC__AVX2_SUPPORTED */
+#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
+#endif /* FLAC__NO_ASM */
diff --git a/src/libFLAC/stream_encoder_intrin_sse2.c b/src/libFLAC/stream_encoder_intrin_sse2.c
new file mode 100644
index 0000000..dd25fa6
--- /dev/null
+++ b/src/libFLAC/stream_encoder_intrin_sse2.c
@@ -0,0 +1,159 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "private/cpu.h"
+
+#ifndef FLAC__NO_ASM
+#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
+#include "private/stream_encoder.h"
+#include "private/bitmath.h"
+#ifdef FLAC__SSE2_SUPPORTED
+
+#include <stdlib.h> /* for abs() */
+#include <emmintrin.h> /* SSE2 */
+#include "FLAC/assert.h"
+#include "share/compat.h"
+
+FLAC__SSE_TARGET("sse2")
+static inline __m128i local_abs_epi32(__m128i val)
+{
+ __m128i mask = _mm_srai_epi32(val, 31);
+ val = _mm_xor_si128(val, mask);
+ val = _mm_sub_epi32(val, mask);
+ return val;
+}
+
+
+FLAC__SSE_TARGET("sse2")
+void FLAC__precompute_partition_info_sums_intrin_sse2(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[],
+ uint32_t residual_samples, uint32_t predictor_order, uint32_t min_partition_order, uint32_t max_partition_order, uint32_t bps)
+{
+ const uint32_t default_partition_samples = (residual_samples + predictor_order) >> max_partition_order;
+ uint32_t partitions = 1u << max_partition_order;
+
+ FLAC__ASSERT(default_partition_samples > predictor_order);
+
+ /* first do max_partition_order */
+ {
+ const uint32_t threshold = 32 - FLAC__bitmath_ilog2(default_partition_samples);
+ uint32_t partition, residual_sample, end = (uint32_t)(-(int32_t)predictor_order);
+
+ if(bps + FLAC__MAX_EXTRA_RESIDUAL_BPS < threshold) {
+ for(partition = residual_sample = 0; partition < partitions; partition++) {
+ __m128i mm_sum = _mm_setzero_si128();
+ uint32_t e1, e3;
+ end += default_partition_samples;
+
+ e1 = (residual_sample + 3) & ~3; e3 = end & ~3;
+ if(e1 > end)
+ e1 = end; /* try flac -l 1 -b 16 and you'll be here */
+
+ /* assumption: residual[] is properly aligned so (residual + e1) is properly aligned too and _mm_loadu_si128() is fast */
+ for( ; residual_sample < e1; residual_sample++) {
+ __m128i mm_res = local_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample]));
+ mm_sum = _mm_add_epi32(mm_sum, mm_res);
+ }
+
+ for( ; residual_sample < e3; residual_sample+=4) {
+ __m128i mm_res = local_abs_epi32(_mm_loadu_si128((const __m128i*)(const void*)(residual+residual_sample)));
+ mm_sum = _mm_add_epi32(mm_sum, mm_res);
+ }
+
+ for( ; residual_sample < end; residual_sample++) {
+ __m128i mm_res = local_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample]));
+ mm_sum = _mm_add_epi32(mm_sum, mm_res);
+ }
+
+ mm_sum = _mm_add_epi32(mm_sum, _mm_shuffle_epi32(mm_sum, _MM_SHUFFLE(1,0,3,2)));
+ mm_sum = _mm_add_epi32(mm_sum, _mm_shufflelo_epi16(mm_sum, _MM_SHUFFLE(1,0,3,2)));
+ abs_residual_partition_sums[partition] = (FLAC__uint32)_mm_cvtsi128_si32(mm_sum);
+/* workaround for MSVC bugs (at least versions 2015 and 2017 are affected) */
+#if (defined _MSC_VER) && (defined FLAC__CPU_X86_64)
+ abs_residual_partition_sums[partition] &= 0xFFFFFFFF;
+#endif
+ }
+ }
+ else { /* have to pessimistically use 64 bits for accumulator */
+ for(partition = residual_sample = 0; partition < partitions; partition++) {
+ __m128i mm_sum = _mm_setzero_si128();
+ uint32_t e1, e3;
+ end += default_partition_samples;
+
+ e1 = (residual_sample + 1) & ~1; e3 = end & ~1;
+ FLAC__ASSERT(e1 <= end);
+
+ for( ; residual_sample < e1; residual_sample++) {
+ __m128i mm_res = local_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample])); /* 0 0 0 |r0| == 00 |r0_64| */
+ mm_sum = _mm_add_epi64(mm_sum, mm_res);
+ }
+
+ for( ; residual_sample < e3; residual_sample+=2) {
+ __m128i mm_res = local_abs_epi32(_mm_loadl_epi64((const __m128i*)(const void*)(residual+residual_sample))); /* 0 0 |r1| |r0| */
+ mm_res = _mm_shuffle_epi32(mm_res, _MM_SHUFFLE(3,1,2,0)); /* 0 |r1| 0 |r0| == |r1_64| |r0_64| */
+ mm_sum = _mm_add_epi64(mm_sum, mm_res);
+ }
+
+ for( ; residual_sample < end; residual_sample++) {
+ __m128i mm_res = local_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample]));
+ mm_sum = _mm_add_epi64(mm_sum, mm_res);
+ }
+
+ mm_sum = _mm_add_epi64(mm_sum, _mm_srli_si128(mm_sum, 8));
+ _mm_storel_epi64((__m128i*)(void*)(abs_residual_partition_sums+partition), mm_sum);
+ }
+ }
+ }
+
+ /* now merge partitions for lower orders */
+ {
+ uint32_t 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--) {
+ uint32_t 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;
+ }
+ }
+ }
+}
+
+#endif /* FLAC__SSE2_SUPPORTED */
+#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
+#endif /* FLAC__NO_ASM */
diff --git a/src/libFLAC/stream_encoder_intrin_ssse3.c b/src/libFLAC/stream_encoder_intrin_ssse3.c
new file mode 100644
index 0000000..241f723
--- /dev/null
+++ b/src/libFLAC/stream_encoder_intrin_ssse3.c
@@ -0,0 +1,148 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "private/cpu.h"
+
+#ifndef FLAC__NO_ASM
+#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
+#include "private/stream_encoder.h"
+#include "private/bitmath.h"
+#ifdef FLAC__SSSE3_SUPPORTED
+
+#include <stdlib.h> /* for abs() */
+#include <tmmintrin.h> /* SSSE3 */
+#include "FLAC/assert.h"
+
+FLAC__SSE_TARGET("ssse3")
+void FLAC__precompute_partition_info_sums_intrin_ssse3(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[],
+ uint32_t residual_samples, uint32_t predictor_order, uint32_t min_partition_order, uint32_t max_partition_order, uint32_t bps)
+{
+ const uint32_t default_partition_samples = (residual_samples + predictor_order) >> max_partition_order;
+ uint32_t partitions = 1u << max_partition_order;
+
+ FLAC__ASSERT(default_partition_samples > predictor_order);
+
+ /* first do max_partition_order */
+ {
+ const uint32_t threshold = 32 - FLAC__bitmath_ilog2(default_partition_samples);
+ uint32_t partition, residual_sample, end = (uint32_t)(-(int32_t)predictor_order);
+
+ if(bps + FLAC__MAX_EXTRA_RESIDUAL_BPS < threshold) {
+ for(partition = residual_sample = 0; partition < partitions; partition++) {
+ __m128i mm_sum = _mm_setzero_si128();
+ uint32_t e1, e3;
+ end += default_partition_samples;
+
+ e1 = (residual_sample + 3) & ~3; e3 = end & ~3;
+ if(e1 > end)
+ e1 = end; /* try flac -l 1 -b 16 and you'll be here */
+
+ /* assumption: residual[] is properly aligned so (residual + e1) is properly aligned too and _mm_loadu_si128() is fast */
+ for( ; residual_sample < e1; residual_sample++) {
+ __m128i mm_res = _mm_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample]));
+ mm_sum = _mm_add_epi32(mm_sum, mm_res);
+ }
+
+ for( ; residual_sample < e3; residual_sample+=4) {
+ __m128i mm_res = _mm_abs_epi32(_mm_loadu_si128((const __m128i*)(const void*)(residual+residual_sample)));
+ mm_sum = _mm_add_epi32(mm_sum, mm_res);
+ }
+
+ for( ; residual_sample < end; residual_sample++) {
+ __m128i mm_res = _mm_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample]));
+ mm_sum = _mm_add_epi32(mm_sum, mm_res);
+ }
+
+ mm_sum = _mm_add_epi32(mm_sum, _mm_shuffle_epi32(mm_sum, _MM_SHUFFLE(1,0,3,2)));
+ mm_sum = _mm_add_epi32(mm_sum, _mm_shufflelo_epi16(mm_sum, _MM_SHUFFLE(1,0,3,2)));
+ abs_residual_partition_sums[partition] = (FLAC__uint32)_mm_cvtsi128_si32(mm_sum);
+/* workaround for MSVC bugs (at least versions 2015 and 2017 are affected) */
+#if (defined _MSC_VER) && (defined FLAC__CPU_X86_64)
+ abs_residual_partition_sums[partition] &= 0xFFFFFFFF;
+#endif
+ }
+ }
+ else { /* have to pessimistically use 64 bits for accumulator */
+ for(partition = residual_sample = 0; partition < partitions; partition++) {
+ __m128i mm_sum = _mm_setzero_si128();
+ uint32_t e1, e3;
+ end += default_partition_samples;
+
+ e1 = (residual_sample + 1) & ~1; e3 = end & ~1;
+ FLAC__ASSERT(e1 <= end);
+
+ for( ; residual_sample < e1; residual_sample++) {
+ __m128i mm_res = _mm_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample])); /* 0 0 0 |r0| == 00 |r0_64| */
+ mm_sum = _mm_add_epi64(mm_sum, mm_res);
+ }
+
+ for( ; residual_sample < e3; residual_sample+=2) {
+ __m128i mm_res = _mm_abs_epi32(_mm_loadl_epi64((const __m128i*)(const void*)(residual+residual_sample))); /* 0 0 |r1| |r0| */
+ mm_res = _mm_shuffle_epi32(mm_res, _MM_SHUFFLE(3,1,2,0)); /* 0 |r1| 0 |r0| == |r1_64| |r0_64| */
+ mm_sum = _mm_add_epi64(mm_sum, mm_res);
+ }
+
+ for( ; residual_sample < end; residual_sample++) {
+ __m128i mm_res = _mm_abs_epi32(_mm_cvtsi32_si128(residual[residual_sample]));
+ mm_sum = _mm_add_epi64(mm_sum, mm_res);
+ }
+
+ mm_sum = _mm_add_epi64(mm_sum, _mm_srli_si128(mm_sum, 8));
+ _mm_storel_epi64((__m128i*)(void*)(abs_residual_partition_sums+partition), mm_sum);
+ }
+ }
+ }
+
+ /* now merge partitions for lower orders */
+ {
+ uint32_t 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--) {
+ uint32_t 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;
+ }
+ }
+ }
+}
+
+#endif /* FLAC__SSSE3_SUPPORTED */
+#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
+#endif /* FLAC__NO_ASM */
diff --git a/src/libFLAC/version.rc b/src/libFLAC/version.rc
new file mode 100644
index 0000000..019da1d
--- /dev/null
+++ b/src/libFLAC/version.rc
@@ -0,0 +1,40 @@
+#include <winver.h>
+#include "config.h"
+#include "FLAC/export.h"
+
+#if (defined GIT_COMMIT_HASH && defined GIT_COMMIT_DATE)
+# ifdef GIT_COMMIT_TAG
+# define VERSIONSTRING GIT_COMMIT_TAG
+# else
+# define VERSIONSTRING "git-" GIT_COMMIT_HASH
+# endif
+#else
+# define VERSIONSTRING PACKAGE_VERSION
+#endif
+
+#define xstr(s) str(s)
+#define str(s) #s
+
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION FLAC_API_VERSION_CURRENT,FLAC_API_VERSION_REVISION,0,0
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+FILEFLAGS 0
+FILEOS VOS__WINDOWS32
+FILETYPE VFT_DLL
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "FileDescription", "libFLAC for Windows"
+ VALUE "ProductName", "Free Lossless Audio Codec"
+ VALUE "ProductVersion", VERSIONSTRING
+ VALUE "CompanyName", "Xiph.Org"
+ VALUE "LegalCopyright", "2000-2009 Josh Coalson, 2011-2023 Xiph.Org Foundation"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/src/libFLAC/window.c b/src/libFLAC/window.c
new file mode 100644
index 0000000..69d5464
--- /dev/null
+++ b/src/libFLAC/window.c
@@ -0,0 +1,308 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2006-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <math.h>
+#include "share/compat.h"
+#include "FLAC/assert.h"
+#include "FLAC/format.h"
+#include "private/window.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+#if defined(_MSC_VER)
+// silence 25 MSVC warnings 'conversion from 'double' to 'float', possible loss of data'
+#pragma warning ( disable : 4244 )
+#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 / (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 * fabsf((float)n/(float)N-0.5f) - 0.38f * cosf(2.0f * M_PI * ((float)n/(float)N)));
+}
+
+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 * cosf(2.0f * M_PI * n / N) + 0.08f * cosf(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 * cosf(2.0f * M_PI * n / N) + 0.14128f * cosf(4.0f * M_PI * n / N) - 0.01168f * cosf(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)(0.21557895f - 0.41663158f * cosf(2.0f * M_PI * n / N) + 0.277263158f * cosf(4.0f * M_PI * n / N) - 0.083578947f * cosf(6.0f * M_PI * n / N) + 0.006947368f * cosf(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;
+
+ if(!(stddev > 0.0f && stddev <= 0.5f))
+ /* stddev is not between 0 and 0.5, might be NaN.
+ * Default to 0.5 */
+ FLAC__window_gauss(window, L, 0.25f);
+ else {
+ 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 * cosf(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 * cosf(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 * cosf(2.0f * M_PI * n / N) + 0.098f * cosf(4.0f * M_PI * n / N) - 0.001f * cosf(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*cosf(2.0f*M_PI*n/N) + 0.1365995f*cosf(4.0f*M_PI*n/N) - 0.0106411f*cosf(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 + 1.0f);
+ for (; n <= L; n++)
+ window[n-1] = (float)(2 * (L - n + 1)) / ((float)L + 1.0f);
+ }
+}
+
+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 if (!(p > 0.0f && p < 1.0f))
+ /* p is not between 0 and 1, probably NaN.
+ * Default to 0.5 */
+ FLAC__window_tukey(window, L, 0.5f);
+ 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 * cosf(M_PI * n / Np));
+ window[L-Np-1+n] = (FLAC__real)(0.5f - 0.5f * cosf(M_PI * (n+Np) / Np));
+ }
+ }
+ }
+}
+
+void FLAC__window_partial_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end)
+{
+ const FLAC__int32 start_n = (FLAC__int32)(start * L);
+ const FLAC__int32 end_n = (FLAC__int32)(end * L);
+ const FLAC__int32 N = end_n - start_n;
+ FLAC__int32 Np, n, i;
+
+ if (p <= 0.0f)
+ FLAC__window_partial_tukey(window, L, 0.05f, start, end);
+ else if (p >= 1.0f)
+ FLAC__window_partial_tukey(window, L, 0.95f, start, end);
+ else if (!(p > 0.0f && p < 1.0f))
+ /* p is not between 0 and 1, probably NaN.
+ * Default to 0.5 */
+ FLAC__window_partial_tukey(window, L, 0.5f, start, end);
+ else {
+
+ Np = (FLAC__int32)(p / 2.0f * N);
+
+ for (n = 0; n < start_n && n < L; n++)
+ window[n] = 0.0f;
+ for (i = 1; n < (start_n+Np) && n < L; n++, i++)
+ window[n] = (FLAC__real)(0.5f - 0.5f * cosf(M_PI * i / Np));
+ for (; n < (end_n-Np) && n < L; n++)
+ window[n] = 1.0f;
+ for (i = Np; n < end_n && n < L; n++, i--)
+ window[n] = (FLAC__real)(0.5f - 0.5f * cosf(M_PI * i / Np));
+ for (; n < L; n++)
+ window[n] = 0.0f;
+ }
+}
+
+void FLAC__window_punchout_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end)
+{
+ const FLAC__int32 start_n = (FLAC__int32)(start * L);
+ const FLAC__int32 end_n = (FLAC__int32)(end * L);
+ FLAC__int32 Ns, Ne, n, i;
+
+ if (p <= 0.0f)
+ FLAC__window_punchout_tukey(window, L, 0.05f, start, end);
+ else if (p >= 1.0f)
+ FLAC__window_punchout_tukey(window, L, 0.95f, start, end);
+ else if (!(p > 0.0f && p < 1.0f))
+ /* p is not between 0 and 1, probably NaN.
+ * Default to 0.5 */
+ FLAC__window_punchout_tukey(window, L, 0.5f, start, end);
+ else {
+
+ Ns = (FLAC__int32)(p / 2.0f * start_n);
+ Ne = (FLAC__int32)(p / 2.0f * (L - end_n));
+
+ for (n = 0, i = 1; n < Ns && n < L; n++, i++)
+ window[n] = (FLAC__real)(0.5f - 0.5f * cosf(M_PI * i / Ns));
+ for (; n < start_n-Ns && n < L; n++)
+ window[n] = 1.0f;
+ for (i = Ns; n < start_n && n < L; n++, i--)
+ window[n] = (FLAC__real)(0.5f - 0.5f * cosf(M_PI * i / Ns));
+ for (; n < end_n && n < L; n++)
+ window[n] = 0.0f;
+ for (i = 1; n < end_n+Ne && n < L; n++, i++)
+ window[n] = (FLAC__real)(0.5f - 0.5f * cosf(M_PI * i / Ne));
+ for (; n < L - (Ne) && n < L; n++)
+ window[n] = 1.0f;
+ for (i = Ne; n < L; n++, i--)
+ window[n] = (FLAC__real)(0.5f - 0.5f * cosf(M_PI * i / Ne));
+ }
+}
+
+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);
+ }
+}
+
+#if defined(_MSC_VER)
+#pragma warning ( default : 4244 )
+#endif
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/src/metaflac/CMakeLists.txt b/src/metaflac/CMakeLists.txt
new file mode 100644
index 0000000..b8af705
--- /dev/null
+++ b/src/metaflac/CMakeLists.txt
@@ -0,0 +1,18 @@
+add_executable(metaflac
+ 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
+ version.rc
+ $<$<BOOL:${WIN32}>:../../include/share/win_utf8_io.h>
+ $<$<BOOL:${WIN32}>:../share/win_utf8_io/win_utf8_io.c>)
+target_link_libraries(metaflac FLAC getopt utf8)
+
+install(TARGETS metaflac EXPORT targets
+ RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
diff --git a/src/metaflac/Makefile.am b/src/metaflac/Makefile.am
new file mode 100644
index 0000000..8c212ff
--- /dev/null
+++ b/src/metaflac/Makefile.am
@@ -0,0 +1,65 @@
+# metaflac - Command-line FLAC metadata editor
+# Copyright (C) 2000-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+if OS_IS_WINDOWS
+win_utf8_lib = $(top_builddir)/src/share/win_utf8_io/libwin_utf8_io.la
+if HAVE_WINDRES
+metaflac_DEPENDENCIES = version.o
+windows_resource_link = -Wl,version.o
+endif
+endif
+
+bin_PROGRAMS = metaflac
+
+AM_CFLAGS = @OGG_CFLAGS@
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+EXTRA_DIST = \
+ CMakeLists.txt \
+ version.rc
+
+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 = $(AM_LDFLAGS) $(windows_resource_link)
+
+metaflac_LDADD = \
+ $(top_builddir)/src/share/grabbag/libgrabbag.la \
+ $(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \
+ $(top_builddir)/src/share/getopt/libgetopt.la \
+ $(top_builddir)/src/share/utf8/libutf8.la \
+ $(top_builddir)/src/libFLAC/libFLAC.la \
+ $(win_utf8_lib) \
+ @LTLIBICONV@
+
+CLEANFILES = metaflac.exe
+
+.rc.o:
+ $(RC) $(AM_CPPFLAGS) $< $@
diff --git a/src/metaflac/Makefile.in b/src/metaflac/Makefile.in
new file mode 100644
index 0000000..dae2fae
--- /dev/null
+++ b/src/metaflac/Makefile.in
@@ -0,0 +1,789 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in 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.
+
+@SET_MAKE@
+
+# metaflac - Command-line FLAC metadata editor
+# Copyright (C) 2000-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@HAVE_WINDRES_FALSE@metaflac_DEPENDENCIES = $(top_builddir)/src/share/grabbag/libgrabbag.la \
+@HAVE_WINDRES_FALSE@ $(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \
+@HAVE_WINDRES_FALSE@ $(top_builddir)/src/share/getopt/libgetopt.la \
+@HAVE_WINDRES_FALSE@ $(top_builddir)/src/share/utf8/libutf8.la \
+@HAVE_WINDRES_FALSE@ $(top_builddir)/src/libFLAC/libFLAC.la \
+@HAVE_WINDRES_FALSE@ $(win_utf8_lib)
+@OS_IS_WINDOWS_FALSE@metaflac_DEPENDENCIES = $(top_builddir)/src/share/grabbag/libgrabbag.la \
+@OS_IS_WINDOWS_FALSE@ $(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \
+@OS_IS_WINDOWS_FALSE@ $(top_builddir)/src/share/getopt/libgetopt.la \
+@OS_IS_WINDOWS_FALSE@ $(top_builddir)/src/share/utf8/libutf8.la \
+@OS_IS_WINDOWS_FALSE@ $(top_builddir)/src/libFLAC/libFLAC.la \
+@OS_IS_WINDOWS_FALSE@ $(win_utf8_lib)
+bin_PROGRAMS = metaflac$(EXEEXT)
+subdir = src/metaflac
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/add_cflags.m4 \
+ $(top_srcdir)/m4/add_cxxflags.m4 \
+ $(top_srcdir)/m4/ax_add_fortify_source.m4 \
+ $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_enable_debug.m4 \
+ $(top_srcdir)/m4/bswap.m4 $(top_srcdir)/m4/clang.m4 \
+ $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gcc_version.m4 \
+ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/ogg.m4 \
+ $(top_srcdir)/m4/really_gcc.m4 \
+ $(top_srcdir)/m4/stack_protect.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)"
+PROGRAMS = $(bin_PROGRAMS)
+am_metaflac_OBJECTS = main.$(OBJEXT) operations.$(OBJEXT) \
+ operations_shorthand_cuesheet.$(OBJEXT) \
+ operations_shorthand_picture.$(OBJEXT) \
+ operations_shorthand_seektable.$(OBJEXT) \
+ operations_shorthand_streaminfo.$(OBJEXT) \
+ operations_shorthand_vorbiscomment.$(OBJEXT) options.$(OBJEXT) \
+ usage.$(OBJEXT) utils.$(OBJEXT)
+metaflac_OBJECTS = $(am_metaflac_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+metaflac_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(metaflac_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/main.Po ./$(DEPDIR)/operations.Po \
+ ./$(DEPDIR)/operations_shorthand_cuesheet.Po \
+ ./$(DEPDIR)/operations_shorthand_picture.Po \
+ ./$(DEPDIR)/operations_shorthand_seektable.Po \
+ ./$(DEPDIR)/operations_shorthand_streaminfo.Po \
+ ./$(DEPDIR)/operations_shorthand_vorbiscomment.Po \
+ ./$(DEPDIR)/options.Po ./$(DEPDIR)/usage.Po \
+ ./$(DEPDIR)/utils.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(metaflac_SOURCES)
+DIST_SOURCES = $(metaflac_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_64_BIT_WORDS = @ENABLE_64_BIT_WORDS@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLAC__HAS_OGG = @FLAC__HAS_OGG@
+FLAC__TEST_LEVEL = @FLAC__TEST_LEVEL@
+FLAC__TEST_WITH_VALGRIND = @FLAC__TEST_WITH_VALGRIND@
+GCC_MAJOR_VERSION = @GCC_MAJOR_VERSION@
+GCC_MINOR_VERSION = @GCC_MINOR_VERSION@
+GCC_VERSION = @GCC_VERSION@
+GIT_COMMIT_VERSION_HASH = @GIT_COMMIT_VERSION_HASH@
+GIT_FOUND = @GIT_FOUND@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_FUZZING_ENGINE = @LIB_FUZZING_ENGINE@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OBJ_FORMAT = @OBJ_FORMAT@
+OGG_CFLAGS = @OGG_CFLAGS@
+OGG_LIBS = @OGG_LIBS@
+OGG_PACKAGE = @OGG_PACKAGE@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@OS_IS_WINDOWS_TRUE@win_utf8_lib = $(top_builddir)/src/share/win_utf8_io/libwin_utf8_io.la
+@HAVE_WINDRES_TRUE@@OS_IS_WINDOWS_TRUE@metaflac_DEPENDENCIES = version.o
+@HAVE_WINDRES_TRUE@@OS_IS_WINDOWS_TRUE@windows_resource_link = -Wl,version.o
+AM_CFLAGS = @OGG_CFLAGS@
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+EXTRA_DIST = \
+ CMakeLists.txt \
+ version.rc
+
+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 = $(AM_LDFLAGS) $(windows_resource_link)
+metaflac_LDADD = \
+ $(top_builddir)/src/share/grabbag/libgrabbag.la \
+ $(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \
+ $(top_builddir)/src/share/getopt/libgetopt.la \
+ $(top_builddir)/src/share/utf8/libutf8.la \
+ $(top_builddir)/src/libFLAC/libFLAC.la \
+ $(win_utf8_lib) \
+ @LTLIBICONV@
+
+CLEANFILES = metaflac.exe
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj .rc
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/metaflac/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/metaflac/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ || test -f $$p1 \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+metaflac$(EXEEXT): $(metaflac_OBJECTS) $(metaflac_DEPENDENCIES) $(EXTRA_metaflac_DEPENDENCIES)
+ @rm -f metaflac$(EXEEXT)
+ $(AM_V_CCLD)$(metaflac_LINK) $(metaflac_OBJECTS) $(metaflac_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/operations.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/operations_shorthand_cuesheet.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/operations_shorthand_picture.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/operations_shorthand_seektable.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/operations_shorthand_streaminfo.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/operations_shorthand_vorbiscomment.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/usage.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/main.Po
+ -rm -f ./$(DEPDIR)/operations.Po
+ -rm -f ./$(DEPDIR)/operations_shorthand_cuesheet.Po
+ -rm -f ./$(DEPDIR)/operations_shorthand_picture.Po
+ -rm -f ./$(DEPDIR)/operations_shorthand_seektable.Po
+ -rm -f ./$(DEPDIR)/operations_shorthand_streaminfo.Po
+ -rm -f ./$(DEPDIR)/operations_shorthand_vorbiscomment.Po
+ -rm -f ./$(DEPDIR)/options.Po
+ -rm -f ./$(DEPDIR)/usage.Po
+ -rm -f ./$(DEPDIR)/utils.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/main.Po
+ -rm -f ./$(DEPDIR)/operations.Po
+ -rm -f ./$(DEPDIR)/operations_shorthand_cuesheet.Po
+ -rm -f ./$(DEPDIR)/operations_shorthand_picture.Po
+ -rm -f ./$(DEPDIR)/operations_shorthand_seektable.Po
+ -rm -f ./$(DEPDIR)/operations_shorthand_streaminfo.Po
+ -rm -f ./$(DEPDIR)/operations_shorthand_vorbiscomment.Po
+ -rm -f ./$(DEPDIR)/options.Po
+ -rm -f ./$(DEPDIR)/usage.Po
+ -rm -f ./$(DEPDIR)/utils.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-binPROGRAMS clean-generic clean-libtool cscopelist-am \
+ ctags ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-binPROGRAMS \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am uninstall-binPROGRAMS
+
+.PRECIOUS: Makefile
+
+
+.rc.o:
+ $(RC) $(AM_CPPFLAGS) $< $@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/metaflac/main.c b/src/metaflac/main.c
new file mode 100644
index 0000000..bb66293
--- /dev/null
+++ b/src/metaflac/main.c
@@ -0,0 +1,75 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "operations.h"
+#include "options.h"
+#include <locale.h>
+#include <stdlib.h>
+#include <string.h>
+#include "share/compat.h"
+
+#ifndef FUZZ_TOOL_METAFLAC
+int main(int argc, char *argv[])
+#else
+static int main_to_fuzz(int argc, char *argv[])
+#endif
+{
+ CommandLineOptions options;
+ int ret = 0;
+
+#ifdef __EMX__
+ _response(&argc, &argv);
+ _wildcard(&argc, &argv);
+#endif
+#ifdef _WIN32
+ if (get_utf8_argv(&argc, &argv) != 0) {
+ fputs("ERROR: failed to convert command line parameters to UTF-8\n", stderr);
+ return 1;
+ }
+#endif
+
+#ifdef _WIN32
+ {
+ const char *var;
+ var = getenv("LC_ALL");
+ if (!var)
+ var = getenv("LC_NUMERIC");
+ if (!var)
+ var = getenv("LANG");
+ if (!var || strcmp(var, "C") != 0)
+ setlocale(LC_ALL, "");
+ }
+#else
+ setlocale(LC_ALL, "");
+#endif
+ init_options(&options);
+
+ if ((ret = parse_options(argc, argv, &options)) == 0)
+ ret = !do_operations(&options);
+ else
+ ret = 1;
+
+ free_options(&options);
+
+ return ret;
+}
diff --git a/src/metaflac/operations.c b/src/metaflac/operations.c
new file mode 100644
index 0000000..d81d87a
--- /dev/null
+++ b/src/metaflac/operations.c
@@ -0,0 +1,823 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "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 "share/compat.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, FLAC__bool scan);
+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);
+static void write_metadata_binary(FLAC__StreamMetadata *block, FLAC__byte *block_raw, FLAC__bool headerless);
+
+/* 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)
+ flac_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)) {
+ if(!options->data_format_is_binary && !options->data_format_is_binary_headerless)
+ write_metadata(filename, block, block_number, !options->utf8_convert, options->application_data_format_is_hexdump);
+ else {
+ FLAC__byte * block_raw = FLAC__metadata_object_get_raw(block);
+ if(block_raw == 0) {
+ flac_fprintf(stderr, "%s: ERROR: couldn't get block in raw form\n", filename);
+ FLAC__metadata_iterator_delete(iterator);
+ return false;
+ }
+ write_metadata_binary(block, block_raw, options->data_format_is_binary_headerless);
+ free(block_raw);
+ }
+ }
+ 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)
+{
+ FLAC__byte header[FLAC__STREAM_METADATA_HEADER_LENGTH];
+ FLAC__byte *buffer;
+ FLAC__uint32 buffer_size, num_objects = 0, i, append_after = UINT32_MAX;
+ FLAC__StreamMetadata *object;
+ FLAC__Metadata_Iterator *iterator = 0;
+ FLAC__bool has_vorbiscomment = false;
+
+ /* First, find out after which block appending should take place */
+ for(i = 0; i < options->args.num_arguments; i++) {
+ if(options->args.arguments[i].type == ARG__BLOCK_NUMBER) {
+ if(append_after != UINT32_MAX || options->args.arguments[i].value.block_number.num_entries > 1) {
+ flac_fprintf(stderr, "ERROR: more than one block number specified with --append\n");
+ return false;
+ }
+ append_after = options->args.arguments[i].value.block_number.entries[0];
+ }
+ }
+
+ iterator = FLAC__metadata_iterator_new();
+
+ if(0 == iterator)
+ die("out of memory allocating iterator");
+
+ FLAC__metadata_iterator_init(iterator, chain);
+
+ /* Find out whether there is already a vorbis comment block present */
+ do {
+ FLAC__MetadataType type = FLAC__metadata_iterator_get_block_type(iterator);
+ if(type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
+ has_vorbiscomment = true;
+ }
+ while(FLAC__metadata_iterator_next(iterator));
+
+ /* Reset iterator */
+ FLAC__metadata_iterator_init(iterator, chain);
+
+ /* Go to requested block */
+ for(i = 0; i < append_after; i++) {
+ if(!FLAC__metadata_iterator_next(iterator))
+ break;
+ }
+
+#ifdef _WIN32
+ _setmode(fileno(stdin),_O_BINARY);
+#endif
+
+ /* Read header from stdin */
+ while(fread(header, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, stdin) == FLAC__STREAM_METADATA_HEADER_LENGTH) {
+
+ buffer_size = ((FLAC__uint32)(header[1]) << 16) + ((FLAC__uint32)(header[2]) << 8) + header[3];
+ buffer = safe_malloc_(buffer_size + FLAC__STREAM_METADATA_HEADER_LENGTH);
+ if(0 == buffer)
+ die("out of memory allocating read buffer");
+ memcpy(buffer, header, FLAC__STREAM_METADATA_HEADER_LENGTH);
+
+ num_objects++;
+
+ if(fread(buffer+FLAC__STREAM_METADATA_HEADER_LENGTH, 1, buffer_size, stdin) < buffer_size) {
+ flac_fprintf(stderr, "ERROR: couldn't read metadata block #%u from stdin\n",(num_objects));
+ free(buffer);
+ FLAC__metadata_iterator_delete(iterator);
+ return false;
+ }
+
+ if((object = FLAC__metadata_object_set_raw(buffer, buffer_size + FLAC__STREAM_METADATA_HEADER_LENGTH)) == NULL) {
+ flac_fprintf(stderr, "ERROR: couldn't parse supplied metadata block #%u\n",(num_objects));
+ free(buffer);
+ FLAC__metadata_iterator_delete(iterator);
+ return false;
+ }
+ free(buffer);
+
+ if(has_vorbiscomment && object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
+ flac_fprintf(stderr, "ERROR: can't add another vorbis comment block to file, it already has one\n");
+ FLAC__metadata_object_delete(object);
+ FLAC__metadata_iterator_delete(iterator);
+ return false;
+ }
+
+
+ if(object->type == FLAC__METADATA_TYPE_STREAMINFO) {
+ flac_fprintf(stderr, "ERROR: can't add streaminfo to file\n");
+ FLAC__metadata_object_delete(object);
+ FLAC__metadata_iterator_delete(iterator);
+ return false;
+ }
+
+ if(object->type == FLAC__METADATA_TYPE_SEEKTABLE) {
+ flac_fprintf(stderr, "ERROR: can't add seektable to file, please use --add-seekpoint instead\n");
+ FLAC__metadata_object_delete(object);
+ FLAC__metadata_iterator_delete(iterator);
+ return false;
+ }
+
+ if(!FLAC__metadata_iterator_insert_block_after(iterator, object)) {
+ flac_fprintf(stderr, "ERROR: couldn't add supplied metadata block #%u to file\n",(num_objects));
+ FLAC__metadata_object_delete(object);
+ FLAC__metadata_iterator_delete(iterator);
+ return false;
+ }
+ /* Now check whether what type of block was added */
+ {
+ FLAC__MetadataType type = FLAC__metadata_iterator_get_block_type(iterator);
+ if(type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
+ has_vorbiscomment = true;
+ }
+ }
+
+#ifdef _WIN32
+ _setmode(fileno(stdin),_O_TEXT);
+#endif
+
+ if(num_objects == 0)
+ flac_fprintf(stderr, "ERROR: unable to find a metadata block in the supplied input\n");
+
+ FLAC__metadata_iterator_delete(iterator);
+
+ return true;
+}
+
+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, false);
+ else if(options->ops.operations[i].type == OP__SCAN_REPLAY_GAIN)
+ ok = do_shorthand_operation__add_replay_gain(options->filenames, options->num_files, options->preserve_modtime, true);
+ }
+ }
+
+ 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);
+ ok = false;
+ goto cleanup;
+ }
+
+ 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);
+ }
+
+ cleanup :
+ 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_ALL_EXCEPT:
+ 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:
+ case OP__SCAN_REPLAY_GAIN:
+ /* these commands are 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__bool scan)
+{
+ 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)) {
+ flac_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) {
+ flac_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) {
+ flac_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) {
+ flac_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)) {
+ flac_fprintf(stderr, "%s: ERROR: sample rate of %u Hz is not supported\n", filenames[i], sample_rate);
+ return false;
+ }
+ if(channels != 1 && channels != 2) {
+ flac_fprintf(stderr, "%s: ERROR: # of channels (%u) is not supported, must be 1 or 2\n", filenames[i], channels);
+ return false;
+ }
+ if(bits_per_sample < FLAC__MIN_BITS_PER_SAMPLE || bits_per_sample > FLAC__MAX_BITS_PER_SAMPLE) {
+ flac_fprintf(stderr, "%s: ERROR: resolution (%u) is not supported, must be between %u and %u\n", filenames[i], bits_per_sample, FLAC__MIN_BITS_PER_SAMPLE, FLAC__MAX_BITS_PER_SAMPLE);
+ return false;
+ }
+ }
+
+ if(!grabbag__replaygain_init(sample_rate)) {
+ FLAC__ASSERT(0);
+ /* double protection */
+ flac_fprintf(stderr, "internal error\n");
+ return false;
+ }
+
+ if(
+ 0 == (title_gains = safe_malloc_mul_2op_(sizeof(float), /*times*/num_files)) ||
+ 0 == (title_peaks = 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))) {
+ flac_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(!scan) {
+ if(0 != (error = grabbag__replaygain_store_to_file(filenames[i], album_gain, album_peak, title_gains[i], title_peaks[i], preserve_modtime))) {
+ flac_fprintf(stderr, "%s: ERROR: writing tags (%s)\n", filenames[i], error);
+ free(title_gains);
+ free(title_peaks);
+ return false;
+ }
+ } else {
+ flac_fprintf(stdout, "%s: %f %f %f %f\n", filenames[i], album_gain, album_peak, title_gains[i], title_peaks[i]);
+ }
+ }
+
+ 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) { if(raw) printf("%s:",filename); else flac_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);
+ PPR; printf(" total samples: %" PRIu64 "\n", block->data.stream_info.total_samples);
+ 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) {
+ PPR; printf(" point %u: sample_number=%" PRIu64 ", stream_offset=%" PRIu64 ", 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: 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);
+ PPR; printf(" lead-in: %" PRIu64 "\n", block->data.cue_sheet.lead_in);
+ 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);
+ PPR; printf(" offset: %" PRIu64 "\n", track->offset);
+ 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 *indx = track->indices+j;
+ PPR; printf(" index[%u]\n", j);
+ PPR; printf(" offset: %" PRIu64 "\n", indx->offset);
+ PPR; printf(" number: %u\n", (unsigned)indx->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
+}
+
+void write_metadata_binary(FLAC__StreamMetadata *block, FLAC__byte *block_raw, FLAC__bool headerless)
+{
+#ifdef _WIN32
+ fflush(stdout);
+ _setmode(fileno(stdout),_O_BINARY);
+#endif
+ if(!headerless)
+ local_fwrite(block_raw, 1, block->length+FLAC__STREAM_METADATA_HEADER_LENGTH, stdout);
+ else if(block->type == FLAC__METADATA_TYPE_APPLICATION && block->length > 3)
+ local_fwrite(block_raw+FLAC__STREAM_METADATA_HEADER_LENGTH+4, 1, block->length-4, stdout);
+ else
+ local_fwrite(block_raw+FLAC__STREAM_METADATA_HEADER_LENGTH, 1, block->length, stdout);
+#ifdef _WIN32
+ fflush(stdout);
+ _setmode(fileno(stdout),_O_TEXT);
+#endif
+}
diff --git a/src/metaflac/operations.h b/src/metaflac/operations.h
new file mode 100644
index 0000000..79e1c3b
--- /dev/null
+++ b/src/metaflac/operations.h
@@ -0,0 +1,27 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#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
index 0000000..1877c26
--- /dev/null
+++ b/src/metaflac/operations_shorthand.h
@@ -0,0 +1,26 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#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
index 0000000..13c4ded
--- /dev/null
+++ b/src/metaflac/operations_shorthand_cuesheet.c
@@ -0,0 +1,226 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include "options.h"
+#include "utils.h"
+#include "FLAC/assert.h"
+#include "share/grabbag.h"
+#include "share/compat.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, unsigned sample_rate, 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;
+ unsigned sample_rate = 0;
+
+ 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) {
+ flac_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;
+ }
+ sample_rate = block->data.stream_info.sample_rate;
+ is_cdda = (block->data.stream_info.channels == 1 || block->data.stream_info.channels == 2) && (block->data.stream_info.bits_per_sample == 16) && (sample_rate == 44100);
+ }
+ else if(block->type == FLAC__METADATA_TYPE_CUESHEET)
+ cuesheet = block;
+ } while(FLAC__metadata_iterator_next(iterator));
+
+ if(lead_out_offset == 0) {
+ flac_fprintf(stderr, "%s: ERROR: FLAC stream has no STREAMINFO block\n", filename);
+ FLAC__metadata_iterator_delete(iterator);
+ return false;
+ }
+
+ if(sample_rate == 0) {
+ flac_fprintf(stderr, "%s: ERROR: cannot parse cuesheet when sample rate is unknown\n", filename);
+ FLAC__metadata_iterator_delete(iterator);
+ return false;
+ }
+
+ switch(operation->type) {
+ case OP__IMPORT_CUESHEET_FROM:
+ if(0 != cuesheet) {
+ flac_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, sample_rate, 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) {
+ flac_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, unsigned sample_rate, 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) {
+ flac_fprintf(stderr, "%s: ERROR: empty import file name\n", filename);
+ return false;
+ }
+ if(0 == strcmp(cs_filename, "-"))
+ f = stdin;
+ else
+ f = flac_fopen(cs_filename, "r");
+
+ if(0 == f) {
+ flac_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, sample_rate, is_cdda, lead_out_offset);
+
+ if(f != stdin)
+ fclose(f);
+
+ if(0 == *cuesheet) {
+ flac_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)) {
+ flac_fprintf(stderr, "%s: ERROR parsing cuesheet \"%s\": %s\n", filename, cs_filename, error_message);
+ FLAC__metadata_object_delete(*cuesheet);
+ 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_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, indx;
+ 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(indx = 0; indx < tr->num_indices; indx++) {
+ flac_snprintf(spec, sizeof (spec), "%" PRIu64 ";", (tr->offset + tr->indices[indx].offset));
+ 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) {
+ flac_fprintf(stderr, "%s: ERROR: empty export file name\n", filename);
+ return false;
+ }
+ if(0 == strcmp(cs_filename, "-"))
+ f = stdout;
+ else
+ f = flac_fopen(cs_filename, "w");
+
+ if(0 == f) {
+ flac_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))) {
+ flac_fprintf(stderr, "%s: ERROR: allocating memory\n", filename);
+ if(f != stdout)
+ fclose(f);
+ return false;
+ }
+
+ flac_snprintf(ref, reflen, "\"%s\" FLAC", filename);
+
+ grabbag__cuesheet_emit(f, cuesheet, ref);
+
+ free(ref);
+
+ if(f != stdout)
+ fclose(f);
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ /* Delete output file when fuzzing */
+ if(f != stdout)
+ flac_unlink(cs_filename);
+#endif
+
+ return true;
+}
diff --git a/src/metaflac/operations_shorthand_picture.c b/src/metaflac/operations_shorthand_picture.c
new file mode 100644
index 0000000..6bb459b
--- /dev/null
+++ b/src/metaflac/operations_shorthand_picture.c
@@ -0,0 +1,184 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <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)
+ flac_fprintf(stderr, "%s: ERROR: FLAC file has no PICTURE block\n", filename);
+ else
+ flac_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) {
+ flac_fprintf(stderr, "%s: ERROR: empty picture specification\n", filename);
+ return false;
+ }
+
+ *picture = grabbag__picture_parse_specification(specification, &error_message);
+
+ if(0 == *picture) {
+ flac_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)) {
+ flac_fprintf(stderr, "%s: ERROR: new PICTURE block for \"%s\" is illegal: %s\n", filename, specification, error_message);
+ FLAC__metadata_object_delete(*picture);
+ *picture = 0;
+ 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) {
+ flac_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 = flac_fopen(pic_filename, "wb");
+
+ if(0 == f) {
+ flac_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) {
+ flac_fprintf(stderr, "%s: ERROR: writing PICTURE data to file\n", filename);
+ if(f != stdout)
+ fclose(f);
+ return false;
+ }
+
+ if(f != stdout)
+ fclose(f);
+
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ /* Delete output file when fuzzing */
+ if(f != stdout)
+ flac_unlink(pic_filename);
+#endif
+
+ return true;
+}
diff --git a/src/metaflac/operations_shorthand_seektable.c b/src/metaflac/operations_shorthand_seektable.c
new file mode 100644
index 0000000..c9175b3
--- /dev/null
+++ b/src/metaflac/operations_shorthand_seektable.c
@@ -0,0 +1,220 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "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) {
+ flac_fprintf(stderr, "%s: ERROR: cannot add seekpoints because STREAMINFO block does not specify total_samples\n", filename);
+ FLAC__metadata_iterator_delete(iterator);
+ 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);
+ FLAC__metadata_iterator_delete(iterator);
+ 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)) {
+ flac_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) {
+ flac_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) {
+ flac_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)) {
+ flac_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)) {
+ flac_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)) {
+ flac_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) {
+ flac_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
index 0000000..3219841
--- /dev/null
+++ b/src/metaflac/operations_shorthand_streaminfo.c
@@ -0,0 +1,127 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "options.h"
+#include "utils.h"
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+#include "share/compat.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)
+ flac_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:
+ printf("%" PRIu64 "\n", block->data.stream_info.total_samples);
+ 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
index 0000000..27c9e4c
--- /dev/null
+++ b/src/metaflac/operations_shorthand_vorbiscomment.c
@@ -0,0 +1,430 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "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"
+#include "share/compat.h"
+
+static FLAC__bool remove_vc_all(const char *filename, FLAC__StreamMetadata *block, FLAC__bool *needs_write);
+static FLAC__bool remove_vc_all_except(const char *filename, FLAC__StreamMetadata *block, const char *field_name, 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_ALL_EXCEPT:
+ ok = remove_vc_all_except(filename, block, operation->argument.vc_field_name.value, 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:
+#ifdef _WIN32 /* do not convert anything or things will break */
+ ok = set_vc_field(filename, block, &operation->argument.vc_field, needs_write, true);
+#else
+ ok = set_vc_field(filename, block, &operation->argument.vc_field, needs_write, raw);
+#endif
+ 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)) {
+ flac_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_all_except(const char *filename, FLAC__StreamMetadata *block, const char *field_name, FLAC__bool *needs_write)
+{
+ char * field_names[200];
+ uint32_t field_name_length, i;
+ int j, num_field_names;
+
+ FLAC__ASSERT(0 != block);
+ FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+ FLAC__ASSERT(0 != needs_write);
+
+ field_name_length = strlen(field_name);
+ field_names[0] = (void *)field_name;
+
+ for(num_field_names = 1; num_field_names < 200; num_field_names++) {
+ char * separator = strchr(field_names[num_field_names-1], '=');
+ if(separator == 0 || separator >= field_name + field_name_length)
+ break;
+ field_names[num_field_names] = separator+1;
+ }
+
+ if(num_field_names > 200) {
+ flac_fprintf(stderr, "%s: ERROR: too many field names\n", filename);
+ return false;
+ }
+
+ for(i = 0; i < block->data.vorbis_comment.num_comments; ) {
+ int field_name_found = false;
+ for(j = 0; j < num_field_names; j++) {
+ const uint32_t length = (j == (num_field_names - 1))?(uint32_t)strlen(field_names[j]):(uint32_t)(strchr(field_names[j],'=')-field_names[j]);
+ if(FLAC__metadata_object_vorbiscomment_entry_matches(block->data.vorbis_comment.comments[i], field_names[j], length)) {
+ field_name_found = true;
+ break;
+ }
+ }
+ if(!field_name_found) {
+ FLAC__metadata_object_vorbiscomment_delete_comment(block, i);
+ *needs_write = true;
+ }
+ else
+ i++;
+ }
+
+ 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) {
+ flac_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) {
+ flac_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 FLAC__off_t size = grabbag__file_get_filesize(field->field_value);
+ if(size < 0) {
+ flac_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 */
+ flac_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 = flac_fopen(field->field_value, "rb")) || fread(data, 1, size, f) != (size_t)size) {
+ flac_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);
+ flac_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);
+ flac_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);
+ flac_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)) {
+ flac_fprintf(stderr, "%s: ERROR: memory allocation failure\n", filename);
+ return false;
+ }
+
+ *needs_write = true;
+ return true;
+ }
+ else {
+ FLAC__bool needs_free = false;
+ entry.entry = (FLAC__byte *)field->field;
+ 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 {
+ flac_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
+ */
+ flac_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);
+ flac_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) {
+ flac_fprintf(stderr, "%s: ERROR: empty import file name\n", filename);
+ return false;
+ }
+ if(0 == strcmp(vc_filename->value, "-"))
+ f = stdin;
+ else
+ f = flac_fopen(vc_filename->value, "r");
+
+ if(0 == f) {
+ flac_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) != NULL) {
+ if(!feof(f)) {
+ char *p = strchr(line, '\n');
+ if(0 == p) {
+ flac_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);
+ flac_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) {
+ flac_fprintf(stderr, "%s: ERROR: empty export file name\n", filename);
+ return false;
+ }
+ if(0 == strcmp(vc_filename->value, "-"))
+ f = stdout;
+ else
+ f = flac_fopen(vc_filename->value, "w");
+
+ if(0 == f) {
+ flac_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);
+
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ /* Delete output file when fuzzing */
+ if(f != stdout)
+ flac_unlink(vc_filename->value);
+#endif
+
+ return ret;
+}
diff --git a/src/metaflac/options.c b/src/metaflac/options.c
new file mode 100644
index 0000000..1b4b6f6
--- /dev/null
+++ b/src/metaflac/options.c
@@ -0,0 +1,1146 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "options.h"
+#include "usage.h"
+#include "utils.h"
+#include "FLAC/assert.h"
+#include "share/alloc.h"
+#include "share/compat.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-all-tags", 0, 0, 0 },
+ { "show-tag", 1, 0, 0 },
+ { "remove-all-tags", 0, 0, 0 },
+ { "remove-all-tags-except", 1, 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 },
+ { "scan-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_vorbis_comment_field_names(const char *field_ref, char **names, 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->data_format_is_binary = false;
+ options->data_format_is_binary_headerless = 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) {
+ flac_fprintf(stderr,"ERROR: you must specify at least one FLAC file;\n");
+ flac_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 = 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) {
+ flac_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) {
+ flac_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(!had_error && options->num_files > 1) {
+ if(0 != find_shorthand_operation(options, OP__IMPORT_CUESHEET_FROM)) {
+ flac_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)) {
+ flac_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)) {
+ flac_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, "-")
+ ) {
+ flac_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) {
+ flac_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:
+ case OP__REMOVE_VC_ALL_EXCEPT:
+ 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)) {
+ flac_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) {
+ flac_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) {
+ flac_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)) {
+ flac_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)) {
+ flac_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)) {
+ flac_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) {
+ flac_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) {
+ flac_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)) {
+ flac_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);
+ flac_fprintf(stderr, "ERROR (--%s): malformed vorbis comment field name \"%s\",\n %s\n", opt, option_argument, violation);
+ ok = false;
+ }
+ }
+ else if(0 == strcmp(opt, "show-all-tags")) {
+ op = append_shorthand_operation(options, OP__EXPORT_VC_TO);
+ parse_string("-",&op->argument.filename.value);
+ }
+ else if(0 == strcmp(opt, "remove-all-tags")) {
+ (void) append_shorthand_operation(options, OP__REMOVE_VC_ALL);
+ }
+ else if(0 == strcmp(opt, "remove-all-tags-except")) {
+ const char *violation;
+ op = append_shorthand_operation(options, OP__REMOVE_VC_ALL_EXCEPT);
+ FLAC__ASSERT(0 != option_argument);
+ if(!parse_vorbis_comment_field_names(option_argument, &(op->argument.vc_field_name.value), &violation)) {
+ FLAC__ASSERT(0 != violation);
+ flac_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-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);
+ flac_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);
+ flac_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);
+ flac_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);
+ flac_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))) {
+ flac_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))) {
+ flac_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)) {
+ flac_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))) {
+ flac_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))) {
+ flac_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))) {
+ flac_fprintf(stderr, "ERROR (--%s): missing specification\n", opt);
+ ok = false;
+ }
+ }
+ else if(0 == strcmp(opt, "export-picture-to")) {
+ 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))) {
+ flac_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);
+ flac_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, "scan-replay-gain")) {
+ (void) append_shorthand_operation(options, OP__SCAN_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))) {
+ flac_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))) {
+ flac_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))) {
+ flac_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))) {
+ flac_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))) {
+ flac_fprintf(stderr, "ERROR (--%s): illegal data format \"%s\"\n", opt, option_argument);
+ ok = false;
+ }
+ options->data_format_is_binary = arg->value.data_format.is_binary;
+ options->data_format_is_binary_headerless = arg->value.data_format.is_headerless;
+ }
+ 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))) {
+ flac_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 = 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 > UINT32_MAX / 2) /* overflow check */
+ die("out of memory allocating space for option list");
+ options->ops.capacity *= 2;
+ if(0 == (options->ops.operations = 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 = 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 > UINT32_MAX / 2) /* overflow check */
+ die("out of memory allocating space for option list");
+ options->args.capacity *= 2;
+ if(0 == (options->args.arguments = 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;
+}
+
+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;
+ *dest = strtoull(src, 0, 10);
+ 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_vorbis_comment_field_names(const char *field_ref, char **names, 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) {
+ free(s);
+ *violation = violations[0];
+ return false;
+ }
+ }
+
+ *names = 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 = 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 = 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) == sizeof (out->entries[entry].application_id)) {
+ memcpy(out->entries[entry].application_id, r, sizeof (out->entries[entry].application_id));
+ }
+ else if(strlen(r) == 10 && FLAC__STRNCASECMP(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-headerless")) {
+ out->is_binary = false;
+ out->is_headerless = true;
+ }
+ else if(0 == strcmp(in, "binary")) {
+ out->is_binary = true;
+ out->is_headerless = false;
+ }
+ else if(0 == strcmp(in, "text")) {
+ out->is_binary = false;
+ out->is_headerless = 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)
+{
+ flac_fprintf(stderr, "WARNING: undocumented 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
index 0000000..984f2e1
--- /dev/null
+++ b/src/metaflac/options.h
@@ -0,0 +1,221 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#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_ALL_EXCEPT,
+ 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__SCAN_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;
+ FLAC__bool is_headerless;
+} 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 data_format_is_binary;
+ FLAC__bool data_format_is_binary_headerless;
+ 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
index 0000000..58afc0e
--- /dev/null
+++ b/src/metaflac/usage.c
@@ -0,0 +1,349 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "utils.h"
+#include "usage.h"
+#include "FLAC/format.h"
+#include <stdarg.h>
+#include <stdio.h>
+#include "share/compat.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-2009 Josh Coalson\n");
+ fprintf(out, "Copyright (C) 2011-2023 Xiph.Org Foundation\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 along\n");
+ fprintf(out, "with this program; if not, write to the Free Software Foundation, Inc.,\n");
+ fprintf(out, "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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, " This option has no effect for options exporting to a\n");
+ fprintf(out, " file, like --export-tags-to.\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);
+ flac_fprintf(stderr, "\n");
+ flac_fprintf(stderr, "This is the short help; for full help use 'metaflac --help'\n");
+ flac_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 field name matches 'NAME'.\n");
+ fprintf(out, "--show-all-tags Show all tags. This is an alias for --export-tags-to=-.\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, "--remove-all-tags-except=NAME1[=NAME2[=...]] Remove all tags, except the vendor\n");
+ fprintf(out, " string and the tag names specified. Tag names must be\n");
+ fprintf(out, " separated by an = character.\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 specifies 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. Only mono and stereo files are allowed,\n");
+ fprintf(out, " and the sample rate must be 8, 11.025, 12, 16, 18.9,\n");
+ fprintf(out, " 22.05, 24, 28, 32, 36, 37.8, 44.1, 48, 56, 64, 72, 75.6,\n");
+ fprintf(out, " 88.2, 96, 112, 128, 144, 151.2, 176.4, 192, 224, 256,\n");
+ fprintf(out, " 288, 302.4, 352.8, 384, 448, 512, 576, or 604.8 kHz.\n");
+ fprintf(out, "--scan-replay-gain Like --add-replay-gain, but only analyzes the files\n");
+ fprintf(out, " rather than writing them to tags.\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");
+ fprintf(out, " --data-format=binary|binary-headerless|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. Specify --data-format=binary-headerless to omit output of\n");
+ fprintf(out, " metadata block headers, including the id of APPLICATION metadata blocks.\n");
+ fprintf(out, " The output can be read in using a subsequent call to\n");
+ fprintf(out, " \"metaflac --append\"\n");
+ fprintf(out, "\n");
+ 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");
+ fprintf(out, "--append\n");
+ fprintf(out, " Insert a metadata block from a file. This must be a binary block as\n");
+ fprintf(out, " exported with --list --data-format=binary. The insertion point is\n");
+ fprintf(out, " defined with --block-number=#. The new block will be added after the\n");
+ fprintf(out, " given block number. This prevents the illegal insertion of a block\n");
+ fprintf(out, " before the first STREAMINFO block. You may not --append another\n");
+ fprintf(out, " STREAMINFO block. It is possible to copy a metadata block from one\n");
+ fprintf(out, " file to another with this option. For example use\n");
+ fprintf(out, " metaflac --list --data-format=binary --block-number=6 file.flac > block\n");
+ fprintf(out, " to export the block, and then import it with\n");
+ fprintf(out, " metaflac --append anotherfile.flac < block\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");
+#if 0
+ /*@@@ not implemented yet */
+ 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
index 0000000..1366417
--- /dev/null
+++ b/src/metaflac/usage.h
@@ -0,0 +1,26 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#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
index 0000000..045719a
--- /dev/null
+++ b/src/metaflac/utils.c
@@ -0,0 +1,282 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "utils.h"
+#include "FLAC/assert.h"
+#include "share/alloc.h"
+#include "share/safe_str.h"
+#include "share/utf8.h"
+#include "share/compat.h"
+
+void die(const char *message)
+{
+ FLAC__ASSERT(0 != message);
+ flac_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, outlen;
+
+ FLAC__ASSERT(0 != dest);
+ FLAC__ASSERT(0 != source);
+
+ ndest = *dest ? strlen(*dest) : 0;
+ nsource = strlen(source);
+ outlen = ndest + nsource + 1;
+
+ if(nsource == 0)
+ return;
+
+ *dest = safe_realloc_add_3op_(*dest, ndest, /*+*/nsource, /*+*/1);
+ if(*dest == NULL)
+ die("out of memory growing string");
+ /* If ndest == 0, strlen in safe_strncat reads
+ * uninitialized data. To prevent that, set first character
+ * to zero */
+ if(ndest == 0)
+ *dest[0] = 0;
+ safe_strncat(*dest, source, outlen);
+}
+
+static inline int local_isprint(int c)
+{
+ if (c < 32) return 0;
+ if (c > 127) return 0;
+ return isprint(c);
+}
+
+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) {
+ flac_printf("%s%s", filename? filename:"", filename? ":":"");
+ printf("%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",
+ 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) ? (local_isprint(b[ 0]) ? b[ 0] : '.') : ' ',
+ (left > 1) ? (local_isprint(b[ 1]) ? b[ 1] : '.') : ' ',
+ (left > 2) ? (local_isprint(b[ 2]) ? b[ 2] : '.') : ' ',
+ (left > 3) ? (local_isprint(b[ 3]) ? b[ 3] : '.') : ' ',
+ (left > 4) ? (local_isprint(b[ 4]) ? b[ 4] : '.') : ' ',
+ (left > 5) ? (local_isprint(b[ 5]) ? b[ 5] : '.') : ' ',
+ (left > 6) ? (local_isprint(b[ 6]) ? b[ 6] : '.') : ' ',
+ (left > 7) ? (local_isprint(b[ 7]) ? b[ 7] : '.') : ' ',
+ (left > 8) ? (local_isprint(b[ 8]) ? b[ 8] : '.') : ' ',
+ (left > 9) ? (local_isprint(b[ 9]) ? b[ 9] : '.') : ' ',
+ (left > 10) ? (local_isprint(b[10]) ? b[10] : '.') : ' ',
+ (left > 11) ? (local_isprint(b[11]) ? b[11] : '.') : ' ',
+ (left > 12) ? (local_isprint(b[12]) ? b[12] : '.') : ' ',
+ (left > 13) ? (local_isprint(b[13]) ? b[13] : '.') : ' ',
+ (left > 14) ? (local_isprint(b[14]) ? b[14] : '.') : ' ',
+ (left > 15) ? (local_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) flac_vfprintf(stderr, format, args);
+
+ va_end(args);
+
+ flac_fprintf(stderr, ", status = \"%s\"\n", FLAC__Metadata_ChainStatusString[status]);
+
+ if(status == FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE) {
+ flac_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) {
+ flac_fprintf(stderr, "\n"
+ "The file does not appear to be a FLAC file.\n"
+ );
+ }
+ else if(status == FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE) {
+ flac_fprintf(stderr, "\n"
+ "The FLAC file does not have write permissions.\n"
+ );
+ }
+ else if(status == FLAC__METADATA_CHAIN_STATUS_BAD_METADATA) {
+ flac_fprintf(stderr, "\n"
+ "The metadata to be written does not conform to the FLAC metadata\n"
+ "specifications.\n"
+ );
+ }
+ else if(status == FLAC__METADATA_CHAIN_STATUS_READ_ERROR) {
+ flac_fprintf(stderr, "\n"
+ "There was an error while reading the FLAC file.\n"
+ );
+ }
+ else if(status == FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR) {
+ flac_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) {
+ flac_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)
+ flac_fprintf(f, "%s:", filename);
+
+ if(!raw) {
+ /*
+ * WATCHOUT: comments that contain an embedded null will
+ * be truncated by utf_decode().
+ */
+#ifdef _WIN32 /* if we are outputting to console, we need to use proper print functions to show unicode characters */
+ if (f == stdout || f == stderr) {
+ flac_fprintf(f, "%s", entry->entry);
+ } else {
+#endif
+ 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);
+ }
+#ifdef _WIN32
+ }
+#endif
+ }
+ 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
index 0000000..972a450
--- /dev/null
+++ b/src/metaflac/utils.h
@@ -0,0 +1,47 @@
+/* metaflac - Command-line FLAC metadata editor
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef metaflac__utils_h
+#define metaflac__utils_h
+
+#include "FLAC/metadata.h"
+#include <stdio.h> /* for FILE */
+
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+#undef stderr
+#define stderr stdout
+#endif
+
+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/metaflac/version.rc b/src/metaflac/version.rc
new file mode 100644
index 0000000..5117202
--- /dev/null
+++ b/src/metaflac/version.rc
@@ -0,0 +1,38 @@
+#include <winver.h>
+#include "config.h"
+
+#if (defined GIT_COMMIT_HASH && defined GIT_COMMIT_DATE)
+# ifdef GIT_COMMIT_TAG
+# define VERSIONSTRING GIT_COMMIT_TAG
+# else
+# define VERSIONSTRING "git-" GIT_COMMIT_HASH
+# endif
+#else
+# define VERSIONSTRING PACKAGE_VERSION
+#endif
+
+#define xstr(s) str(s)
+#define str(s) #s
+
+VS_VERSION_INFO VERSIONINFO
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+FILEFLAGS 0
+FILEOS VOS__WINDOWS32
+FILETYPE VFT_DLL
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "FileDescription", "metaflac command line tool for Windows"
+ VALUE "ProductName", "Free Lossless Audio Codec"
+ VALUE "ProductVersion", VERSIONSTRING
+ VALUE "CompanyName", "Xiph.Org"
+ VALUE "LegalCopyright", "2000-2009 Josh Coalson, 2011-2023 Xiph.Org Foundation"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/src/share/Makefile.am b/src/share/Makefile.am
new file mode 100644
index 0000000..caf6122
--- /dev/null
+++ b/src/share/Makefile.am
@@ -0,0 +1,73 @@
+# FLAC - Free Lossless Audio Codec
+# Copyright (C) 2002-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This file is part the FLAC project. FLAC is comprised of several
+# components distributed under different 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_OPTIONS = subdir-objects
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+
+EXTRA_DIST = \
+ README \
+ getopt/CMakeLists.txt \
+ grabbag/CMakeLists.txt \
+ replaygain_analysis/CMakeLists.txt \
+ replaygain_synthesis/CMakeLists.txt \
+ utf8/CMakeLists.txt \
+ utf8/charmaps.h \
+ utf8/makemap.c \
+ utf8/charset_test.c
+
+
+noinst_LTLIBRARIES = \
+ getopt/libgetopt.la \
+ grabbag/libgrabbag.la \
+ utf8/libutf8.la \
+ $(libwin_utf8_io) \
+ replaygain_analysis/libreplaygain_analysis.la \
+ replaygain_synthesis/libreplaygain_synthesis.la
+
+
+if OS_IS_WINDOWS
+win_utf8_io_libwin_utf8_io_la_SOURCES = win_utf8_io/win_utf8_io.c
+libwin_utf8_io = win_utf8_io/libwin_utf8_io.la
+else
+win_utf8_io_libwin_utf8_io_la_SOURCES =
+libwin_utf8_io =
+endif
+
+getopt_libgetopt_la_SOURCES = getopt/getopt.c getopt/getopt1.c
+
+grabbag_libgrabbag_la_SOURCES = \
+ grabbag/alloc.c \
+ grabbag/cuesheet.c \
+ grabbag/file.c \
+ grabbag/picture.c \
+ grabbag/replaygain.c \
+ grabbag/seektable.c \
+ grabbag/snprintf.c
+
+utf8_libutf8_la_SOURCES = \
+ utf8/charset.c \
+ utf8/charset.h \
+ utf8/iconvert.c \
+ utf8/iconvert.h \
+ utf8/utf8.c
+
+replaygain_analysis_libreplaygain_analysis_la_SOURCES = replaygain_analysis/replaygain_analysis.c
+
+replaygain_synthesis_libreplaygain_synthesis_la_CFLAGS = -I $(top_srcdir)/src/share/replaygain_synthesis/include
+replaygain_synthesis_libreplaygain_synthesis_la_SOURCES = replaygain_synthesis/replaygain_synthesis.c
diff --git a/src/share/Makefile.in b/src/share/Makefile.in
new file mode 100644
index 0000000..a944998
--- /dev/null
+++ b/src/share/Makefile.in
@@ -0,0 +1,905 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in 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.
+
+@SET_MAKE@
+
+# FLAC - Free Lossless Audio Codec
+# Copyright (C) 2002-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This file is part the FLAC project. FLAC is comprised of several
+# components distributed under different 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.
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/share
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/add_cflags.m4 \
+ $(top_srcdir)/m4/add_cxxflags.m4 \
+ $(top_srcdir)/m4/ax_add_fortify_source.m4 \
+ $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_enable_debug.m4 \
+ $(top_srcdir)/m4/bswap.m4 $(top_srcdir)/m4/clang.m4 \
+ $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gcc_version.m4 \
+ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/ogg.m4 \
+ $(top_srcdir)/m4/really_gcc.m4 \
+ $(top_srcdir)/m4/stack_protect.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+getopt_libgetopt_la_LIBADD =
+am__dirstamp = $(am__leading_dot)dirstamp
+am_getopt_libgetopt_la_OBJECTS = getopt/getopt.lo getopt/getopt1.lo
+getopt_libgetopt_la_OBJECTS = $(am_getopt_libgetopt_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+grabbag_libgrabbag_la_LIBADD =
+am_grabbag_libgrabbag_la_OBJECTS = grabbag/alloc.lo \
+ grabbag/cuesheet.lo grabbag/file.lo grabbag/picture.lo \
+ grabbag/replaygain.lo grabbag/seektable.lo grabbag/snprintf.lo
+grabbag_libgrabbag_la_OBJECTS = $(am_grabbag_libgrabbag_la_OBJECTS)
+replaygain_analysis_libreplaygain_analysis_la_LIBADD =
+am_replaygain_analysis_libreplaygain_analysis_la_OBJECTS = \
+ replaygain_analysis/replaygain_analysis.lo
+replaygain_analysis_libreplaygain_analysis_la_OBJECTS = \
+ $(am_replaygain_analysis_libreplaygain_analysis_la_OBJECTS)
+replaygain_synthesis_libreplaygain_synthesis_la_LIBADD =
+am_replaygain_synthesis_libreplaygain_synthesis_la_OBJECTS = replaygain_synthesis/libreplaygain_synthesis_la-replaygain_synthesis.lo
+replaygain_synthesis_libreplaygain_synthesis_la_OBJECTS = \
+ $(am_replaygain_synthesis_libreplaygain_synthesis_la_OBJECTS)
+replaygain_synthesis_libreplaygain_synthesis_la_LINK = $(LIBTOOL) \
+ $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) \
+ $(replaygain_synthesis_libreplaygain_synthesis_la_CFLAGS) \
+ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+utf8_libutf8_la_LIBADD =
+am_utf8_libutf8_la_OBJECTS = utf8/charset.lo utf8/iconvert.lo \
+ utf8/utf8.lo
+utf8_libutf8_la_OBJECTS = $(am_utf8_libutf8_la_OBJECTS)
+win_utf8_io_libwin_utf8_io_la_LIBADD =
+am__win_utf8_io_libwin_utf8_io_la_SOURCES_DIST = \
+ win_utf8_io/win_utf8_io.c
+@OS_IS_WINDOWS_TRUE@am_win_utf8_io_libwin_utf8_io_la_OBJECTS = \
+@OS_IS_WINDOWS_TRUE@ win_utf8_io/win_utf8_io.lo
+win_utf8_io_libwin_utf8_io_la_OBJECTS = \
+ $(am_win_utf8_io_libwin_utf8_io_la_OBJECTS)
+@OS_IS_WINDOWS_TRUE@am_win_utf8_io_libwin_utf8_io_la_rpath =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = getopt/$(DEPDIR)/getopt.Plo \
+ getopt/$(DEPDIR)/getopt1.Plo grabbag/$(DEPDIR)/alloc.Plo \
+ grabbag/$(DEPDIR)/cuesheet.Plo grabbag/$(DEPDIR)/file.Plo \
+ grabbag/$(DEPDIR)/picture.Plo grabbag/$(DEPDIR)/replaygain.Plo \
+ grabbag/$(DEPDIR)/seektable.Plo grabbag/$(DEPDIR)/snprintf.Plo \
+ replaygain_analysis/$(DEPDIR)/replaygain_analysis.Plo \
+ replaygain_synthesis/$(DEPDIR)/libreplaygain_synthesis_la-replaygain_synthesis.Plo \
+ utf8/$(DEPDIR)/charset.Plo utf8/$(DEPDIR)/iconvert.Plo \
+ utf8/$(DEPDIR)/utf8.Plo win_utf8_io/$(DEPDIR)/win_utf8_io.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(getopt_libgetopt_la_SOURCES) \
+ $(grabbag_libgrabbag_la_SOURCES) \
+ $(replaygain_analysis_libreplaygain_analysis_la_SOURCES) \
+ $(replaygain_synthesis_libreplaygain_synthesis_la_SOURCES) \
+ $(utf8_libutf8_la_SOURCES) \
+ $(win_utf8_io_libwin_utf8_io_la_SOURCES)
+DIST_SOURCES = $(getopt_libgetopt_la_SOURCES) \
+ $(grabbag_libgrabbag_la_SOURCES) \
+ $(replaygain_analysis_libreplaygain_analysis_la_SOURCES) \
+ $(replaygain_synthesis_libreplaygain_synthesis_la_SOURCES) \
+ $(utf8_libutf8_la_SOURCES) \
+ $(am__win_utf8_io_libwin_utf8_io_la_SOURCES_DIST)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp README
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_64_BIT_WORDS = @ENABLE_64_BIT_WORDS@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLAC__HAS_OGG = @FLAC__HAS_OGG@
+FLAC__TEST_LEVEL = @FLAC__TEST_LEVEL@
+FLAC__TEST_WITH_VALGRIND = @FLAC__TEST_WITH_VALGRIND@
+GCC_MAJOR_VERSION = @GCC_MAJOR_VERSION@
+GCC_MINOR_VERSION = @GCC_MINOR_VERSION@
+GCC_VERSION = @GCC_VERSION@
+GIT_COMMIT_VERSION_HASH = @GIT_COMMIT_VERSION_HASH@
+GIT_FOUND = @GIT_FOUND@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_FUZZING_ENGINE = @LIB_FUZZING_ENGINE@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OBJ_FORMAT = @OBJ_FORMAT@
+OGG_CFLAGS = @OGG_CFLAGS@
+OGG_LIBS = @OGG_LIBS@
+OGG_PACKAGE = @OGG_PACKAGE@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AUTOMAKE_OPTIONS = subdir-objects
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+EXTRA_DIST = \
+ README \
+ getopt/CMakeLists.txt \
+ grabbag/CMakeLists.txt \
+ replaygain_analysis/CMakeLists.txt \
+ replaygain_synthesis/CMakeLists.txt \
+ utf8/CMakeLists.txt \
+ utf8/charmaps.h \
+ utf8/makemap.c \
+ utf8/charset_test.c
+
+noinst_LTLIBRARIES = \
+ getopt/libgetopt.la \
+ grabbag/libgrabbag.la \
+ utf8/libutf8.la \
+ $(libwin_utf8_io) \
+ replaygain_analysis/libreplaygain_analysis.la \
+ replaygain_synthesis/libreplaygain_synthesis.la
+
+@OS_IS_WINDOWS_FALSE@win_utf8_io_libwin_utf8_io_la_SOURCES =
+@OS_IS_WINDOWS_TRUE@win_utf8_io_libwin_utf8_io_la_SOURCES = win_utf8_io/win_utf8_io.c
+@OS_IS_WINDOWS_FALSE@libwin_utf8_io =
+@OS_IS_WINDOWS_TRUE@libwin_utf8_io = win_utf8_io/libwin_utf8_io.la
+getopt_libgetopt_la_SOURCES = getopt/getopt.c getopt/getopt1.c
+grabbag_libgrabbag_la_SOURCES = \
+ grabbag/alloc.c \
+ grabbag/cuesheet.c \
+ grabbag/file.c \
+ grabbag/picture.c \
+ grabbag/replaygain.c \
+ grabbag/seektable.c \
+ grabbag/snprintf.c
+
+utf8_libutf8_la_SOURCES = \
+ utf8/charset.c \
+ utf8/charset.h \
+ utf8/iconvert.c \
+ utf8/iconvert.h \
+ utf8/utf8.c
+
+replaygain_analysis_libreplaygain_analysis_la_SOURCES = replaygain_analysis/replaygain_analysis.c
+replaygain_synthesis_libreplaygain_synthesis_la_CFLAGS = -I $(top_srcdir)/src/share/replaygain_synthesis/include
+replaygain_synthesis_libreplaygain_synthesis_la_SOURCES = replaygain_synthesis/replaygain_synthesis.c
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/share/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/share/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+getopt/$(am__dirstamp):
+ @$(MKDIR_P) getopt
+ @: > getopt/$(am__dirstamp)
+getopt/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) getopt/$(DEPDIR)
+ @: > getopt/$(DEPDIR)/$(am__dirstamp)
+getopt/getopt.lo: getopt/$(am__dirstamp) \
+ getopt/$(DEPDIR)/$(am__dirstamp)
+getopt/getopt1.lo: getopt/$(am__dirstamp) \
+ getopt/$(DEPDIR)/$(am__dirstamp)
+
+getopt/libgetopt.la: $(getopt_libgetopt_la_OBJECTS) $(getopt_libgetopt_la_DEPENDENCIES) $(EXTRA_getopt_libgetopt_la_DEPENDENCIES) getopt/$(am__dirstamp)
+ $(AM_V_CCLD)$(LINK) $(getopt_libgetopt_la_OBJECTS) $(getopt_libgetopt_la_LIBADD) $(LIBS)
+grabbag/$(am__dirstamp):
+ @$(MKDIR_P) grabbag
+ @: > grabbag/$(am__dirstamp)
+grabbag/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) grabbag/$(DEPDIR)
+ @: > grabbag/$(DEPDIR)/$(am__dirstamp)
+grabbag/alloc.lo: grabbag/$(am__dirstamp) \
+ grabbag/$(DEPDIR)/$(am__dirstamp)
+grabbag/cuesheet.lo: grabbag/$(am__dirstamp) \
+ grabbag/$(DEPDIR)/$(am__dirstamp)
+grabbag/file.lo: grabbag/$(am__dirstamp) \
+ grabbag/$(DEPDIR)/$(am__dirstamp)
+grabbag/picture.lo: grabbag/$(am__dirstamp) \
+ grabbag/$(DEPDIR)/$(am__dirstamp)
+grabbag/replaygain.lo: grabbag/$(am__dirstamp) \
+ grabbag/$(DEPDIR)/$(am__dirstamp)
+grabbag/seektable.lo: grabbag/$(am__dirstamp) \
+ grabbag/$(DEPDIR)/$(am__dirstamp)
+grabbag/snprintf.lo: grabbag/$(am__dirstamp) \
+ grabbag/$(DEPDIR)/$(am__dirstamp)
+
+grabbag/libgrabbag.la: $(grabbag_libgrabbag_la_OBJECTS) $(grabbag_libgrabbag_la_DEPENDENCIES) $(EXTRA_grabbag_libgrabbag_la_DEPENDENCIES) grabbag/$(am__dirstamp)
+ $(AM_V_CCLD)$(LINK) $(grabbag_libgrabbag_la_OBJECTS) $(grabbag_libgrabbag_la_LIBADD) $(LIBS)
+replaygain_analysis/$(am__dirstamp):
+ @$(MKDIR_P) replaygain_analysis
+ @: > replaygain_analysis/$(am__dirstamp)
+replaygain_analysis/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) replaygain_analysis/$(DEPDIR)
+ @: > replaygain_analysis/$(DEPDIR)/$(am__dirstamp)
+replaygain_analysis/replaygain_analysis.lo: \
+ replaygain_analysis/$(am__dirstamp) \
+ replaygain_analysis/$(DEPDIR)/$(am__dirstamp)
+
+replaygain_analysis/libreplaygain_analysis.la: $(replaygain_analysis_libreplaygain_analysis_la_OBJECTS) $(replaygain_analysis_libreplaygain_analysis_la_DEPENDENCIES) $(EXTRA_replaygain_analysis_libreplaygain_analysis_la_DEPENDENCIES) replaygain_analysis/$(am__dirstamp)
+ $(AM_V_CCLD)$(LINK) $(replaygain_analysis_libreplaygain_analysis_la_OBJECTS) $(replaygain_analysis_libreplaygain_analysis_la_LIBADD) $(LIBS)
+replaygain_synthesis/$(am__dirstamp):
+ @$(MKDIR_P) replaygain_synthesis
+ @: > replaygain_synthesis/$(am__dirstamp)
+replaygain_synthesis/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) replaygain_synthesis/$(DEPDIR)
+ @: > replaygain_synthesis/$(DEPDIR)/$(am__dirstamp)
+replaygain_synthesis/libreplaygain_synthesis_la-replaygain_synthesis.lo: \
+ replaygain_synthesis/$(am__dirstamp) \
+ replaygain_synthesis/$(DEPDIR)/$(am__dirstamp)
+
+replaygain_synthesis/libreplaygain_synthesis.la: $(replaygain_synthesis_libreplaygain_synthesis_la_OBJECTS) $(replaygain_synthesis_libreplaygain_synthesis_la_DEPENDENCIES) $(EXTRA_replaygain_synthesis_libreplaygain_synthesis_la_DEPENDENCIES) replaygain_synthesis/$(am__dirstamp)
+ $(AM_V_CCLD)$(replaygain_synthesis_libreplaygain_synthesis_la_LINK) $(replaygain_synthesis_libreplaygain_synthesis_la_OBJECTS) $(replaygain_synthesis_libreplaygain_synthesis_la_LIBADD) $(LIBS)
+utf8/$(am__dirstamp):
+ @$(MKDIR_P) utf8
+ @: > utf8/$(am__dirstamp)
+utf8/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) utf8/$(DEPDIR)
+ @: > utf8/$(DEPDIR)/$(am__dirstamp)
+utf8/charset.lo: utf8/$(am__dirstamp) utf8/$(DEPDIR)/$(am__dirstamp)
+utf8/iconvert.lo: utf8/$(am__dirstamp) utf8/$(DEPDIR)/$(am__dirstamp)
+utf8/utf8.lo: utf8/$(am__dirstamp) utf8/$(DEPDIR)/$(am__dirstamp)
+
+utf8/libutf8.la: $(utf8_libutf8_la_OBJECTS) $(utf8_libutf8_la_DEPENDENCIES) $(EXTRA_utf8_libutf8_la_DEPENDENCIES) utf8/$(am__dirstamp)
+ $(AM_V_CCLD)$(LINK) $(utf8_libutf8_la_OBJECTS) $(utf8_libutf8_la_LIBADD) $(LIBS)
+win_utf8_io/$(am__dirstamp):
+ @$(MKDIR_P) win_utf8_io
+ @: > win_utf8_io/$(am__dirstamp)
+win_utf8_io/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) win_utf8_io/$(DEPDIR)
+ @: > win_utf8_io/$(DEPDIR)/$(am__dirstamp)
+win_utf8_io/win_utf8_io.lo: win_utf8_io/$(am__dirstamp) \
+ win_utf8_io/$(DEPDIR)/$(am__dirstamp)
+
+win_utf8_io/libwin_utf8_io.la: $(win_utf8_io_libwin_utf8_io_la_OBJECTS) $(win_utf8_io_libwin_utf8_io_la_DEPENDENCIES) $(EXTRA_win_utf8_io_libwin_utf8_io_la_DEPENDENCIES) win_utf8_io/$(am__dirstamp)
+ $(AM_V_CCLD)$(LINK) $(am_win_utf8_io_libwin_utf8_io_la_rpath) $(win_utf8_io_libwin_utf8_io_la_OBJECTS) $(win_utf8_io_libwin_utf8_io_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+ -rm -f getopt/*.$(OBJEXT)
+ -rm -f getopt/*.lo
+ -rm -f grabbag/*.$(OBJEXT)
+ -rm -f grabbag/*.lo
+ -rm -f replaygain_analysis/*.$(OBJEXT)
+ -rm -f replaygain_analysis/*.lo
+ -rm -f replaygain_synthesis/*.$(OBJEXT)
+ -rm -f replaygain_synthesis/*.lo
+ -rm -f utf8/*.$(OBJEXT)
+ -rm -f utf8/*.lo
+ -rm -f win_utf8_io/*.$(OBJEXT)
+ -rm -f win_utf8_io/*.lo
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@getopt/$(DEPDIR)/getopt.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@getopt/$(DEPDIR)/getopt1.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@grabbag/$(DEPDIR)/alloc.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@grabbag/$(DEPDIR)/cuesheet.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@grabbag/$(DEPDIR)/file.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@grabbag/$(DEPDIR)/picture.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@grabbag/$(DEPDIR)/replaygain.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@grabbag/$(DEPDIR)/seektable.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@grabbag/$(DEPDIR)/snprintf.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@replaygain_analysis/$(DEPDIR)/replaygain_analysis.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@replaygain_synthesis/$(DEPDIR)/libreplaygain_synthesis_la-replaygain_synthesis.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@utf8/$(DEPDIR)/charset.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@utf8/$(DEPDIR)/iconvert.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@utf8/$(DEPDIR)/utf8.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@win_utf8_io/$(DEPDIR)/win_utf8_io.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+replaygain_synthesis/libreplaygain_synthesis_la-replaygain_synthesis.lo: replaygain_synthesis/replaygain_synthesis.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(replaygain_synthesis_libreplaygain_synthesis_la_CFLAGS) $(CFLAGS) -MT replaygain_synthesis/libreplaygain_synthesis_la-replaygain_synthesis.lo -MD -MP -MF replaygain_synthesis/$(DEPDIR)/libreplaygain_synthesis_la-replaygain_synthesis.Tpo -c -o replaygain_synthesis/libreplaygain_synthesis_la-replaygain_synthesis.lo `test -f 'replaygain_synthesis/replaygain_synthesis.c' || echo '$(srcdir)/'`replaygain_synthesis/replaygain_synthesis.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) replaygain_synthesis/$(DEPDIR)/libreplaygain_synthesis_la-replaygain_synthesis.Tpo replaygain_synthesis/$(DEPDIR)/libreplaygain_synthesis_la-replaygain_synthesis.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='replaygain_synthesis/replaygain_synthesis.c' object='replaygain_synthesis/libreplaygain_synthesis_la-replaygain_synthesis.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(replaygain_synthesis_libreplaygain_synthesis_la_CFLAGS) $(CFLAGS) -c -o replaygain_synthesis/libreplaygain_synthesis_la-replaygain_synthesis.lo `test -f 'replaygain_synthesis/replaygain_synthesis.c' || echo '$(srcdir)/'`replaygain_synthesis/replaygain_synthesis.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+ -rm -rf getopt/.libs getopt/_libs
+ -rm -rf grabbag/.libs grabbag/_libs
+ -rm -rf replaygain_analysis/.libs replaygain_analysis/_libs
+ -rm -rf replaygain_synthesis/.libs replaygain_synthesis/_libs
+ -rm -rf utf8/.libs utf8/_libs
+ -rm -rf win_utf8_io/.libs win_utf8_io/_libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+ -rm -f getopt/$(DEPDIR)/$(am__dirstamp)
+ -rm -f getopt/$(am__dirstamp)
+ -rm -f grabbag/$(DEPDIR)/$(am__dirstamp)
+ -rm -f grabbag/$(am__dirstamp)
+ -rm -f replaygain_analysis/$(DEPDIR)/$(am__dirstamp)
+ -rm -f replaygain_analysis/$(am__dirstamp)
+ -rm -f replaygain_synthesis/$(DEPDIR)/$(am__dirstamp)
+ -rm -f replaygain_synthesis/$(am__dirstamp)
+ -rm -f utf8/$(DEPDIR)/$(am__dirstamp)
+ -rm -f utf8/$(am__dirstamp)
+ -rm -f win_utf8_io/$(DEPDIR)/$(am__dirstamp)
+ -rm -f win_utf8_io/$(am__dirstamp)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f getopt/$(DEPDIR)/getopt.Plo
+ -rm -f getopt/$(DEPDIR)/getopt1.Plo
+ -rm -f grabbag/$(DEPDIR)/alloc.Plo
+ -rm -f grabbag/$(DEPDIR)/cuesheet.Plo
+ -rm -f grabbag/$(DEPDIR)/file.Plo
+ -rm -f grabbag/$(DEPDIR)/picture.Plo
+ -rm -f grabbag/$(DEPDIR)/replaygain.Plo
+ -rm -f grabbag/$(DEPDIR)/seektable.Plo
+ -rm -f grabbag/$(DEPDIR)/snprintf.Plo
+ -rm -f replaygain_analysis/$(DEPDIR)/replaygain_analysis.Plo
+ -rm -f replaygain_synthesis/$(DEPDIR)/libreplaygain_synthesis_la-replaygain_synthesis.Plo
+ -rm -f utf8/$(DEPDIR)/charset.Plo
+ -rm -f utf8/$(DEPDIR)/iconvert.Plo
+ -rm -f utf8/$(DEPDIR)/utf8.Plo
+ -rm -f win_utf8_io/$(DEPDIR)/win_utf8_io.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f getopt/$(DEPDIR)/getopt.Plo
+ -rm -f getopt/$(DEPDIR)/getopt1.Plo
+ -rm -f grabbag/$(DEPDIR)/alloc.Plo
+ -rm -f grabbag/$(DEPDIR)/cuesheet.Plo
+ -rm -f grabbag/$(DEPDIR)/file.Plo
+ -rm -f grabbag/$(DEPDIR)/picture.Plo
+ -rm -f grabbag/$(DEPDIR)/replaygain.Plo
+ -rm -f grabbag/$(DEPDIR)/seektable.Plo
+ -rm -f grabbag/$(DEPDIR)/snprintf.Plo
+ -rm -f replaygain_analysis/$(DEPDIR)/replaygain_analysis.Plo
+ -rm -f replaygain_synthesis/$(DEPDIR)/libreplaygain_synthesis_la-replaygain_synthesis.Plo
+ -rm -f utf8/$(DEPDIR)/charset.Plo
+ -rm -f utf8/$(DEPDIR)/iconvert.Plo
+ -rm -f utf8/$(DEPDIR)/utf8.Plo
+ -rm -f win_utf8_io/$(DEPDIR)/win_utf8_io.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/share/README b/src/share/README
new file mode 100644
index 0000000..1d4fede
--- /dev/null
+++ b/src/share/README
@@ -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/CMakeLists.txt b/src/share/getopt/CMakeLists.txt
new file mode 100644
index 0000000..d905615
--- /dev/null
+++ b/src/share/getopt/CMakeLists.txt
@@ -0,0 +1,13 @@
+check_include_file("string.h" HAVE_STRING_H)
+
+if(NOT WIN32)
+ find_package(Intl)
+endif()
+
+add_library(getopt STATIC getopt.c getopt1.c)
+
+if(Intl_FOUND)
+ target_include_directories(getopt PRIVATE ${Intl_INCLUDE_DIRS})
+ target_link_libraries(getopt PUBLIC ${Intl_LIBRARIES})
+ target_compile_definitions(getopt PRIVATE HAVE_LIBINTL_H)
+endif()
diff --git a/src/share/getopt/getopt.c b/src/share/getopt/getopt.c
new file mode 100644
index 0000000..39fab80
--- /dev/null
+++ b/src/share/getopt/getopt.c
@@ -0,0 +1,1053 @@
+/*
+ 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:
+ https://sourceforge.net/p/flac/patches/
+
+ 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* 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
+
+#ifdef 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>
+# ifdef HAVE_STRING_H
+# 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;
+
+#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 (const char * name);
+#endif
+
+static char *
+my_index (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__ */
+
+/* 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 (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 (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 =
+ 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;
+}
+
+/* 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 (
+ 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 ((size_t) (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 `%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 ((size_t) (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 (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. */
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+ the above definition of `share__getopt'. */
+
+int
+main (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
index 0000000..fc52678
--- /dev/null
+++ b/src/share/getopt/getopt1.c
@@ -0,0 +1,189 @@
+/*
+ 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:
+ https://sourceforge.net/p/flac/patches/
+
+ 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+#ifdef 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>
+
+#include "share/getopt.h"
+/*[JEC] was:#include "getopt.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(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(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. */
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int main(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/grabbag/CMakeLists.txt b/src/share/grabbag/CMakeLists.txt
new file mode 100644
index 0000000..203ae3f
--- /dev/null
+++ b/src/share/grabbag/CMakeLists.txt
@@ -0,0 +1,14 @@
+add_library(grabbag STATIC
+ alloc.c
+ cuesheet.c
+ file.c
+ picture.c
+ replaygain.c
+ seektable.c
+ snprintf.c)
+target_link_libraries(grabbag PUBLIC
+ FLAC
+ replaygain_analysis)
+if(TARGET win_utf8_io)
+ target_link_libraries(grabbag PUBLIC win_utf8_io)
+endif()
diff --git a/src/share/grabbag/alloc.c b/src/share/grabbag/alloc.c
new file mode 100644
index 0000000..4e5fb60
--- /dev/null
+++ b/src/share/grabbag/alloc.c
@@ -0,0 +1,48 @@
+/* alloc - Convenience routines for safely allocating memory
+ * Copyright (C) 2007-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+
+#include "share/alloc.h"
+
+void *safe_malloc_mul_2op_(size_t size1, size_t size2)
+{
+ 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);
+}
diff --git a/src/share/grabbag/cuesheet.c b/src/share/grabbag/cuesheet.c
new file mode 100644
index 0000000..0d19ee7
--- /dev/null
+++ b/src/share/grabbag/cuesheet.c
@@ -0,0 +1,681 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include "FLAC/assert.h"
+#include "share/compat.h"
+#include "share/grabbag.h"
+#include "share/safe_str.h"
+
+uint32_t grabbag__cuesheet_msf_to_frame(uint32_t minutes, uint32_t seconds, uint32_t frames)
+{
+ return ((minutes * 60) + seconds) * 75 + frames;
+}
+
+void grabbag__cuesheet_frame_to_msf(uint32_t frame, uint32_t *minutes, uint32_t *seconds, uint32_t *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 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') {
+ if(ret >= (INT64_MAX / 10))
+ return -1;
+ else
+ 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 int local__parse_int_(const char *s)
+{
+ FLAC__int64 ret64 = local__parse_int64_(s);
+ if(ret64 < 0 || ret64 > INT_MAX)
+ return -1;
+ return ret64;
+}
+
+/* accept minute:second:frame syntax of '[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
+ * WATCHOUT: if sample rate is not evenly divisible by 75, the resulting sample number will be approximate
+ */
+static FLAC__int64 local__parse_msf_(const char *s, uint32_t sample_rate)
+{
+ FLAC__int64 ret, field;
+ char c;
+
+ if(sample_rate == 0)
+ return -1;
+
+ c = *s++;
+ if(c >= '0' && c <= '9')
+ field = (c - '0');
+ else
+ return -1;
+ while(':' != (c = *s++)) {
+ if(c >= '0' && c <= '9') {
+ if(field >= (INT64_MAX / 10))
+ return -1;
+ else
+ field = field * 10 + (c - '0');
+ }
+ else
+ return -1;
+ }
+
+ if(field >= INT64_MAX / (60 * sample_rate))
+ return -1;
+ ret = field * 60 * sample_rate;
+
+ 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;
+
+ {
+ FLAC__int64 tmp = ret;
+ ret += field * sample_rate;
+ if(ret < tmp)
+ return -1;
+ }
+
+ 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;
+
+ {
+ FLAC__int64 tmp = ret;
+ ret += field * (sample_rate / 75);
+ if(ret < tmp)
+ return -1;
+ }
+
+ return ret;
+}
+
+/* accept minute:second syntax of '[0-9]+:[0-9][0-9]?{,.[0-9]+}', but second < 60, e.g. 0:0.0, 3:5, 15:31.731
+ * return sample number or <0 for error
+ * WATCHOUT: depending on the sample rate, the resulting sample number may be approximate with fractional seconds
+ */
+static FLAC__int64 local__parse_ms_(const char *s, uint32_t sample_rate)
+{
+ FLAC__int64 ret, field;
+ double x;
+ char c, *end;
+
+ if(sample_rate == 0)
+ return -1;
+
+ c = *s++;
+ if(c >= '0' && c <= '9')
+ field = (c - '0');
+ else
+ return -1;
+ while(':' != (c = *s++)) {
+ if(c >= '0' && c <= '9') {
+ if(field >= (INT64_MAX / 10))
+ return -1;
+ else
+ field = field * 10 + (c - '0');
+ }
+ else
+ return -1;
+ }
+
+ if(field >= INT64_MAX / (60 * sample_rate))
+ return -1;
+ ret = field * 60 * sample_rate;
+
+ if(strspn(s, "0123456789.") != strlen(s))
+ return -1;
+ x = strtod(s, &end);
+ if(*end || end == s)
+ return -1;
+ if(x < 0.0 || x >= 60.0)
+ return -1;
+
+ ret += (FLAC__int64)(x * sample_rate);
+
+ 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, uint32_t *last_line_read, FLAC__StreamMetadata *cuesheet, uint32_t sample_rate, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset)
+{
+ char buffer[4096], *line, *field;
+ uint32_t 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;
+
+ FLAC__ASSERT(!is_cdda || sample_rate == 44100);
+ /* double protection */
+ if(is_cdda && sample_rate != 44100) {
+ *error_message = "CD-DA cuesheet only allowed with 44.1kHz sample rate";
+ return false;
+ }
+
+ 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;
+ }
+ safe_strncpy(cs->media_catalog_number, field, sizeof(cs->media_catalog_number));
+ 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;
+ }
+ /* first parse as minute:second:frame format */
+ xx = local__parse_msf_(field, sample_rate);
+ if(xx < 0) {
+ /* CD-DA must use only MM:SS:FF format */
+ if(is_cdda) {
+ *error_message = "illegal INDEX offset (not of the form MM:SS:FF)";
+ return false;
+ }
+ /* as an extension for non-CD-DA we allow MM:SS.SS or raw sample number */
+ xx = local__parse_ms_(field, sample_rate);
+ if(xx < 0) {
+ xx = local__parse_int64_(field);
+ if(xx < 0) {
+ *error_message = "illegal INDEX offset";
+ return false;
+ }
+ }
+ }
+ else if(sample_rate % 75 && xx) {
+ /* only sample zero is exact */
+ *error_message = "illegal INDEX offset (MM:SS:FF form not allowed if sample rate is not a multiple of 75)";
+ 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=*/true))) {
+ *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;
+ }
+ safe_strncpy(cs->tracks[cs->num_tracks-1].isrc, field, sizeof(cs->tracks[cs->num_tracks-1].isrc));
+ 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 = (uint32_t)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;
+}
+
+FLAC__StreamMetadata *grabbag__cuesheet_parse(FILE *file, const char **error_message, uint32_t *last_line_read, uint32_t sample_rate, 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, sample_rate, 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;
+ uint32_t 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);
+
+ FLAC__ASSERT(cs->num_tracks > 0);
+
+ 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", (uint32_t)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 *indx = track->indices + index_num;
+
+ fprintf(file, " INDEX %02u ", (uint32_t)indx->number);
+ if(cs->is_cd) {
+ const uint32_t logical_frame = (uint32_t)((track->offset + indx->offset) / (44100 / 75));
+ uint32_t m, s, f;
+ grabbag__cuesheet_frame_to_msf(logical_frame, &m, &s, &f);
+ fprintf(file, "%02u:%02u:%02u\n", m, s, f);
+ }
+ else
+ fprintf(file, "%" PRIu64 "\n", (track->offset + indx->offset));
+ }
+ }
+
+ fprintf(file, "REM FLAC__lead-in %" PRIu64 "\n", cs->lead_in);
+ fprintf(file, "REM FLAC__lead-out %u %" PRIu64 "\n", (uint32_t)cs->tracks[track_num].number, cs->tracks[track_num].offset);
+}
diff --git a/src/share/grabbag/file.c b/src/share/grabbag/file.c
new file mode 100644
index 0000000..307645f
--- /dev/null
+++ b/src/share/grabbag/file.c
@@ -0,0 +1,207 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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
+ */
+
+#ifdef 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 */
+#endif
+#if 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"
+#include "share/compat.h"
+
+
+void grabbag__file_copy_metadata(const char *srcpath, const char *destpath)
+{
+ struct flac_stat_s srcstat;
+
+ if(0 == flac_stat(srcpath, &srcstat)) {
+#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L) && !defined(_WIN32)
+ struct timespec srctime[2] = {};
+ srctime[0].tv_sec = srcstat.st_atime;
+ srctime[1].tv_sec = srcstat.st_mtime;
+#else
+ struct utimbuf srctime;
+ srctime.actime = srcstat.st_atime;
+ srctime.modtime = srcstat.st_mtime;
+#endif
+ (void)flac_chmod(destpath, srcstat.st_mode);
+ (void)flac_utime(destpath, &srctime);
+ }
+}
+
+FLAC__off_t grabbag__file_get_filesize(const char *srcpath)
+{
+ struct flac_stat_s srcstat;
+
+ if(0 == flac_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) {
+#if defined _WIN32 && !defined __CYGWIN__
+ p = strrchr(srcpath, '\\');
+ if(0 == p)
+#endif
+ return srcpath;
+ }
+ return ++p;
+}
+
+FLAC__bool grabbag__file_change_stats(const char *filename, FLAC__bool read_only)
+{
+ struct flac_stat_s stats;
+
+ if(0 == flac_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 != flac_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 _WIN32 && !defined __CYGWIN__
+#if !defined(WINAPI_FAMILY_PARTITION)
+#define WINAPI_FAMILY_PARTITION(x) x
+#define WINAPI_PARTITION_DESKTOP 1
+#endif
+ /* 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_utf8(f1, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ h2 = CreateFile_utf8(f2, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if(h1 == INVALID_HANDLE_VALUE || h2 == INVALID_HANDLE_VALUE)
+ ok = 0;
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+ ok &= GetFileInformationByHandle(h1, &info1);
+ ok &= GetFileInformationByHandle(h2, &info2);
+ if(ok)
+ same =
+ info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber &&
+ info1.nFileIndexHigh == info2.nFileIndexHigh &&
+ info1.nFileIndexLow == info2.nFileIndexLow
+ ;
+#else // !WINAPI_PARTITION_DESKTOP
+ FILE_ID_INFO id_info1, id_info2;
+ same = GetFileInformationByHandleEx(h1, FileIdInfo, &id_info1, sizeof (id_info1)) &&
+ GetFileInformationByHandleEx(h2, FileIdInfo, &id_info2, sizeof (id_info2)) &&
+ id_info1.VolumeSerialNumber == id_info2.VolumeSerialNumber &&
+ memcmp(&id_info1.FileId, &id_info2.FileId, sizeof(id_info1.FileId)) == 0;
+#endif // !WINAPI_PARTITION_DESKTOP
+ if(h1 != INVALID_HANDLE_VALUE)
+ CloseHandle(h1);
+ if(h2 != INVALID_HANDLE_VALUE)
+ CloseHandle(h2);
+ return same;
+#else
+ struct flac_stat_s s1, s2;
+ return f1 && f2 && flac_stat(f1, &s1) == 0 && flac_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 == flac_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 __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 __EMX__
+ setmode(fileno(stdout), O_BINARY);
+#endif
+
+ return stdout;
+}
diff --git a/src/share/grabbag/picture.c b/src/share/grabbag/picture.c
new file mode 100644
index 0000000..9a4aafe
--- /dev/null
+++ b/src/share/grabbag/picture.c
@@ -0,0 +1,515 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2006-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "share/alloc.h"
+#include "share/grabbag.h"
+#include "FLAC/assert.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "share/compat.h"
+#include "share/safe_str.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 = 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];
+ /* First check whether clen makes sense or causes overflow in this bit of code */
+ if(clen + 12 <= clen || clen + 12 > len)
+ return false;
+ else if(0 == memcmp(data+4, "IHDR", 4) && clen == 13) {
+ uint32_t 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 {
+ 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;
+}
+
+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",
+ "file not found", /* currently unused */
+ "file is too large",
+ "empty file"
+};
+
+static const char * read_file (const char * filepath, FLAC__StreamMetadata * obj)
+{
+ const FLAC__off_t size = grabbag__file_get_filesize(filepath);
+ FLAC__byte *buffer;
+ FILE *file;
+ const char *error_message=NULL;
+
+ if (size < 0)
+ return error_messages[5];
+
+ if (size == 0)
+ return error_messages[12];
+
+ if (size >= (FLAC__off_t)(1u << FLAC__STREAM_METADATA_LENGTH_LEN)) /* actual limit is less because of other fields in the PICTURE metadata block */
+ return error_messages[11];
+
+ if ((buffer = safe_malloc_(size)) == NULL)
+ return error_messages[0];
+
+ if ((file = flac_fopen(filepath, "rb")) == NULL) {
+ free(buffer);
+ return error_messages[5];
+ }
+
+ if (fread(buffer, 1, size, file) != (size_t) size) {
+ fclose(file);
+ free(buffer);
+ return error_messages[6];
+ }
+ fclose(file);
+
+ if (!FLAC__metadata_object_picture_set_data(obj, buffer, (FLAC__uint32)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];
+ /* check metadata block size */
+ else if (obj->length >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN))
+ error_message = error_messages[11];
+
+ return error_message;
+}
+
+FLAC__StreamMetadata *grabbag__picture_parse_specification(const char *spec, const char **error_message)
+{
+ FLAC__StreamMetadata *obj;
+ int state = 0;
+
+ 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];
+ return obj;
+ }
+
+ 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(strlen(spec) == 0)
+ *error_message = error_messages[1];
+ else 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 */
+ *error_message = read_file (spec, obj);
+ }
+ }
+ }
+
+ 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;
+}
+
+FLAC__StreamMetadata *grabbag__picture_from_specification(int type, const char *mime_type_in, const char * description,
+ const PictureResolution * res, const char * filepath, const char **error_message)
+{
+
+ FLAC__StreamMetadata *obj;
+ char mime_type [64] ;
+
+ if (error_message == 0)
+ return 0;
+
+ safe_strncpy(mime_type, mime_type_in, sizeof (mime_type));
+
+ *error_message = 0;
+
+ if ((obj = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE)) == 0) {
+ *error_message = error_messages[0];
+ return obj;
+ }
+
+ /* Picture type if known. */
+ obj->data.picture.type = type >= 0 ? type : FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
+
+ /* Mime type if known. */
+ if (mime_type_in && ! FLAC__metadata_object_picture_set_mime_type(obj, mime_type, /*copy=*/true)) {
+ *error_message = error_messages[0];
+ return obj;
+ }
+
+ /* Description if present. */
+ if (description && ! FLAC__metadata_object_picture_set_description(obj, (FLAC__byte*) description, /*copy=*/true)) {
+ *error_message = error_messages[0];
+ return obj;
+ }
+
+ if (res == NULL) {
+ obj->data.picture.width = 0;
+ obj->data.picture.height = 0;
+ obj->data.picture.depth = 0;
+ obj->data.picture.colors = 0;
+ }
+ else {
+ obj->data.picture.width = res->width;
+ obj->data.picture.height = res->height;
+ obj->data.picture.depth = res->depth;
+ obj->data.picture.colors = res->colors;
+ }
+
+ if (strcmp(obj->data.picture.mime_type, "-->") == 0) { /* magic MIME type means URL */
+ if (!FLAC__metadata_object_picture_set_data(obj, (FLAC__byte*)filepath, strlen(filepath), /*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 {
+ *error_message = read_file (filepath, obj);
+ }
+
+ if (*error_message == NULL) {
+ 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
index 0000000..32c9603
--- /dev/null
+++ b/src/share/grabbag/replaygain.c
@@ -0,0 +1,669 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#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() */
+
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+#include "FLAC/stream_decoder.h"
+#include "share/grabbag.h"
+#include "share/replaygain_analysis.h"
+#include "share/safe_str.h"
+
+#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))
+
+#ifdef abs32
+#undef abs32
+#endif
+#define abs32(a) (((a)==INT32_MIN)?INT32_MAX:abs(a))
+
+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 uint32_t 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 flac_stat_s *stats)
+{
+ FLAC__ASSERT(0 != filename);
+ FLAC__ASSERT(0 != stats);
+ return (0 == flac_stat(filename, stats));
+}
+
+static void set_file_stats_(const char *filename, struct flac_stat_s *stats)
+{
+ FLAC__ASSERT(0 != filename);
+ FLAC__ASSERT(0 != stats);
+
+ (void)flac_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");
+ flac_snprintf(buffer, sizeof(buffer), format, name, value);
+ 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(uint32_t sample_frequency)
+{
+ return ValidGainFrequency( sample_frequency );
+}
+
+FLAC__bool grabbag__replaygain_init(uint32_t 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, uint32_t bps, uint32_t samples)
+{
+ /* using a small buffer improves data locality; we'd like it to fit easily in the dcache */
+ static flac_float_t lbuffer[2048], rbuffer[2048];
+ static const uint32_t nbuffer = sizeof(lbuffer) / sizeof(lbuffer[0]);
+ FLAC__int32 block_peak = 0, s;
+ uint32_t i, j;
+
+ FLAC__ASSERT(bps >= FLAC__MIN_BITS_PER_SAMPLE && bps <= FLAC__MAX_BITS_PER_SAMPLE);
+ FLAC__ASSERT(FLAC__MIN_BITS_PER_SAMPLE == 4 && FLAC__MAX_BITS_PER_SAMPLE == 32);
+
+ if(bps == 16) {
+ if(is_stereo) {
+ j = 0;
+ while(samples > 0) {
+ const uint32_t n = local_min(samples, nbuffer);
+ for(i = 0; i < n; i++, j++) {
+ s = input[0][j];
+ lbuffer[i] = (flac_float_t)s;
+ s = abs(s);
+ block_peak = local_max(block_peak, s);
+
+ s = input[1][j];
+ rbuffer[i] = (flac_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 uint32_t n = local_min(samples, nbuffer);
+ for(i = 0; i < n; i++, j++) {
+ s = input[0][j];
+ lbuffer[i] = (flac_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 {
+ const double scale = (
+ (bps > 16)?
+ (double)1. / (double)(1u << (bps - 16)) :
+ (double)(1u << (16 - bps))
+ );
+
+ if(is_stereo) {
+ j = 0;
+ while(samples > 0) {
+ const uint32_t n = local_min(samples, nbuffer);
+ for(i = 0; i < n; i++, j++) {
+ s = input[0][j];
+ lbuffer[i] = (flac_float_t)(scale * (double)s);
+ s = abs32(s);
+ block_peak = local_max(block_peak, s);
+
+ s = input[1][j];
+ rbuffer[i] = (flac_float_t)(scale * (double)s);
+ s = abs32(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 uint32_t n = local_min(samples, nbuffer);
+ for(i = 0; i < n; i++, j++) {
+ s = input[0][j];
+ lbuffer[i] = (flac_float_t)(scale * (double)s);
+ s = abs32(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 {
+ uint32_t channels;
+ uint32_t bits_per_sample;
+ uint32_t 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 uint32_t bits_per_sample = frame->header.bits_per_sample;
+ const uint32_t channels = frame->header.channels;
+ const uint32_t sample_rate = frame->header.sample_rate;
+ const uint32_t 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 flac_stat_s 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)) {
+ const char *error;
+ error = FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(chain)];
+ FLAC__metadata_chain_delete(chain);
+ return error;
+ }
+
+ 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 = NULL;
+ 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 = NULL;
+ 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 = NULL;
+ 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 = NULL;
+ 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++;
+ safe_strncpy(s, q, local_min(sizeof(s), (size_t) (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;
+ char *saved_locale;
+ FLAC__bool res = true;
+
+ 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;
+
+ /*
+ * We need to save the old locale and switch to "C" because the locale
+ * influences the behaviour of strtod 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(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))))
+ res = false;
+ 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))))
+ res = false;
+
+ if(res && !parse_double_(block->data.vorbis_comment.comments + gain_offset, gain))
+ res = false;
+ if(res && !parse_double_(block->data.vorbis_comment.comments + peak_offset, peak))
+ res = false;
+ if(res && *peak < 0.0)
+ res = false;
+
+ setlocale(LC_ALL, saved_locale);
+ free(saved_locale);
+
+ /* something failed; retry with strict */
+ if (!res && !strict)
+ res = grabbag__replaygain_load_from_vorbiscomment(block, !album_mode, /*strict=*/true, reference, gain, peak);
+
+ return res;
+}
+
+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
index 0000000..01caa99
--- /dev/null
+++ b/src/share/grabbag/seektable.c
@@ -0,0 +1,105 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "share/grabbag.h"
+#include "share/compat.h"
+#include "FLAC/assert.h"
+#include <stdlib.h> /* for atoi() */
+#include <string.h>
+
+FLAC__bool grabbag__seektable_convert_specification_to_template(const char *spec, FLAC__bool only_explicit_placeholders, FLAC__uint64 total_samples_to_encode, uint32_t sample_rate, FLAC__StreamMetadata *seektable_template, FLAC__bool *spec_has_real_points)
+{
+ uint32_t 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 = (uint32_t)atoi(pt);
+ if(n > 0)
+ if(!FLAC__metadata_object_seektable_template_append_spaced_points(seektable_template, (uint32_t)n, total_samples_to_encode))
+ return false;
+ }
+ }
+ }
+ else if(q[-1] == 's') { /* -S #s */
+ if(total_samples_to_encode > 0 && sample_rate > 0) { /* we can only do these if we know the number of samples and sample rate to encode up front */
+ if(0 != spec_has_real_points)
+ *spec_has_real_points = true;
+ if(!only_explicit_placeholders) {
+ const double sec = atof(pt);
+ if(sec > 0.0) {
+ uint32_t samples = (uint32_t)(sec * (double)sample_rate);
+ /* Restrict seekpoints to two per second of audio. */
+ samples = samples < sample_rate / 2 ? sample_rate / 2 : samples;
+ 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;
+ const FLAC__int64 n = (FLAC__int64)strtoll(pt, &endptr, 10);
+ 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/grabbag/snprintf.c b/src/share/grabbag/snprintf.c
new file mode 100644
index 0000000..bd7ffba
--- /dev/null
+++ b/src/share/grabbag/snprintf.c
@@ -0,0 +1,101 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2013-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "share/compat.h"
+
+/*
+ * FLAC needs to compile and work correctly on systems with a normal ISO C99
+ * snprintf as well as Microsoft Visual Studio which has an non-standards
+ * conformant snprint_s function.
+ *
+ * The important difference occurs when the resultant string (plus string
+ * terminator) would have been longer than the supplied size parameter. When
+ * this happens, ISO C's snprintf returns the length of resultant string, but
+ * does not over-write the end of the buffer. MS's snprintf_s in this case
+ * returns -1.
+ *
+ * The _MSC_VER code below attempts to modify the return code for vsnprintf_s
+ * to something that is more compatible with the behaviour of the ISO C version.
+ */
+
+int
+flac_snprintf(char *str, size_t size, const char *fmt, ...)
+{
+ va_list va;
+ int rc;
+
+#if defined _MSC_VER
+ if (size == 0)
+ return 1024;
+#endif
+
+ va_start (va, fmt);
+
+#if defined _MSC_VER
+ rc = vsnprintf_s (str, size, _TRUNCATE, fmt, va);
+ if (rc < 0)
+ rc = size - 1;
+#elif defined __MINGW32__
+ rc = __mingw_vsnprintf (str, size, fmt, va);
+#else
+ rc = vsnprintf (str, size, fmt, va);
+#endif
+ va_end (va);
+
+ return rc;
+}
+
+int
+flac_vsnprintf(char *str, size_t size, const char *fmt, va_list va)
+{
+ int rc;
+
+#if defined _MSC_VER
+ if (size == 0)
+ return 1024;
+ rc = vsnprintf_s (str, size, _TRUNCATE, fmt, va);
+ if (rc < 0)
+ rc = size - 1;
+#elif defined __MINGW32__
+ rc = __mingw_vsnprintf (str, size, fmt, va);
+#else
+ rc = vsnprintf (str, size, fmt, va);
+#endif
+
+ return rc;
+}
diff --git a/src/share/replaygain_analysis/CMakeLists.txt b/src/share/replaygain_analysis/CMakeLists.txt
new file mode 100644
index 0000000..4362b90
--- /dev/null
+++ b/src/share/replaygain_analysis/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_library(replaygain_analysis STATIC
+ replaygain_analysis.c)
diff --git a/src/share/replaygain_analysis/replaygain_analysis.c b/src/share/replaygain_analysis/replaygain_analysis.c
new file mode 100644
index 0000000..37b77ab
--- /dev/null
+++ b/src/share/replaygain_analysis/replaygain_analysis.c
@@ -0,0 +1,575 @@
+/*
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 flac_float_t* left_samples,
+ * const flac_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:
+ *
+ * flac_float_t l_samples [4096];
+ * flac_float_t r_samples [4096];
+ * size_t num_samples;
+ * uint32_t num_songs;
+ * uint32_t 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "share/alloc.h"
+#include "share/compat.h"
+#include "share/replaygain_analysis.h"
+
+flac_float_t ReplayGainReferenceLoudness = 89.0; /* in dB SPL */
+
+#define YULE_ORDER 10
+#define BUTTER_ORDER 2
+#define RMS_PERCENTILE 0.95 /* percentile which is louder than the proposed level */
+#define RMS_WINDOW_TIME 50 /* Time slice size [ms] */
+#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)
+#define PINK_REF 64.82 /* 298640883795 */ /* calibration value */
+
+static flac_float_t linprebuf [MAX_ORDER * 2];
+static flac_float_t* linpre; /* left input samples, with pre-buffer */
+static flac_float_t* lstepbuf;
+static flac_float_t* lstep; /* left "first step" (i.e. post first filter) samples */
+static flac_float_t* loutbuf;
+static flac_float_t* lout; /* left "out" (i.e. post second filter) samples */
+static flac_float_t rinprebuf [MAX_ORDER * 2];
+static flac_float_t* rinpre; /* right input samples ... */
+static flac_float_t* rstepbuf;
+static flac_float_t* rstep;
+static flac_float_t* routbuf;
+static flac_float_t* rout;
+static uint32_t sampleWindow; /* number of samples required to reach number of milliseconds required for RMS window */
+static uint64_t totsamp;
+static double lsum;
+static double rsum;
+#if 0
+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 [120 * 100];
+static uint32_t B [120 * 100];
+#endif
+
+#ifdef _MSC_VER
+#pragma warning ( disable : 4305 )
+#endif
+
+struct ReplayGainFilter {
+ long rate;
+ uint32_t downsample;
+ flac_float_t BYule[YULE_ORDER+1];
+ flac_float_t AYule[YULE_ORDER+1];
+ flac_float_t BButter[BUTTER_ORDER+1];
+ flac_float_t AButter[BUTTER_ORDER+1];
+};
+
+static struct ReplayGainFilter *replaygainfilter;
+
+static const struct ReplayGainFilter ReplayGainFilters[] = {
+
+ {
+ 48000, 0, /* ORIGINAL */
+ { 0.03857599435200, -0.02160367184185, -0.00123395316851, -0.00009291677959, -0.01655260341619, 0.02161526843274, -0.02074045215285, 0.00594298065125, 0.00306428023191, 0.00012025322027, 0.00288463683916 },
+ { 1.00000000000000, -3.84664617118067, 7.81501653005538, -11.34170355132042, 13.05504219327545, -12.28759895145294, 9.48293806319790, -5.87257861775999, 2.75465861874613, -0.86984376593551, 0.13919314567432 },
+ { 0.98621192462708, -1.97242384925416, 0.98621192462708 },
+ { 1.00000000000000, -1.97223372919527, 0.97261396931306 },
+ },
+
+ {
+ 44100, 0, /* ORIGINAL */
+ { 0.05418656406430, -0.02911007808948, -0.00848709379851, -0.00851165645469, -0.00834990904936, 0.02245293253339, -0.02596338512915, 0.01624864962975, -0.00240879051584, 0.00674613682247, -0.00187763777362 },
+ { 1.00000000000000, -3.47845948550071, 6.36317777566148, -8.54751527471874, 9.47693607801280, -8.81498681370155, 6.85401540936998, -4.39470996079559, 2.19611684890774, -0.75104302451432, 0.13149317958808 },
+ { 0.98500175787242, -1.97000351574484, 0.98500175787242 },
+ { 1.00000000000000, -1.96977855582618, 0.97022847566350 },
+ },
+
+ {
+ 37800, 0,
+ { 0.10296717174470, -0.04877975583256, -0.02878009075237, -0.03519509188311, 0.02888717172493, -0.00609872684844, 0.00209851217112, 0.00911704668543, 0.01154404718589, -0.00630293688700, 0.00107527155228 },
+ { 1.00000000000000, -2.64848054923531, 3.58406058405771, -3.83794914179161, 3.90142345804575, -3.50179818637243, 2.67085284083076, -1.82581142372418, 1.09530368139801, -0.47689017820395, 0.11171431535905 },
+ { 0.98252400815195, -1.96504801630391, 0.98252400815195 },
+ { 1.00000000000000, -1.96474258269041, 0.96535344991740 },
+ },
+
+ {
+ 36000, 0,
+ { 0.11572297028613, -0.04120916051252, -0.04977731768022, -0.01047308680426, 0.00750863219157, 0.00055507694408, 0.00140344192886, 0.01286095246036, 0.00998223033885, -0.00725013810661, 0.00326503346879 },
+ { 1.00000000000000, -2.43606802820871, 3.01907406973844, -2.90372016038192, 2.67947188094303, -2.17606479220391, 1.44912956803015, -0.87785765549050, 0.53592202672557, -0.26469344817509, 0.07495878059717 },
+ { 0.98165826840326, -1.96331653680652, 0.98165826840326 },
+ { 1.00000000000000, -1.96298008938934, 0.96365298422371 },
+ },
+
+ {
+ 32000, 0, /* ORIGINAL */
+ { 0.15457299681924, -0.09331049056315, -0.06247880153653, 0.02163541888798, -0.05588393329856, 0.04781476674921, 0.00222312597743, 0.03174092540049, -0.01390589421898, 0.00651420667831, -0.00881362733839 },
+ { 1.00000000000000, -2.37898834973084, 2.84868151156327, -2.64577170229825, 2.23697657451713, -1.67148153367602, 1.00595954808547, -0.45953458054983, 0.16378164858596, -0.05032077717131, 0.02347897407020 },
+ { 0.97938932735214, -1.95877865470428, 0.97938932735214 },
+ { 1.00000000000000, -1.95835380975398, 0.95920349965459 },
+ },
+
+ {
+ 28000, 0,
+ { 0.23882392323383, -0.22007791534089, -0.06014581950332, 0.05004458058021, -0.03293111254977, 0.02348678189717, 0.04290549799671, -0.00938141862174, 0.00015095146303, -0.00712601540885, -0.00626520210162 },
+ { 1.00000000000000, -2.06894080899139, 1.76944699577212, -0.81404732584187, 0.25418286850232, -0.30340791669762, 0.35616884070937, -0.14967310591258, -0.07024154183279, 0.11078404345174, -0.03551838002425 },
+ { 0.97647981663949, -1.95295963327897, 0.97647981663949 },
+ { 1.00000000000000, -1.95240635772520, 0.95351290883275 },
+
+ },
+
+ {
+ 24000, 0, /* ORIGINAL */
+ { 0.30296907319327, -0.22613988682123, -0.08587323730772, 0.03282930172664, -0.00915702933434, -0.02364141202522, -0.00584456039913, 0.06276101321749, -0.00000828086748, 0.00205861885564, -0.02950134983287 },
+ { 1.00000000000000, -1.61273165137247, 1.07977492259970, -0.25656257754070, -0.16276719120440, -0.22638893773906, 0.39120800788284, -0.22138138954925, 0.04500235387352, 0.02005851806501, 0.00302439095741 },
+ { 0.97531843204928, -1.95063686409857, 0.97531843204928 },
+ { 1.00000000000000, -1.95002759149878, 0.95124613669835 },
+ },
+
+ {
+ 22050, 0, /* ORIGINAL */
+ { 0.33642304856132, -0.25572241425570, -0.11828570177555, 0.11921148675203, -0.07834489609479, -0.00469977914380, -0.00589500224440, 0.05724228140351, 0.00832043980773, -0.01635381384540, -0.01760176568150 },
+ { 1.00000000000000, -1.49858979367799, 0.87350271418188, 0.12205022308084, -0.80774944671438, 0.47854794562326, -0.12453458140019, -0.04067510197014, 0.08333755284107, -0.04237348025746, 0.02977207319925 },
+ { 0.97316523498161, -1.94633046996323, 0.97316523498161 },
+ { 1.00000000000000, -1.94561023566527, 0.94705070426118 },
+ },
+
+ {
+ 18900, 0,
+ { 0.38412657295385, -0.44533729608120, 0.20426638066221, -0.28031676047946, 0.31484202614802, -0.26078311203207, 0.12925201224848, -0.01141164696062, 0.03036522115769, -0.03776339305406, 0.00692036603586 },
+ { 1.00000000000000, -1.74403915585708, 1.96686095832499, -2.10081452941881, 1.90753918182846, -1.83814263754422, 1.36971352214969, -0.77883609116398, 0.39266422457649, -0.12529383592986, 0.05424760697665 },
+ { 0.96535326815829, -1.93070653631658, 0.96535326815829 },
+ { 1.00000000000000, -1.92950577983524, 0.93190729279793 },
+ },
+
+ {
+ 16000, 0, /* ORIGINAL */
+ { 0.44915256608450, -0.14351757464547, -0.22784394429749, -0.01419140100551, 0.04078262797139, -0.12398163381748, 0.04097565135648, 0.10478503600251, -0.01863887810927, -0.03193428438915, 0.00541907748707 },
+ { 1.00000000000000, -0.62820619233671, 0.29661783706366, -0.37256372942400, 0.00213767857124, -0.42029820170918, 0.22199650564824, 0.00613424350682, 0.06747620744683, 0.05784820375801, 0.03222754072173 },
+ { 0.96454515552826, -1.92909031105652, 0.96454515552826 },
+ { 1.00000000000000, -1.92783286977036, 0.93034775234268 },
+ },
+
+ {
+ 12000, 0, /* ORIGINAL */
+ { 0.56619470757641, -0.75464456939302, 0.16242137742230, 0.16744243493672, -0.18901604199609, 0.30931782841830, -0.27562961986224, 0.00647310677246, 0.08647503780351, -0.03788984554840, -0.00588215443421 },
+ { 1.00000000000000, -1.04800335126349, 0.29156311971249, -0.26806001042947, 0.00819999645858, 0.45054734505008, -0.33032403314006, 0.06739368333110, -0.04784254229033, 0.01639907836189, 0.01807364323573 },
+ { 0.96009142950541, -1.92018285901082, 0.96009142950541 },
+ { 1.00000000000000, -1.91858953033784, 0.92177618768381 },
+ },
+
+ {
+ 11025, 0, /* ORIGINAL */
+ { 0.58100494960553, -0.53174909058578, -0.14289799034253, 0.17520704835522, 0.02377945217615, 0.15558449135573, -0.25344790059353, 0.01628462406333, 0.06920467763959, -0.03721611395801, -0.00749618797172 },
+ { 1.00000000000000, -0.51035327095184, -0.31863563325245, -0.20256413484477, 0.14728154134330, 0.38952639978999, -0.23313271880868, -0.05246019024463, -0.02505961724053, 0.02442357316099, 0.01818801111503 },
+ { 0.95856916599601, -1.91713833199203, 0.95856916599601 },
+ { 1.00000000000000, -1.91542108074780, 0.91885558323625 },
+ },
+
+ {
+ 8000, 0, /* ORIGINAL */
+ { 0.53648789255105, -0.42163034350696, -0.00275953611929, 0.04267842219415, -0.10214864179676, 0.14590772289388, -0.02459864859345, -0.11202315195388, -0.04060034127000, 0.04788665548180, -0.02217936801134 },
+ { 1.00000000000000, -0.25049871956020, -0.43193942311114, -0.03424681017675, -0.04678328784242, 0.26408300200955, 0.15113130533216, -0.17556493366449, -0.18823009262115, 0.05477720428674, 0.04704409688120 },
+ { 0.94597685600279, -1.89195371200558, 0.94597685600279 },
+ { 1.00000000000000, -1.88903307939452, 0.89487434461664 },
+ },
+
+};
+
+#ifdef _MSC_VER
+#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 flac_float_t* input, flac_float_t* output, size_t nSamples, const flac_float_t* a, const flac_float_t* b, size_t order, uint32_t downsample )
+{
+ double y;
+ size_t i;
+ size_t k;
+
+ const flac_float_t* input_head = input;
+ const flac_float_t* input_tail;
+
+ flac_float_t* output_head = output;
+ flac_float_t* output_tail;
+
+ for ( i = 0; i < nSamples; i++, input_head += downsample, ++output_head ) {
+
+ input_tail = input_head;
+ output_tail = output_head;
+
+ y = *input_head * b[0];
+
+ for ( k = 1; k <= order; k++ ) {
+ input_tail -= downsample;
+ --output_tail;
+ y += *input_tail * b[k] - *output_tail * a[k];
+ }
+
+ output[i] = (flac_float_t)y;
+ }
+}
+
+/* returns a INIT_GAIN_ANALYSIS_OK if successful, INIT_GAIN_ANALYSIS_ERROR if not */
+
+static struct ReplayGainFilter*
+CreateGainFilter ( long samplefreq )
+{
+ uint32_t i;
+ long maxrate = 0;
+ uint32_t downsample = 1;
+ struct ReplayGainFilter* gainfilter = malloc(sizeof(*gainfilter));
+
+ if ( !gainfilter )
+ return 0;
+
+ while (1) {
+ for ( i = 0; i < sizeof(ReplayGainFilters)/sizeof(ReplayGainFilters[0]); ++i ) {
+ if (maxrate < ReplayGainFilters[i].rate)
+ maxrate = ReplayGainFilters[i].rate;
+
+ if ( ReplayGainFilters[i].rate == samplefreq ) {
+ *gainfilter = ReplayGainFilters[i];
+ gainfilter->downsample = downsample;
+ return gainfilter;
+ }
+ }
+
+ if (samplefreq < maxrate)
+ break;
+
+ while (samplefreq > maxrate) {
+ downsample *= 2;
+ samplefreq /= 2;
+ }
+ }
+
+ free(gainfilter);
+
+ return 0;
+}
+
+static void*
+ReallocateWindowBuffer(uint32_t window_size, flac_float_t **window_buffer)
+{
+ *window_buffer = safe_realloc_(*window_buffer, sizeof(**window_buffer) * (window_size + MAX_ORDER));
+ return *window_buffer;
+}
+
+static int
+ResetSampleFrequency ( long samplefreq ) {
+ int i;
+
+ free(replaygainfilter);
+
+ replaygainfilter = CreateGainFilter( samplefreq );
+
+ if ( ! replaygainfilter)
+ return INIT_GAIN_ANALYSIS_ERROR;
+
+ sampleWindow =
+ (replaygainfilter->rate * RMS_WINDOW_TIME + 1000-1) / 1000;
+
+ if ( ! ReallocateWindowBuffer(sampleWindow, &lstepbuf) ||
+ ! ReallocateWindowBuffer(sampleWindow, &rstepbuf) ||
+ ! ReallocateWindowBuffer(sampleWindow, &loutbuf) ||
+ ! ReallocateWindowBuffer(sampleWindow, &routbuf) ) {
+
+ return INIT_GAIN_ANALYSIS_ERROR;
+ }
+
+ /* zero out initial values */
+ for ( i = 0; i < MAX_ORDER; i++ )
+ linprebuf[i] = lstepbuf[i] = loutbuf[i] = rinprebuf[i] = rstepbuf[i] = routbuf[i] = 0.;
+
+ lsum = 0.;
+ rsum = 0.;
+ totsamp = 0;
+
+ memset ( A, 0, sizeof(A) );
+
+ return INIT_GAIN_ANALYSIS_OK;
+}
+
+int
+ValidGainFrequency ( long samplefreq )
+{
+ struct ReplayGainFilter* gainfilter = CreateGainFilter( samplefreq );
+
+ if (gainfilter == 0) {
+ return 0;
+ } else {
+ free(gainfilter);
+ return 1;
+ }
+}
+
+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 flac_float_t* left_samples, const flac_float_t* right_samples, size_t num_samples, int num_channels )
+{
+ uint32_t downsample = replaygainfilter->downsample;
+ const flac_float_t* curleft;
+ const flac_float_t* curright;
+ long prebufsamples;
+ long batchsamples;
+ long cursamples;
+ long cursamplepos;
+ int i;
+
+ num_samples /= downsample;
+
+ 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;
+ }
+
+ prebufsamples = MAX_ORDER;
+ if ((size_t) prebufsamples > num_samples)
+ prebufsamples = num_samples;
+
+ for ( i = 0; i < prebufsamples; ++i ) {
+ linprebuf[i+MAX_ORDER] = left_samples [i * downsample];
+ rinprebuf[i+MAX_ORDER] = right_samples[i * downsample];
+ }
+
+ while ( batchsamples > 0 ) {
+ cursamples = batchsamples > (long)(sampleWindow-totsamp) ? (long)(sampleWindow - totsamp) : batchsamples;
+ if ( cursamplepos < MAX_ORDER ) {
+ downsample = 1;
+ curleft = linpre+cursamplepos;
+ curright = rinpre+cursamplepos;
+ if (cursamples > MAX_ORDER - cursamplepos )
+ cursamples = MAX_ORDER - cursamplepos;
+ }
+ else {
+ downsample = replaygainfilter->downsample;
+ curleft = left_samples + cursamplepos * downsample;
+ curright = right_samples + cursamplepos * downsample;
+ }
+
+ filter ( curleft , lstep + totsamp, cursamples, replaygainfilter->AYule, replaygainfilter->BYule, YULE_ORDER, downsample );
+ filter ( curright, rstep + totsamp, cursamples, replaygainfilter->AYule, replaygainfilter->BYule, YULE_ORDER, downsample );
+
+ filter ( lstep + totsamp, lout + totsamp, cursamples, replaygainfilter->AButter, replaygainfilter->BButter, BUTTER_ORDER, 1 );
+ filter ( rstep + totsamp, rout + totsamp, cursamples, replaygainfilter->AButter, replaygainfilter->BButter, BUTTER_ORDER, 1 );
+
+ 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(flac_float_t) );
+ memmove ( routbuf , routbuf + totsamp, MAX_ORDER * sizeof(flac_float_t) );
+ memmove ( lstepbuf, lstepbuf + totsamp, MAX_ORDER * sizeof(flac_float_t) );
+ memmove ( rstepbuf, rstepbuf + totsamp, MAX_ORDER * sizeof(flac_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(flac_float_t) );
+ memmove ( rinprebuf, rinprebuf + num_samples, (MAX_ORDER-num_samples) * sizeof(flac_float_t) );
+ memcpy ( linprebuf + MAX_ORDER - num_samples, left_samples, num_samples * sizeof(flac_float_t) );
+ memcpy ( rinprebuf + MAX_ORDER - num_samples, right_samples, num_samples * sizeof(flac_float_t) );
+ }
+ else {
+ downsample = replaygainfilter->downsample;
+
+ left_samples += (num_samples - MAX_ORDER) * downsample;
+ right_samples += (num_samples - MAX_ORDER) * downsample;
+
+ for ( i = 0; i < MAX_ORDER; ++i ) {
+ linprebuf[i] = left_samples [i * downsample];
+ rinprebuf[i] = right_samples[i * downsample];
+ }
+ }
+
+ return GAIN_ANALYSIS_OK;
+}
+
+
+static flac_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;
+
+/* workaround for GCC bug #61423: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61423 */
+#if 0
+ upper = (int32_t) ceil (elems * (1. - RMS_PERCENTILE));
+#else
+ upper = (int32_t) (elems / 20 + ((elems % 20) ? 1 : 0));
+#endif
+ for ( i = len; i-- > 0; ) {
+ if ( (upper -= Array[i]) <= 0 )
+ break;
+ }
+
+ return (flac_float_t) ((flac_float_t)PINK_REF - (flac_float_t)i / (flac_float_t)STEPS_per_dB);
+}
+
+
+flac_float_t
+GetTitleGain ( void )
+{
+ flac_float_t retval;
+ uint32_t 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;
+}
+
+
+flac_float_t
+GetAlbumGain ( void )
+{
+ return analyzeResult ( B, sizeof(B)/sizeof(*B) );
+}
+
+/* end of replaygain_analysis.c */
diff --git a/src/share/replaygain_synthesis/CMakeLists.txt b/src/share/replaygain_synthesis/CMakeLists.txt
new file mode 100644
index 0000000..0736f4f
--- /dev/null
+++ b/src/share/replaygain_synthesis/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_library(replaygain_synthesis STATIC
+ replaygain_synthesis.c)
diff --git a/src/share/replaygain_synthesis/replaygain_synthesis.c b/src/share/replaygain_synthesis/replaygain_synthesis.c
new file mode 100644
index 0000000..8d4fda6
--- /dev/null
+++ b/src/share/replaygain_synthesis/replaygain_synthesis.c
@@ -0,0 +1,429 @@
+/* replaygain_synthesis - Routines for applying ReplayGain to a signal
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * 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
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h> /* for memset() */
+#include <math.h>
+#include "share/compat.h"
+#include "share/replaygain_synthesis.h"
+#include "FLAC/assert.h"
+
+#define FLAC__I64L(x) x##LL
+
+
+/*
+ * 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 uint32_t random_int_(void)
+{
+ static const uint8_t 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 uint32_t r1_ = 1;
+ static uint32_t r2_ = 1;
+
+ uint32_t 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 uint8_t 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 indx;
+
+ if (shapingtype < 0) shapingtype = 0;
+ if (shapingtype > 3) shapingtype = 3;
+ d->ShapingType = (NoiseShaping)shapingtype;
+ indx = bits - 11 - shapingtype;
+ if (indx < 0) indx = 0;
+ if (indx > 9) indx = 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[indx] / (((FLAC__int64)1) << bits);
+ d->LastHistoryIndex = 0;
+}
+
+static inline int64_t
+ROUND64 (DitherContext *d, double x)
+{
+ union {
+ double d;
+ int64_t i;
+ } doubletmp;
+
+ doubletmp.d = x + d->Add + (int64_t)FLAC__I64L(0x001FFFFD80000000);
+
+ return doubletmp.i - (int64_t)FLAC__I64L(0x433FFFFD80000000);
+}
+
+/*
+ * the following is based on parts of wavegain.c
+ */
+
+static int64_t dither_output_(DitherContext *d, FLAC__bool do_dithering, int shapingtype, int i, double Sum, int k)
+{
+ double Sum2;
+ int64_t val;
+
+ 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(d, 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(d, Sum2) & d->Mask;
+ d->ErrorHistory [k] [(-1-i)&15] = (float)(Sum - val);
+ }
+ return val;
+ }
+
+ return ROUND64(d, Sum);
+}
+
+#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 uint32_t_data_out, const FLAC__int32 * const input[], uint32_t wide_samples, uint32_t channels, const uint32_t source_bps, const uint32_t target_bps, const double scale, const FLAC__bool hard_limit, FLAC__bool do_dithering, DitherContext *dither_context)
+{
+ 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_shift = 32 - 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;
+ uint32_t i, channel;
+ const FLAC__int32 *input_;
+ double sample;
+ const uint32_t bytes_per_sample = target_bps / 8;
+ const uint32_t 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 uint32_t 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.;
+
+ val64 = dither_output_(dither_context, do_dithering, noise_shaping, (i + last_history_index) % 32, sample, channel) >> conv_shift;
+
+ 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 (uint32_t_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/utf8/CMakeLists.txt b/src/share/utf8/CMakeLists.txt
new file mode 100644
index 0000000..389b09e
--- /dev/null
+++ b/src/share/utf8/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 3.12)
+
+add_library(utf8 STATIC
+ charset.c
+ iconvert.c
+ utf8.c)
+
+target_link_libraries(utf8 PUBLIC grabbag $<TARGET_NAME_IF_EXISTS:Iconv::Iconv>)
diff --git a/src/share/utf8/charmaps.h b/src/share/utf8/charmaps.h
new file mode 100644
index 0000000..16d049a
--- /dev/null
+++ b/src/share/utf8/charmaps.h
@@ -0,0 +1,57 @@
+
+/*
+ * If you need to generate more maps, use makemap.c on a system
+ * with a decent iconv.
+ */
+
+static const uint16_t 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 uint16_t *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
index 0000000..5c5693d
--- /dev/null
+++ b/src/share/utf8/charset.c
@@ -0,0 +1,534 @@
+/*
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if !defined _WIN32 && !defined HAVE_ICONV /* should be && defined 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 || !*s2)
+ 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 (uint8_t)*s1 - (uint8_t)*s2;
+}
+
+/*
+ * UTF-8 equivalents of the C library's wctomb() and mbtowc().
+ */
+
+int utf8_mbtowc(int *pwc, const char *s, size_t n)
+{
+ uint8_t 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)
+{
+ uint32_t 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 = (uint8_t)*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 = (uint8_t)*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 uint16_t *from;
+ struct inverse_map *to;
+};
+
+static int mbtowc_8bit(void *map1, int *pwc, const char *s, size_t n)
+{
+ struct map *map = map1;
+ uint16_t wc;
+
+ if (!n || !s)
+ return 0;
+ wc = map->from[(uint8_t)*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 {
+ uint8_t first[256];
+ uint8_t 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 uint16_t *from)
+{
+ struct inverse_map *to;
+ char used[256];
+ int i, j, k;
+
+ to = 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;
+}
+
+static int wctomb_8bit(void *map1, char *s, int wc1)
+{
+ struct map *map = map1;
+ uint16_t 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 = malloc(sizeof(struct charset));
+ if (maps[i].charset) {
+ struct map *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;
+ int i, j, wc;
+
+ charset1 = charset_find(fromcode);
+ charset2 = charset_find(tocode);
+ if (!charset1 || !charset2 )
+ return -1;
+
+ tobuf = 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) {
+ char *tobuf_saved = tobuf;
+ *to = realloc(tobuf, p - tobuf);
+ if (*to == NULL)
+ *to = tobuf_saved;
+ }
+ 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
index 0000000..ea8e31e
--- /dev/null
+++ b/src/share/utf8/charset.h
@@ -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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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
index 0000000..6761100
--- /dev/null
+++ b/src/share/utf8/charset_test.c
@@ -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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef 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 */
+ safe_strncpy(s, ".......", sizeof(s));
+ assert(charset_wctomb(charset, s, 1u << 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 */
+ safe_strncpy(s, "..", sizeof(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 */
+ safe_strncpy(s, "..", sizeof(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 */
+ safe_strncpy(s, "..", sizeof(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/iconvert.c b/src/share/utf8/iconvert.c
new file mode 100644
index 0000000..9a1e3f6
--- /dev/null
+++ b/src/share/utf8/iconvert.c
@@ -0,0 +1,257 @@
+/*
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if !defined _WIN32 && defined HAVE_ICONV
+
+#include <assert.h>
+#include <errno.h>
+#include <iconv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "iconvert.h"
+#include "share/alloc.h"
+#include "share/safe_str.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, obp, 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;
+ int rc;
+ /*
+ * 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.
+ */
+
+ rc = asprintf(&tocode1, "%s//TRANSLIT", tocode);
+ if (rc < 0 || ! tocode1)
+ goto fail;
+
+ 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 = 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;
+ obp = ob - utfbuf; /* save position */
+ newbuf = realloc(utfbuf, utflen);
+ if (!newbuf)
+ goto fail;
+ ob = newbuf + obp;
+ obl = utflen - obp;
+ 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 = safe_realloc_nofree_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;
+ if (utflen == 0)
+ goto fail;
+ newbuf = 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 = 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
index 0000000..a2d75a2
--- /dev/null
+++ b/src/share/utf8/iconvert.h
@@ -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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef 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
index 0000000..790021c
--- /dev/null
+++ b/src/share/utf8/makemap.c
@@ -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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef 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;
+ uint8_t 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
index 0000000..34af187
--- /dev/null
+++ b/src/share/utf8/utf8.c
@@ -0,0 +1,202 @@
+/*
+ * 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
+ *
+ * Win32 part rewritten: lvqcl, 2/2/2016
+ *
+ * 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.
+ */
+
+/*
+ * Convert a string between UTF-8 and the locale's charset.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "share/alloc.h"
+#include "share/utf8.h"
+
+#ifdef _WIN32
+
+#include <windows.h>
+
+int utf8_encode(const char *from, char **to)
+{
+ wchar_t *unicode = NULL;
+ char *utf8 = NULL;
+ int ret = -1;
+
+ do {
+ int len;
+
+ len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, -1, NULL, 0);
+ if(len == 0) break;
+ unicode = (wchar_t*) safe_malloc_mul_2op_((size_t)len, sizeof(wchar_t));
+ if(unicode == NULL) break;
+ len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, -1, unicode, len);
+ if(len == 0) break;
+
+ len = WideCharToMultiByte(CP_UTF8, 0, unicode, -1, NULL, 0, NULL, NULL);
+ if(len == 0) break;
+ utf8 = (char*) safe_malloc_mul_2op_((size_t)len, sizeof(char));
+ if(utf8 == NULL) break;
+ len = WideCharToMultiByte(CP_UTF8, 0, unicode, -1, utf8, len, NULL, NULL);
+ if(len == 0) break;
+
+ ret = 0;
+
+ } while(0);
+
+ free(unicode);
+
+ if(ret == 0) {
+ *to = utf8;
+ } else {
+ free(utf8);
+ *to = NULL;
+ }
+
+ return ret;
+}
+
+int utf8_decode(const char *from, char **to)
+{
+ wchar_t *unicode = NULL;
+ char *acp = NULL;
+ int ret = -1;
+
+ do {
+ int len;
+
+ len = MultiByteToWideChar(CP_UTF8, 0, from, -1, NULL, 0);
+ if(len == 0) break;
+ unicode = (wchar_t*) safe_malloc_mul_2op_((size_t)len, sizeof(wchar_t));
+ if(unicode == NULL) break;
+ len = MultiByteToWideChar(CP_UTF8, 0, from, -1, unicode, len);
+ if(len == 0) break;
+
+ len = WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, unicode, -1, NULL, 0, NULL, NULL);
+ if(len == 0) break;
+ acp = (char*) safe_malloc_mul_2op_((size_t)len, sizeof(char));
+ if(acp == NULL) break;
+ len = WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, unicode, -1, acp, len, NULL, NULL);
+ if(len == 0) break;
+
+ ret = 0;
+
+ } while(0);
+
+ free(unicode);
+
+ if(ret == 0) {
+ *to = acp;
+ } else {
+ free(acp);
+ *to = NULL;
+ }
+
+ return ret;
+}
+
+#else /* End win32. Rest is for real operating systems */
+
+
+#ifdef HAVE_LANGINFO_CODESET
+#include <langinfo.h>
+#endif
+
+#include <string.h>
+
+#include "share/safe_str.h"
+#include "iconvert.h"
+#include "charset.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;
+ snprintf(s, fromlen + 1, "%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/win_utf8_io/win_utf8_io.c b/src/share/win_utf8_io/win_utf8_io.c
new file mode 100644
index 0000000..3ae35b3
--- /dev/null
+++ b/src/share/win_utf8_io/win_utf8_io.c
@@ -0,0 +1,398 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2013-2023 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <io.h>
+#include <windows.h>
+#include "share/win_utf8_io.h"
+
+#define UTF8_BUFFER_SIZE 32768
+
+/* detect whether it is Windows APP (UWP) or standard Win32 envionment */
+#ifdef WINAPI_FAMILY_PARTITION
+ #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+ #define FLAC_WINDOWS_APP 1
+ #else
+ #define FLAC_WINDOWS_APP 0
+ #endif
+#else
+ #define FLAC_WINDOWS_APP 0
+#endif
+
+static int local_vsnprintf(char *str, size_t size, const char *fmt, va_list va)
+{
+ int rc;
+
+#if defined _MSC_VER
+ if (size == 0)
+ return 1024;
+ rc = vsnprintf_s(str, size, _TRUNCATE, fmt, va);
+ if (rc < 0)
+ rc = size - 1;
+#elif defined __MINGW32__
+ rc = __mingw_vsnprintf(str, size, fmt, va);
+#else
+ rc = vsnprintf(str, size, fmt, va);
+#endif
+
+ return rc;
+}
+
+/* convert WCHAR stored Unicode string to UTF-8. Caller is responsible for freeing memory */
+static char *utf8_from_wchar(const wchar_t *wstr)
+{
+ char *utf8str;
+ int len;
+
+ if (!wstr)
+ return NULL;
+ if ((len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL)) == 0)
+ return NULL;
+ if ((utf8str = (char *)malloc(len)) == NULL)
+ return NULL;
+ if (WideCharToMultiByte(CP_UTF8, 0, wstr, -1, utf8str, len, NULL, NULL) == 0) {
+ free(utf8str);
+ utf8str = NULL;
+ }
+
+ return utf8str;
+}
+
+/* convert UTF-8 back to WCHAR. Caller is responsible for freeing memory */
+static wchar_t *wchar_from_utf8(const char *str)
+{
+ wchar_t *widestr;
+ int len;
+
+ if (!str)
+ return NULL;
+ if ((len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)) == 0)
+ return NULL;
+ if ((widestr = (wchar_t *)malloc(len*sizeof(wchar_t))) == NULL)
+ return NULL;
+ if (MultiByteToWideChar(CP_UTF8, 0, str, -1, widestr, len) == 0) {
+ free(widestr);
+ widestr = NULL;
+ }
+
+ return widestr;
+}
+
+/* retrieve WCHAR commandline, expand wildcards and convert everything to UTF-8 */
+int get_utf8_argv(int *argc, char ***argv)
+{
+#if !FLAC_WINDOWS_APP
+ typedef int (__cdecl *wgetmainargs_t)(int*, wchar_t***, wchar_t***, int, int*);
+ wgetmainargs_t wgetmainargs;
+ HMODULE handle;
+#endif // !FLAC_WINDOWS_APP
+ int wargc;
+ wchar_t **wargv;
+ wchar_t **wenv;
+ char **utf8argv;
+ int ret, i;
+
+#if FLAC_WINDOWS_APP
+ wargc = __argc;
+ wargv = __wargv;
+ wenv = _wenviron;
+#else // !FLAC_WINDOWS_APP
+ if ((handle = LoadLibraryW(L"msvcrt.dll")) == NULL) return 1;
+ if ((wgetmainargs = (wgetmainargs_t)GetProcAddress(handle, "__wgetmainargs")) == NULL) {
+ FreeLibrary(handle);
+ return 1;
+ }
+ i = 0;
+ /* when the 4th argument is 1, __wgetmainargs expands wildcards but also erroneously converts \\?\c:\path\to\file.flac to \\file.flac */
+ if (wgetmainargs(&wargc, &wargv, &wenv, 1, &i) != 0) {
+ FreeLibrary(handle);
+ return 1;
+ }
+#endif // !FLAC_WINDOWS_APP
+ if ((utf8argv = (char **)calloc(wargc, sizeof(char*))) == NULL) {
+ #if !FLAC_WINDOWS_APP
+ FreeLibrary(handle);
+ #endif // !FLAC_WINDOWS_APP
+ return 1;
+ }
+
+ ret = 0;
+ for (i=0; i<wargc; i++) {
+ if ((utf8argv[i] = utf8_from_wchar(wargv[i])) == NULL) {
+ ret = 1;
+ break;
+ }
+ }
+
+#if !FLAC_WINDOWS_APP
+ FreeLibrary(handle); /* do not free it when wargv or wenv are still in use */
+#endif // !FLAC_WINDOWS_APP
+
+ if (ret == 0) {
+ *argc = wargc;
+ *argv = utf8argv;
+ } else {
+ for (i=0; i<wargc; i++)
+ free(utf8argv[i]);
+ free(utf8argv);
+ }
+
+ return ret;
+}
+
+/* similar to CreateFileW but accepts UTF-8 encoded lpFileName */
+HANDLE WINAPI CreateFile_utf8(const char *lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
+{
+ wchar_t *wname;
+ HANDLE handle = INVALID_HANDLE_VALUE;
+
+ if ((wname = wchar_from_utf8(lpFileName)) != NULL) {
+#if !FLAC_WINDOWS_APP
+ handle = CreateFileW(wname, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
+#else // FLAC_WINDOWS_APP
+ CREATEFILE2_EXTENDED_PARAMETERS params;
+ params.dwSize = sizeof(params);
+ params.dwFileAttributes = dwFlagsAndAttributes & 0xFFFF;
+ params.dwFileFlags = dwFlagsAndAttributes & 0xFFF00000;
+ params.dwSecurityQosFlags = dwFlagsAndAttributes & 0x000F0000;
+ params.lpSecurityAttributes = lpSecurityAttributes;
+ params.hTemplateFile = hTemplateFile;
+ handle = CreateFile2(wname, dwDesiredAccess, dwShareMode, dwCreationDisposition, &params);
+#endif // FLAC_WINDOWS_APP
+ free(wname);
+ }
+
+ return handle;
+}
+
+/* return number of characters in the UTF-8 string */
+size_t strlen_utf8(const char *str)
+{
+ size_t len;
+ len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); /* includes terminating null */
+ if (len != 0)
+ return len-1;
+ else
+ return strlen(str);
+}
+
+/* get the console width in characters */
+int win_get_console_width(void)
+{
+ int width = 80;
+#if !FLAC_WINDOWS_APP
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+ HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
+ if(hOut != INVALID_HANDLE_VALUE && hOut != NULL)
+ if (GetConsoleScreenBufferInfo(hOut, &csbi) != 0)
+ width = csbi.dwSize.X;
+#endif // !FLAC_WINDOWS_APP
+ return width;
+}
+
+/* print functions */
+
+#if !FLAC_WINDOWS_APP
+static int wprint_console(FILE *stream, const wchar_t *text, size_t len)
+{
+ DWORD out;
+ int ret;
+
+ do {
+ if (stream == stdout) {
+ HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (hOut == INVALID_HANDLE_VALUE || hOut == NULL || GetFileType(hOut) != FILE_TYPE_CHAR)
+ break;
+ if (WriteConsoleW(hOut, text, len, &out, NULL) == 0)
+ return -1;
+ return out;
+ }
+ if (stream == stderr) {
+ HANDLE hErr = GetStdHandle(STD_ERROR_HANDLE);
+ if (hErr == INVALID_HANDLE_VALUE || hErr == NULL || GetFileType(hErr) != FILE_TYPE_CHAR)
+ break;
+ if (WriteConsoleW(hErr, text, len, &out, NULL) == 0)
+ return -1;
+ return out;
+ }
+ } while(0);
+
+ ret = fputws(text, stream);
+ if (ret < 0)
+ return ret;
+ return len;
+}
+#endif // !FLAC_WINDOWS_APP
+
+int printf_utf8(const char *format, ...)
+{
+ int ret;
+ va_list argptr;
+ va_start(argptr, format);
+
+ ret = vfprintf_utf8(stdout, format, argptr);
+
+ va_end(argptr);
+
+ return ret;
+}
+
+int fprintf_utf8(FILE *stream, const char *format, ...)
+{
+ int ret;
+ va_list argptr;
+ va_start(argptr, format);
+
+ ret = vfprintf_utf8(stream, format, argptr);
+
+ va_end(argptr);
+
+ return ret;
+}
+
+int vfprintf_utf8(FILE *stream, const char *format, va_list argptr)
+{
+ char *utmp = NULL;
+ wchar_t *wout = NULL;
+ int ret = -1;
+
+ do {
+ if (!(utmp = (char *)malloc(UTF8_BUFFER_SIZE))) break;
+ if ((ret = local_vsnprintf(utmp, UTF8_BUFFER_SIZE, format, argptr)) <= 0) break;
+ if (!(wout = wchar_from_utf8(utmp))) {
+ ret = -1;
+ break;
+ }
+#if !FLAC_WINDOWS_APP
+ ret = wprint_console(stream, wout, wcslen(wout));
+#else // FLAC_WINDOWS_APP
+ OutputDebugStringW(wout);
+ ret = 0;
+#endif // FLAC_WINDOWS_APP
+ } while(0);
+
+ free(utmp);
+ free(wout);
+
+ return ret;
+}
+
+/* file functions */
+
+FILE* fopen_utf8(const char *filename, const char *mode)
+{
+ wchar_t *wname = NULL;
+ wchar_t *wmode = NULL;
+ FILE *f = NULL;
+
+ do {
+ if (!(wname = wchar_from_utf8(filename))) break;
+ if (!(wmode = wchar_from_utf8(mode))) break;
+ f = _wfopen(wname, wmode);
+ } while(0);
+
+ free(wname);
+ free(wmode);
+
+ return f;
+}
+
+int stat64_utf8(const char *path, struct __stat64 *buffer)
+{
+ wchar_t *wpath;
+ int ret;
+
+ if (!(wpath = wchar_from_utf8(path))) return -1;
+ ret = _wstat64(wpath, buffer);
+ free(wpath);
+
+ return ret;
+}
+
+int chmod_utf8(const char *filename, int pmode)
+{
+ wchar_t *wname;
+ int ret;
+
+ if (!(wname = wchar_from_utf8(filename))) return -1;
+ ret = _wchmod(wname, pmode);
+ free(wname);
+
+ return ret;
+}
+
+int utime_utf8(const char *filename, struct utimbuf *times)
+{
+ wchar_t *wname;
+ struct __utimbuf64 ut;
+ int ret;
+
+ if (!(wname = wchar_from_utf8(filename))) return -1;
+ ut.actime = times->actime;
+ ut.modtime = times->modtime;
+ ret = _wutime64(wname, &ut);
+ free(wname);
+
+ return ret;
+}
+
+int unlink_utf8(const char *filename)
+{
+ wchar_t *wname;
+ int ret;
+
+ if (!(wname = wchar_from_utf8(filename))) return -1;
+ ret = _wunlink(wname);
+ free(wname);
+
+ return ret;
+}
+
+int rename_utf8(const char *oldname, const char *newname)
+{
+ wchar_t *wold = NULL;
+ wchar_t *wnew = NULL;
+ int ret = -1;
+
+ do {
+ if (!(wold = wchar_from_utf8(oldname))) break;
+ if (!(wnew = wchar_from_utf8(newname))) break;
+ ret = _wrename(wold, wnew);
+ } while(0);
+
+ free(wold);
+ free(wnew);
+
+ return ret;
+}
diff --git a/src/test_grabbag/CMakeLists.txt b/src/test_grabbag/CMakeLists.txt
new file mode 100644
index 0000000..56abe81
--- /dev/null
+++ b/src/test_grabbag/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(cuesheet)
+add_subdirectory(picture)
diff --git a/src/test_grabbag/Makefile.am b/src/test_grabbag/Makefile.am
new file mode 100644
index 0000000..ea71009
--- /dev/null
+++ b/src/test_grabbag/Makefile.am
@@ -0,0 +1,22 @@
+# FLAC - Free Lossless Audio Codec
+# Copyright (C) 2002-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This file is part the FLAC project. FLAC is comprised of several
+# components distributed under different 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 = \
+ CMakeLists.txt
diff --git a/src/test_grabbag/Makefile.in b/src/test_grabbag/Makefile.in
new file mode 100644
index 0000000..3d85721
--- /dev/null
+++ b/src/test_grabbag/Makefile.in
@@ -0,0 +1,679 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in 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.
+
+@SET_MAKE@
+
+# FLAC - Free Lossless Audio Codec
+# Copyright (C) 2002-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This file is part the FLAC project. FLAC is comprised of several
+# components distributed under different 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.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/test_grabbag
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/add_cflags.m4 \
+ $(top_srcdir)/m4/add_cxxflags.m4 \
+ $(top_srcdir)/m4/ax_add_fortify_source.m4 \
+ $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_enable_debug.m4 \
+ $(top_srcdir)/m4/bswap.m4 $(top_srcdir)/m4/clang.m4 \
+ $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gcc_version.m4 \
+ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/ogg.m4 \
+ $(top_srcdir)/m4/really_gcc.m4 \
+ $(top_srcdir)/m4/stack_protect.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_64_BIT_WORDS = @ENABLE_64_BIT_WORDS@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLAC__HAS_OGG = @FLAC__HAS_OGG@
+FLAC__TEST_LEVEL = @FLAC__TEST_LEVEL@
+FLAC__TEST_WITH_VALGRIND = @FLAC__TEST_WITH_VALGRIND@
+GCC_MAJOR_VERSION = @GCC_MAJOR_VERSION@
+GCC_MINOR_VERSION = @GCC_MINOR_VERSION@
+GCC_VERSION = @GCC_VERSION@
+GIT_COMMIT_VERSION_HASH = @GIT_COMMIT_VERSION_HASH@
+GIT_FOUND = @GIT_FOUND@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_FUZZING_ENGINE = @LIB_FUZZING_ENGINE@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OBJ_FORMAT = @OBJ_FORMAT@
+OGG_CFLAGS = @OGG_CFLAGS@
+OGG_LIBS = @OGG_LIBS@
+OGG_PACKAGE = @OGG_PACKAGE@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = cuesheet picture
+EXTRA_DIST = \
+ CMakeLists.txt
+
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/test_grabbag/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/test_grabbag/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-generic clean-libtool cscopelist-am ctags \
+ ctags-am distclean distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/test_grabbag/cuesheet/CMakeLists.txt b/src/test_grabbag/cuesheet/CMakeLists.txt
new file mode 100644
index 0000000..5f9a646
--- /dev/null
+++ b/src/test_grabbag/cuesheet/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_executable(test_cuesheet
+ main.c
+ $<$<BOOL:${WIN32}>:../../../include/share/win_utf8_io.h>
+ $<$<BOOL:${WIN32}>:../../share/win_utf8_io/win_utf8_io.c>)
+target_link_libraries(test_cuesheet FLAC grabbag)
diff --git a/src/test_grabbag/cuesheet/Makefile.am b/src/test_grabbag/cuesheet/Makefile.am
new file mode 100644
index 0000000..1cee370
--- /dev/null
+++ b/src/test_grabbag/cuesheet/Makefile.am
@@ -0,0 +1,37 @@
+# test_cuesheet - Simple tester for cuesheet routines in grabbag
+# Copyright (C) 2002-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+EXTRA_DIST = \
+ CMakeLists.txt
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+check_PROGRAMS = test_cuesheet
+test_cuesheet_SOURCES = \
+ main.c
+
+if OS_IS_WINDOWS
+win_utf8_lib = $(top_builddir)/src/share/win_utf8_io/libwin_utf8_io.la
+endif
+
+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 \
+ $(win_utf8_lib)
+
+CLEANFILES = test_cuesheet.exe
diff --git a/src/test_grabbag/cuesheet/Makefile.in b/src/test_grabbag/cuesheet/Makefile.in
new file mode 100644
index 0000000..6188573
--- /dev/null
+++ b/src/test_grabbag/cuesheet/Makefile.in
@@ -0,0 +1,669 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in 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.
+
+@SET_MAKE@
+
+# test_cuesheet - Simple tester for cuesheet routines in grabbag
+# Copyright (C) 2002-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+check_PROGRAMS = test_cuesheet$(EXEEXT)
+subdir = src/test_grabbag/cuesheet
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/add_cflags.m4 \
+ $(top_srcdir)/m4/add_cxxflags.m4 \
+ $(top_srcdir)/m4/ax_add_fortify_source.m4 \
+ $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_enable_debug.m4 \
+ $(top_srcdir)/m4/bswap.m4 $(top_srcdir)/m4/clang.m4 \
+ $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gcc_version.m4 \
+ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/ogg.m4 \
+ $(top_srcdir)/m4/really_gcc.m4 \
+ $(top_srcdir)/m4/stack_protect.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am_test_cuesheet_OBJECTS = main.$(OBJEXT)
+test_cuesheet_OBJECTS = $(am_test_cuesheet_OBJECTS)
+test_cuesheet_DEPENDENCIES = \
+ $(top_builddir)/src/share/grabbag/libgrabbag.la \
+ $(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \
+ $(top_builddir)/src/libFLAC/libFLAC.la $(win_utf8_lib)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/main.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(test_cuesheet_SOURCES)
+DIST_SOURCES = $(test_cuesheet_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_64_BIT_WORDS = @ENABLE_64_BIT_WORDS@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLAC__HAS_OGG = @FLAC__HAS_OGG@
+FLAC__TEST_LEVEL = @FLAC__TEST_LEVEL@
+FLAC__TEST_WITH_VALGRIND = @FLAC__TEST_WITH_VALGRIND@
+GCC_MAJOR_VERSION = @GCC_MAJOR_VERSION@
+GCC_MINOR_VERSION = @GCC_MINOR_VERSION@
+GCC_VERSION = @GCC_VERSION@
+GIT_COMMIT_VERSION_HASH = @GIT_COMMIT_VERSION_HASH@
+GIT_FOUND = @GIT_FOUND@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_FUZZING_ENGINE = @LIB_FUZZING_ENGINE@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OBJ_FORMAT = @OBJ_FORMAT@
+OGG_CFLAGS = @OGG_CFLAGS@
+OGG_LIBS = @OGG_LIBS@
+OGG_PACKAGE = @OGG_PACKAGE@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = \
+ CMakeLists.txt
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+test_cuesheet_SOURCES = \
+ main.c
+
+@OS_IS_WINDOWS_TRUE@win_utf8_lib = $(top_builddir)/src/share/win_utf8_io/libwin_utf8_io.la
+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 \
+ $(win_utf8_lib)
+
+CLEANFILES = test_cuesheet.exe
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/test_grabbag/cuesheet/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/test_grabbag/cuesheet/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+ @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+test_cuesheet$(EXEEXT): $(test_cuesheet_OBJECTS) $(test_cuesheet_DEPENDENCIES) $(EXTRA_test_cuesheet_DEPENDENCIES)
+ @rm -f test_cuesheet$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_cuesheet_OBJECTS) $(test_cuesheet_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/main.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/main.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-checkPROGRAMS clean-generic clean-libtool cscopelist-am \
+ ctags ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/test_grabbag/cuesheet/main.c b/src/test_grabbag/cuesheet/main.c
new file mode 100644
index 0000000..b3d0e9a
--- /dev/null
+++ b/src/test_grabbag/cuesheet/main.c
@@ -0,0 +1,147 @@
+/* test_cuesheet - Simple tester for cuesheet routines in grabbag
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+#include "share/grabbag.h"
+
+static int do_cuesheet(const char *infilename, uint32_t sample_rate, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset)
+{
+ FILE *fin, *fout;
+ const char *error_message, *tmpfilenamebase;
+ char tmpfilename[4096];
+ uint32_t 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 = flac_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, sample_rate, 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;
+ }
+
+ tmpfilenamebase = strstr(infilename, "cuesheets/");
+ tmpfilenamebase = tmpfilenamebase == NULL ? infilename : tmpfilenamebase;
+
+ flac_snprintf(tmpfilename, sizeof (tmpfilename), "%s.1", tmpfilenamebase);
+ if(0 == (fout = flac_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 = flac_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, sample_rate, 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;
+ }
+ flac_snprintf(tmpfilename, sizeof (tmpfilename), "%s.2", tmpfilenamebase);
+ if(0 == (fout = flac_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;
+ uint32_t sample_rate = 48000;
+ FLAC__bool is_cdda = false;
+ const char *usage = "usage: test_cuesheet cuesheet_file lead_out_offset [ [ sample_rate ] cdda ]\n";
+
+ if(argc > 1 && 0 == strcmp(argv[1], "-h")) {
+ puts(usage);
+ return 0;
+ }
+
+ if(argc < 3 || argc > 5) {
+ fputs(usage, stderr);
+ return 255;
+ }
+
+ lead_out_offset = (FLAC__uint64)strtoul(argv[2], 0, 10);
+ if(argc >= 4) {
+ sample_rate = (uint32_t)atoi(argv[3]);
+ if(argc >= 5) {
+ if(0 == strcmp(argv[4], "cdda"))
+ is_cdda = true;
+ else {
+ fputs(usage, stderr);
+ return 255;
+ }
+ }
+ }
+
+ return do_cuesheet(argv[1], sample_rate, is_cdda, lead_out_offset);
+}
diff --git a/src/test_grabbag/picture/CMakeLists.txt b/src/test_grabbag/picture/CMakeLists.txt
new file mode 100644
index 0000000..77f1a38
--- /dev/null
+++ b/src/test_grabbag/picture/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_executable(test_picture
+ main.c
+ $<$<BOOL:${WIN32}>:../../../include/share/win_utf8_io.h>
+ $<$<BOOL:${WIN32}>:../../share/win_utf8_io/win_utf8_io.c>)
+target_link_libraries(test_picture FLAC grabbag)
diff --git a/src/test_grabbag/picture/Makefile.am b/src/test_grabbag/picture/Makefile.am
new file mode 100644
index 0000000..45e1457
--- /dev/null
+++ b/src/test_grabbag/picture/Makefile.am
@@ -0,0 +1,37 @@
+# test_picture - Simple tester for picture routines in grabbag
+# Copyright (C) 2006-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+EXTRA_DIST = \
+ CMakeLists.txt
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+check_PROGRAMS = test_picture
+test_picture_SOURCES = \
+ main.c
+
+if OS_IS_WINDOWS
+win_utf8_lib = $(top_builddir)/src/share/win_utf8_io/libwin_utf8_io.la
+endif
+
+test_picture_LDADD = \
+ $(top_builddir)/src/share/grabbag/libgrabbag.la \
+ $(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \
+ $(top_builddir)/src/libFLAC/libFLAC.la \
+ $(win_utf8_lib)
+
+CLEANFILES = test_picture.exe
diff --git a/src/test_grabbag/picture/Makefile.in b/src/test_grabbag/picture/Makefile.in
new file mode 100644
index 0000000..43f1a7a
--- /dev/null
+++ b/src/test_grabbag/picture/Makefile.in
@@ -0,0 +1,669 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in 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.
+
+@SET_MAKE@
+
+# test_picture - Simple tester for picture routines in grabbag
+# Copyright (C) 2006-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+check_PROGRAMS = test_picture$(EXEEXT)
+subdir = src/test_grabbag/picture
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/add_cflags.m4 \
+ $(top_srcdir)/m4/add_cxxflags.m4 \
+ $(top_srcdir)/m4/ax_add_fortify_source.m4 \
+ $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_enable_debug.m4 \
+ $(top_srcdir)/m4/bswap.m4 $(top_srcdir)/m4/clang.m4 \
+ $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gcc_version.m4 \
+ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/ogg.m4 \
+ $(top_srcdir)/m4/really_gcc.m4 \
+ $(top_srcdir)/m4/stack_protect.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am_test_picture_OBJECTS = main.$(OBJEXT)
+test_picture_OBJECTS = $(am_test_picture_OBJECTS)
+test_picture_DEPENDENCIES = \
+ $(top_builddir)/src/share/grabbag/libgrabbag.la \
+ $(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \
+ $(top_builddir)/src/libFLAC/libFLAC.la $(win_utf8_lib)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/main.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(test_picture_SOURCES)
+DIST_SOURCES = $(test_picture_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_64_BIT_WORDS = @ENABLE_64_BIT_WORDS@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLAC__HAS_OGG = @FLAC__HAS_OGG@
+FLAC__TEST_LEVEL = @FLAC__TEST_LEVEL@
+FLAC__TEST_WITH_VALGRIND = @FLAC__TEST_WITH_VALGRIND@
+GCC_MAJOR_VERSION = @GCC_MAJOR_VERSION@
+GCC_MINOR_VERSION = @GCC_MINOR_VERSION@
+GCC_VERSION = @GCC_VERSION@
+GIT_COMMIT_VERSION_HASH = @GIT_COMMIT_VERSION_HASH@
+GIT_FOUND = @GIT_FOUND@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_FUZZING_ENGINE = @LIB_FUZZING_ENGINE@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OBJ_FORMAT = @OBJ_FORMAT@
+OGG_CFLAGS = @OGG_CFLAGS@
+OGG_LIBS = @OGG_LIBS@
+OGG_PACKAGE = @OGG_PACKAGE@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = \
+ CMakeLists.txt
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+test_picture_SOURCES = \
+ main.c
+
+@OS_IS_WINDOWS_TRUE@win_utf8_lib = $(top_builddir)/src/share/win_utf8_io/libwin_utf8_io.la
+test_picture_LDADD = \
+ $(top_builddir)/src/share/grabbag/libgrabbag.la \
+ $(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \
+ $(top_builddir)/src/libFLAC/libFLAC.la \
+ $(win_utf8_lib)
+
+CLEANFILES = test_picture.exe
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/test_grabbag/picture/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/test_grabbag/picture/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+ @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+test_picture$(EXEEXT): $(test_picture_OBJECTS) $(test_picture_DEPENDENCIES) $(EXTRA_test_picture_DEPENDENCIES)
+ @rm -f test_picture$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_picture_OBJECTS) $(test_picture_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/main.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/main.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-checkPROGRAMS clean-generic clean-libtool cscopelist-am \
+ ctags ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/test_grabbag/picture/main.c b/src/test_grabbag/picture/main.c
new file mode 100644
index 0000000..fe43be9
--- /dev/null
+++ b/src/test_grabbag/picture/main.c
@@ -0,0 +1,222 @@
+/* test_picture - Simple tester for picture routines in grabbag
+ * Copyright (C) 2006-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <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 PictureResolution * res, FLAC__bool fn_only)
+{
+ FLAC__StreamMetadata *obj;
+ const char *error;
+ char s[4096];
+ if(fn_only)
+ flac_snprintf(s, sizeof(s), "pictures/%s", pf->path);
+ else if (res == NULL)
+ flac_snprintf(s, sizeof(s), "%u|%s|%s||pictures/%s", (uint32_t)pf->type, pf->mime_type, pf->description, pf->path);
+ else
+ flac_snprintf(s, sizeof(s), "%u|%s|%s|%dx%dx%d/%d|pictures/%s", (uint32_t)pf->type, pf->mime_type, pf->description, res->width, res->height, res->depth, res->colors, pf->path);
+
+ printf("testing grabbag__picture_parse_specification(\"%s\")... ", s);
+
+ flac_snprintf(s, sizeof(s), "%s/%s", prefix, pf->path);
+ if((obj = grabbag__picture_from_specification(fn_only? FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER : pf->type, pf->mime_type, pf->description, res, s, &error)) == 0)
+ 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;
+ PictureResolution res;
+ 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, NULL, /*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, NULL, /*fn_only=*/false))
+ return false;
+
+ res.width = picturefiles[0].width = 320;
+ res.height = picturefiles[0].height = 240;
+ res.depth = picturefiles[0].depth = 3;
+ res.colors = picturefiles[0].colors = 2;
+ if(!test_one_picture(prefix, picturefiles+0, &res, /*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")) {
+ puts(usage);
+ return 0;
+ }
+
+ if(argc != 2) {
+ fputs(usage, stderr);
+ return 255;
+ }
+
+ return do_picture(argv[1])? 0 : 1;
+}
diff --git a/src/test_libFLAC++/CMakeLists.txt b/src/test_libFLAC++/CMakeLists.txt
new file mode 100644
index 0000000..2fa7b1e
--- /dev/null
+++ b/src/test_libFLAC++/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_executable(test_libFLAC++
+ decoders.cpp
+ encoders.cpp
+ main.cpp
+ metadata.cpp
+ metadata_manip.cpp
+ metadata_object.cpp
+ $<$<BOOL:${WIN32}>:../../include/share/win_utf8_io.h>
+ $<$<BOOL:${WIN32}>:../share/win_utf8_io/win_utf8_io.c>)
+target_link_libraries(test_libFLAC++ FLAC++ test_libs_common grabbag)
diff --git a/src/test_libFLAC++/Makefile.am b/src/test_libFLAC++/Makefile.am
new file mode 100644
index 0000000..8bf746f
--- /dev/null
+++ b/src/test_libFLAC++/Makefile.am
@@ -0,0 +1,50 @@
+# test_libFLAC++ - Unit tester for libFLAC++
+# Copyright (C) 2002-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+EXTRA_DIST = \
+ CMakeLists.txt
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+check_PROGRAMS = test_libFLAC++
+
+if OS_IS_WINDOWS
+win_utf8_lib = $(top_builddir)/src/share/win_utf8_io/libwin_utf8_io.la
+endif
+
+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 \
+ $(win_utf8_lib) \
+ @OGG_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
+
+CLEANFILES = test_libFLAC++.exe
diff --git a/src/test_libFLAC++/Makefile.in b/src/test_libFLAC++/Makefile.in
new file mode 100644
index 0000000..825dad6
--- /dev/null
+++ b/src/test_libFLAC++/Makefile.in
@@ -0,0 +1,720 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in 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.
+
+@SET_MAKE@
+
+# test_libFLAC++ - Unit tester for libFLAC++
+# Copyright (C) 2002-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+check_PROGRAMS = test_libFLAC++$(EXEEXT)
+subdir = src/test_libFLAC++
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/add_cflags.m4 \
+ $(top_srcdir)/m4/add_cxxflags.m4 \
+ $(top_srcdir)/m4/ax_add_fortify_source.m4 \
+ $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_enable_debug.m4 \
+ $(top_srcdir)/m4/bswap.m4 $(top_srcdir)/m4/clang.m4 \
+ $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gcc_version.m4 \
+ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/ogg.m4 \
+ $(top_srcdir)/m4/really_gcc.m4 \
+ $(top_srcdir)/m4/stack_protect.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am_test_libFLAC___OBJECTS = decoders.$(OBJEXT) encoders.$(OBJEXT) \
+ main.$(OBJEXT) metadata.$(OBJEXT) metadata_manip.$(OBJEXT) \
+ metadata_object.$(OBJEXT)
+test_libFLAC___OBJECTS = $(am_test_libFLAC___OBJECTS)
+test_libFLAC___DEPENDENCIES = \
+ $(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 $(win_utf8_lib)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/decoders.Po ./$(DEPDIR)/encoders.Po \
+ ./$(DEPDIR)/main.Po ./$(DEPDIR)/metadata.Po \
+ ./$(DEPDIR)/metadata_manip.Po ./$(DEPDIR)/metadata_object.Po
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(test_libFLAC___SOURCES)
+DIST_SOURCES = $(test_libFLAC___SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_64_BIT_WORDS = @ENABLE_64_BIT_WORDS@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLAC__HAS_OGG = @FLAC__HAS_OGG@
+FLAC__TEST_LEVEL = @FLAC__TEST_LEVEL@
+FLAC__TEST_WITH_VALGRIND = @FLAC__TEST_WITH_VALGRIND@
+GCC_MAJOR_VERSION = @GCC_MAJOR_VERSION@
+GCC_MINOR_VERSION = @GCC_MINOR_VERSION@
+GCC_VERSION = @GCC_VERSION@
+GIT_COMMIT_VERSION_HASH = @GIT_COMMIT_VERSION_HASH@
+GIT_FOUND = @GIT_FOUND@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_FUZZING_ENGINE = @LIB_FUZZING_ENGINE@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OBJ_FORMAT = @OBJ_FORMAT@
+OGG_CFLAGS = @OGG_CFLAGS@
+OGG_LIBS = @OGG_LIBS@
+OGG_PACKAGE = @OGG_PACKAGE@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = \
+ CMakeLists.txt
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+@OS_IS_WINDOWS_TRUE@win_utf8_lib = $(top_builddir)/src/share/win_utf8_io/libwin_utf8_io.la
+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 \
+ $(win_utf8_lib) \
+ @OGG_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
+
+CLEANFILES = test_libFLAC++.exe
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cpp .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/test_libFLAC++/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/test_libFLAC++/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+ @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+test_libFLAC++$(EXEEXT): $(test_libFLAC___OBJECTS) $(test_libFLAC___DEPENDENCIES) $(EXTRA_test_libFLAC___DEPENDENCIES)
+ @rm -f test_libFLAC++$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(test_libFLAC___OBJECTS) $(test_libFLAC___LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decoders.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/encoders.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/metadata.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/metadata_manip.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/metadata_object.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.cpp.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/decoders.Po
+ -rm -f ./$(DEPDIR)/encoders.Po
+ -rm -f ./$(DEPDIR)/main.Po
+ -rm -f ./$(DEPDIR)/metadata.Po
+ -rm -f ./$(DEPDIR)/metadata_manip.Po
+ -rm -f ./$(DEPDIR)/metadata_object.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/decoders.Po
+ -rm -f ./$(DEPDIR)/encoders.Po
+ -rm -f ./$(DEPDIR)/main.Po
+ -rm -f ./$(DEPDIR)/metadata.Po
+ -rm -f ./$(DEPDIR)/metadata_manip.Po
+ -rm -f ./$(DEPDIR)/metadata_object.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-checkPROGRAMS clean-generic clean-libtool cscopelist-am \
+ ctags ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/test_libFLAC++/decoders.cpp b/src/test_libFLAC++/decoders.cpp
new file mode 100644
index 0000000..9f375f3
--- /dev/null
+++ b/src/test_libFLAC++/decoders.cpp
@@ -0,0 +1,1179 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "decoders.h"
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h" // for ::FLAC__metadata_object_is_equal()
+#include "FLAC++/decoder.h"
+#include "share/grabbag.h"
+#include "share/compat.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 uint32_t num_expected_;
+static FLAC__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", (uint32_t)((::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_;
+ uint32_t current_metadata_number_;
+ bool ignore_errors_;
+ bool error_occurred_;
+
+ DecoderCommon(Layer layer): layer_(layer), current_metadata_number_(0), ignore_errors_(false), error_occurred_(false) { }
+ virtual ~DecoderCommon(void) { }
+ ::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("%u... ", 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", (uint32_t)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);
+private:
+ StreamDecoder(const StreamDecoder&);
+ StreamDecoder&operator=(const StreamDecoder&);
+};
+
+::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_, (FLAC__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;
+
+ FLAC__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", (uint32_t)((::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", (uint32_t)((::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 = ::flac_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", (uint32_t)((::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", (uint32_t)((::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");
+ delete decoder;
+ 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");
+ delete decoder;
+ 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");
+ delete decoder;
+ 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");
+ delete decoder;
+ 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_ = ::flac_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 = ::flac_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", (uint32_t)((::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()... ");
+ {
+ uint32_t 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()... ");
+ {
+ uint32_t 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()... ");
+ {
+ uint32_t 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()... ");
+ {
+ uint32_t 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", (uint32_t)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()) {
+ state = decoder->get_state();
+ printf("FAILED, returned false, state = %u (%s)\n", (uint32_t)((::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. Also removes the seektable */
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &application1_;
+ expected_metadata_sequence_[num_expected_++] = &application2_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+ else {
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &seektable_;
+ expected_metadata_sequence_[num_expected_++] = &application1_;
+ expected_metadata_sequence_[num_expected_++] = &application2_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+
+ if(!(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_;
+ if(!is_ogg) /* encoder removes seektable for ogg */
+ expected_metadata_sequence_[num_expected_++] = &seektable_;
+ expected_metadata_sequence_[num_expected_++] = &application1_;
+ expected_metadata_sequence_[num_expected_++] = &application2_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+ if(!(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. Also removes the seektable */
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+ else {
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &seektable_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+
+ if(!(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. Also removes the seektable */
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &application2_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+ else {
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &seektable_;
+ expected_metadata_sequence_[num_expected_++] = &application2_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+
+ if(!(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. Also removes seektable */
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+ else {
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &seektable_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+
+ if(!(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. Also removes the seektable */
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &application1_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+ else {
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &seektable_;
+ expected_metadata_sequence_[num_expected_++] = &application1_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+
+ if(!(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
index 0000000..4bbce13
--- /dev/null
+++ b/src/test_libFLAC++/decoders.h
@@ -0,0 +1,25 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#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
index 0000000..0e356af
--- /dev/null
+++ b/src/test_libFLAC++/encoders.cpp
@@ -0,0 +1,576 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "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>
+#include "share/compat.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_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 uint32_t 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", (uint32_t)((::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", (uint32_t)((::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, uint32_t samples, uint32_t 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);
+private:
+ StreamEncoder(const StreamEncoder&);
+ StreamEncoder&operator=(const StreamEncoder&);
+};
+
+::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, uint32_t samples, uint32_t 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(fseeko(file_, (FLAC__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 StreamEncoder::tell_callback(FLAC__uint64 *absolute_byte_offset)
+{
+ FLAC__off_t pos;
+ if(layer_==LAYER_STREAM)
+ 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;
+ }
+}
+
+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, uint32_t frames_written, uint32_t total_frames_estimate);
+};
+
+void FileEncoder::progress_callback(FLAC__uint64 bytes_written, FLAC__uint64 samples_written, uint32_t frames_written, uint32_t 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 };
+ uint32_t 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");
+ delete encoder;
+ 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((uint32_t)(-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");
+
+ printf("testing set_limit_min_bitrate()... ");
+ if(!encoder->set_limit_min_bitrate(true))
+ return die_s_("returned false", encoder);
+ printf("OK\n");
+
+ if(layer < LAYER_FILENAME) {
+ printf("opening file for FLAC output... ");
+ file = ::flac_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", (uint32_t)((::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", (uint32_t)((::FLAC__StreamDecoderState)dstate), dstate.as_cstring());
+
+ {
+ FLAC__uint64 absolute_sample;
+ uint32_t frame_number;
+ uint32_t channel;
+ uint32_t 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 %d, 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 %d, 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 %d, 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 %d, got %u\n", 0, encoder->get_rice_parameter_search_dist());
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing get_total_samples_estimate()... ");
+ if(encoder->get_total_samples_estimate() != streaminfo_.data.stream_info.total_samples) {
+ printf("FAILED, expected %" PRIu64 ", got %" PRIu64 "\n", streaminfo_.data.stream_info.total_samples, encoder->get_total_samples_estimate());
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing get_limit_min_bitrate()... ");
+ if(encoder->get_limit_min_bitrate() != true) {
+ printf("FAILED, expected true, got false\n");
+ 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()) {
+ state = encoder->get_state();
+ printf("FAILED, returned false, state = %u (%s)\n", (uint32_t)((::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
index 0000000..9da415c
--- /dev/null
+++ b/src/test_libFLAC++/encoders.h
@@ -0,0 +1,25 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#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
index 0000000..7183def
--- /dev/null
+++ b/src/test_libFLAC++/main.cpp
@@ -0,0 +1,42 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "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
index 0000000..a31031b
--- /dev/null
+++ b/src/test_libFLAC++/metadata.cpp
@@ -0,0 +1,41 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "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
index 0000000..8c45bc0
--- /dev/null
+++ b/src/test_libFLAC++/metadata.h
@@ -0,0 +1,25 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#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
index 0000000..5d395db
--- /dev/null
+++ b/src/test_libFLAC++/metadata_manip.cpp
@@ -0,0 +1,2241 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcpy()/memset() */
+#include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
+#ifdef _MSC_VER
+#include <sys/utime.h>
+#endif
+#if !defined _MSC_VER && !defined __MINGW32__ && !defined __EMX__
+#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"
+#include "share/compat.h"
+#include "share/macros.h"
+#include "share/safe_str.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];
+ uint32_t 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 uint32_t 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", (uint32_t)((::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", (uint32_t)((::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", (uint32_t)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, uint32_t position, bool copy)
+{
+ uint32_t 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, uint32_t position, bool copy)
+{
+ uint32_t 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_(uint32_t position)
+{
+ uint32_t 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_(uint32_t indx, int delta)
+{
+ FLAC::Metadata::Padding *padding = dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[indx]);
+ FLAC__ASSERT(0 != padding);
+ padding->set_length((uint32_t)((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";
+ size_t destlen = strlen(filename) + strlen(tempfile_suffix) + 1;
+
+ *tempfilename = (char*)malloc(destlen);
+ if (*tempfilename == 0)
+ return false;
+ flac_snprintf(*tempfilename, destlen, "%s%s", filename, tempfile_suffix);
+
+ *tempfile = flac_fopen(*tempfilename, "wb");
+ if (*tempfile == 0)
+ return false;
+
+ return true;
+}
+
+void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
+{
+ if (*tempfile != 0) {
+ (void)fclose(*tempfile);
+ *tempfile = 0;
+ }
+
+ if (*tempfilename != 0) {
+ (void)flac_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, flac_rename() will fail if the destination already exists */
+ if(flac_unlink(filename) < 0) {
+ cleanup_tempfile_(tempfile, tempfilename);
+ return false;
+ }
+#endif
+
+ if(0 != flac_rename(*tempfilename, filename)) {
+ cleanup_tempfile_(tempfile, tempfilename);
+ return false;
+ }
+
+ cleanup_tempfile_(tempfile, tempfilename);
+
+ return true;
+}
+
+bool get_file_stats_(const char *filename, struct flac_stat_s *stats)
+{
+ FLAC__ASSERT(0 != filename);
+ FLAC__ASSERT(0 != stats);
+ return (0 == flac_stat(filename, stats));
+}
+
+void set_file_stats_(const char *filename, struct flac_stat_s *stats)
+{
+ FLAC__ASSERT(0 != filename);
+ FLAC__ASSERT(0 != stats);
+
+#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L) && !defined(_WIN32)
+ struct timespec srctime[2] = {};
+ srctime[0].tv_sec = stats->st_atime;
+ srctime[1].tv_sec = stats->st_mtime;
+#else
+ struct utimbuf srctime;
+ srctime.actime = stats->st_atime;
+ srctime.modtime = stats->st_mtime;
+#endif
+ (void)flac_chmod(filename, stats->st_mode);
+ (void)flac_utime(filename, &srctime);
+#if !defined _MSC_VER && !defined __MINGW32__ && !defined __EMX__
+ FLAC_CHECK_RETURN(chown(filename, stats->st_uid, (gid_t)(-1)));
+ FLAC_CHECK_RETURN(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)
+{
+ FLAC__off_t o = (FLAC__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 flac_stat_s stats;
+ FILE *file, *tempfile;
+ char *tempfilename;
+ if(preserve_file_stats) {
+ if(!get_file_stats_(filename, &stats))
+ return false;
+ }
+ if(0 == (file = flac_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 = flac_fopen(filename, "r+b");
+ if(0 == file)
+ return false; /*@@@@ chain status still says OK though */
+ if(!chain.write(use_padding, (::FLAC__IOHandle)file, callbacks)) {
+ fclose(file);
+ 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 = flac_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, uint32_t current_position, FLAC::Metadata::Prototype *current_block)
+{
+ uint32_t 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("%u... ", 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], (uint32_t)status);
+}
+
+static bool generate_file_(bool include_extras, bool is_ogg)
+{
+ ::FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, picture, padding;
+ ::FLAC__StreamMetadata *metadata[4];
+ uint32_t 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 uint32_t vendor_string_length = (uint32_t)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;
+ safe_strncpy(cuesheet->data.cue_sheet.media_catalog_number, "bogo-MCN", sizeof(cuesheet->data.cue_sheet.media_catalog_number));
+ 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=*/(uint32_t)(-1), /*max_height=*/(uint32_t)(-1), /*max_depth=*/(uint32_t)(-1), /*max_colors=*/(uint32_t)(-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=*/(uint32_t)(-1), /*max_height=*/(uint32_t)(-1), /*max_depth=*/(uint32_t)(-1), /*max_colors=*/(uint32_t)(-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];
+ uint32_t 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", (uint32_t)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 uint8_t *)"duh");
+
+ printf("creating PADDING block\n");
+
+ if(0 == (padding = new FLAC::Metadata::Padding())) {
+ delete app;
+ return die_("new FLAC::Metadata::Padding()");
+ }
+ padding->set_length(20);
+
+ FLAC::Metadata::SimpleIterator iterator;
+
+ if(!iterator.is_valid()) {
+ delete app;
+ delete padding;
+ return die_("iterator.is_valid() returned false");
+ }
+
+ if(!iterator.init(flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false)) {
+ delete app;
+ delete padding;
+ return die_("iterator.init() returned false");
+ }
+ our_current_position = 0;
+
+ printf("is writable = %u\n", (uint32_t)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 {
+ delete app;
+ delete padding;
+ return die_("iterator.set_block() returned true but shouldn't have");
+ }
+
+ if(iterator.status() != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT)
+ return die_("iterator.status() should have been FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT");
+
+ printf("[S]VP\tnext\n");
+ if(!iterator.next()) {
+ delete app;
+ delete padding;
+ return die_("iterator ended early\n");
+ }
+ our_current_position++;
+
+ printf("S[V]P\tnext\n");
+ if(!iterator.next()) {
+ delete app;
+ delete padding;
+ 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(iterator.status() != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT)
+ return die_("iterator.status() should have been FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT");
+
+ 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 uint8_t *)"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 uint8_t *)"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 uint8_t *)"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 uint8_t *)"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 uint8_t *)"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 uint8_t *)"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 uint8_t *)"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];
+ uint32_t 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 uint8_t *)"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 = flac_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 = flac_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 = flac_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
index 0000000..ab4cfbf
--- /dev/null
+++ b/src/test_libFLAC++/metadata_object.cpp
@@ -0,0 +1,2099 @@
+/* test_libFLAC++ - Unit tester for libFLAC++
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcmp() */
+#include "FLAC/assert.h"
+#include "FLAC++/metadata.h"
+#include "share/safe_str.h"
+
+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", (uint32_t)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 &indx, const ::FLAC__StreamMetadata_CueSheet_Index &indxcopy)
+{
+ if(indxcopy.offset != indx.offset)
+ return false;
+ if(indxcopy.number != indx.number)
+ return false;
+ return true;
+}
+
+static bool track_is_equal_(const ::FLAC__StreamMetadata_CueSheet_Track *track, const ::FLAC__StreamMetadata_CueSheet_Track *trackcopy)
+{
+ uint32_t 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()
+{
+ uint32_t 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()
+{
+ uint32_t 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()
+{
+ uint32_t 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()
+{
+ uint32_t 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()
+{
+ uint32_t 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, uint32_t 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, uint32_t 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, uint32_t 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, uint32_t 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()
+{
+ uint32_t 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));
+ safe_strncpy(mcn, "1234567890123", sizeof(mcn));
+ 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()
+{
+ uint32_t 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/CMakeLists.txt b/src/test_libFLAC/CMakeLists.txt
new file mode 100644
index 0000000..36a5820
--- /dev/null
+++ b/src/test_libFLAC/CMakeLists.txt
@@ -0,0 +1,25 @@
+add_executable(test_libFLAC
+ bitreader.c
+ bitwriter.c
+ crc.c
+ decoders.c
+ encoders.c
+ endswap.c
+ format.c
+ main.c
+ metadata.c
+ metadata_manip.c
+ metadata_object.c
+ md5.c
+ "$<TARGET_PROPERTY:FLAC,SOURCE_DIR>/bitreader.c"
+ "$<TARGET_PROPERTY:FLAC,SOURCE_DIR>/bitwriter.c"
+ "$<TARGET_PROPERTY:FLAC,SOURCE_DIR>/crc.c"
+ "$<TARGET_PROPERTY:FLAC,SOURCE_DIR>/md5.c"
+ $<$<BOOL:${WIN32}>:../../include/share/win_utf8_io.h>
+ $<$<BOOL:${WIN32}>:../share/win_utf8_io/win_utf8_io.c>)
+
+target_compile_definitions(test_libFLAC PRIVATE
+ $<$<BOOL:${ENABLE_64_BIT_WORDS}>:ENABLE_64_BIT_WORDS>)
+target_include_directories(test_libFLAC PRIVATE
+ "$<TARGET_PROPERTY:FLAC,SOURCE_DIR>/include")
+target_link_libraries(test_libFLAC FLAC grabbag test_libs_common)
diff --git a/src/test_libFLAC/Makefile.am b/src/test_libFLAC/Makefile.am
new file mode 100644
index 0000000..c77f87e
--- /dev/null
+++ b/src/test_libFLAC/Makefile.am
@@ -0,0 +1,63 @@
+# test_libFLAC - Unit tester for libFLAC
+# Copyright (C) 2000-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+EXTRA_DIST = \
+ CMakeLists.txt
+
+check_PROGRAMS = test_libFLAC
+
+if OS_IS_WINDOWS
+win_utf8_lib = $(top_builddir)/src/share/win_utf8_io/libwin_utf8_io.la
+flac__no_dll = -DFLAC__NO_DLL
+endif
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include -I$(top_srcdir)/src/libFLAC/include $(flac__no_dll)
+
+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-static.la \
+ $(win_utf8_lib) \
+ @OGG_LIBS@ \
+ -lm
+
+test_libFLAC_SOURCES = \
+ bitreader.c \
+ bitwriter.c \
+ crc.c \
+ decoders.c \
+ encoders.c \
+ endswap.c \
+ format.c \
+ main.c \
+ metadata.c \
+ metadata_manip.c \
+ metadata_object.c \
+ md5.c \
+ bitreader.h \
+ bitwriter.h \
+ crc.h \
+ decoders.h \
+ encoders.h \
+ endswap.h \
+ format.h \
+ metadata.h \
+ md5.h
+
+CLEANFILES = test_libFLAC.exe
diff --git a/src/test_libFLAC/Makefile.in b/src/test_libFLAC/Makefile.in
new file mode 100644
index 0000000..ee0dcf8
--- /dev/null
+++ b/src/test_libFLAC/Makefile.in
@@ -0,0 +1,736 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in 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.
+
+@SET_MAKE@
+
+# test_libFLAC - Unit tester for libFLAC
+# Copyright (C) 2000-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+check_PROGRAMS = test_libFLAC$(EXEEXT)
+subdir = src/test_libFLAC
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/add_cflags.m4 \
+ $(top_srcdir)/m4/add_cxxflags.m4 \
+ $(top_srcdir)/m4/ax_add_fortify_source.m4 \
+ $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_enable_debug.m4 \
+ $(top_srcdir)/m4/bswap.m4 $(top_srcdir)/m4/clang.m4 \
+ $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gcc_version.m4 \
+ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/ogg.m4 \
+ $(top_srcdir)/m4/really_gcc.m4 \
+ $(top_srcdir)/m4/stack_protect.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am_test_libFLAC_OBJECTS = bitreader.$(OBJEXT) bitwriter.$(OBJEXT) \
+ crc.$(OBJEXT) decoders.$(OBJEXT) encoders.$(OBJEXT) \
+ endswap.$(OBJEXT) format.$(OBJEXT) main.$(OBJEXT) \
+ metadata.$(OBJEXT) metadata_manip.$(OBJEXT) \
+ metadata_object.$(OBJEXT) md5.$(OBJEXT)
+test_libFLAC_OBJECTS = $(am_test_libFLAC_OBJECTS)
+test_libFLAC_DEPENDENCIES = \
+ $(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-static.la $(win_utf8_lib)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/bitreader.Po \
+ ./$(DEPDIR)/bitwriter.Po ./$(DEPDIR)/crc.Po \
+ ./$(DEPDIR)/decoders.Po ./$(DEPDIR)/encoders.Po \
+ ./$(DEPDIR)/endswap.Po ./$(DEPDIR)/format.Po \
+ ./$(DEPDIR)/main.Po ./$(DEPDIR)/md5.Po ./$(DEPDIR)/metadata.Po \
+ ./$(DEPDIR)/metadata_manip.Po ./$(DEPDIR)/metadata_object.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(test_libFLAC_SOURCES)
+DIST_SOURCES = $(test_libFLAC_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_64_BIT_WORDS = @ENABLE_64_BIT_WORDS@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLAC__HAS_OGG = @FLAC__HAS_OGG@
+FLAC__TEST_LEVEL = @FLAC__TEST_LEVEL@
+FLAC__TEST_WITH_VALGRIND = @FLAC__TEST_WITH_VALGRIND@
+GCC_MAJOR_VERSION = @GCC_MAJOR_VERSION@
+GCC_MINOR_VERSION = @GCC_MINOR_VERSION@
+GCC_VERSION = @GCC_VERSION@
+GIT_COMMIT_VERSION_HASH = @GIT_COMMIT_VERSION_HASH@
+GIT_FOUND = @GIT_FOUND@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_FUZZING_ENGINE = @LIB_FUZZING_ENGINE@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OBJ_FORMAT = @OBJ_FORMAT@
+OGG_CFLAGS = @OGG_CFLAGS@
+OGG_LIBS = @OGG_LIBS@
+OGG_PACKAGE = @OGG_PACKAGE@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = \
+ CMakeLists.txt
+
+@OS_IS_WINDOWS_TRUE@win_utf8_lib = $(top_builddir)/src/share/win_utf8_io/libwin_utf8_io.la
+@OS_IS_WINDOWS_TRUE@flac__no_dll = -DFLAC__NO_DLL
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include -I$(top_srcdir)/src/libFLAC/include $(flac__no_dll)
+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-static.la \
+ $(win_utf8_lib) \
+ @OGG_LIBS@ \
+ -lm
+
+test_libFLAC_SOURCES = \
+ bitreader.c \
+ bitwriter.c \
+ crc.c \
+ decoders.c \
+ encoders.c \
+ endswap.c \
+ format.c \
+ main.c \
+ metadata.c \
+ metadata_manip.c \
+ metadata_object.c \
+ md5.c \
+ bitreader.h \
+ bitwriter.h \
+ crc.h \
+ decoders.h \
+ encoders.h \
+ endswap.h \
+ format.h \
+ metadata.h \
+ md5.h
+
+CLEANFILES = test_libFLAC.exe
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/test_libFLAC/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/test_libFLAC/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+ @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+test_libFLAC$(EXEEXT): $(test_libFLAC_OBJECTS) $(test_libFLAC_DEPENDENCIES) $(EXTRA_test_libFLAC_DEPENDENCIES)
+ @rm -f test_libFLAC$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_libFLAC_OBJECTS) $(test_libFLAC_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bitreader.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bitwriter.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crc.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decoders.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/encoders.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/endswap.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/format.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/metadata.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/metadata_manip.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/metadata_object.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/bitreader.Po
+ -rm -f ./$(DEPDIR)/bitwriter.Po
+ -rm -f ./$(DEPDIR)/crc.Po
+ -rm -f ./$(DEPDIR)/decoders.Po
+ -rm -f ./$(DEPDIR)/encoders.Po
+ -rm -f ./$(DEPDIR)/endswap.Po
+ -rm -f ./$(DEPDIR)/format.Po
+ -rm -f ./$(DEPDIR)/main.Po
+ -rm -f ./$(DEPDIR)/md5.Po
+ -rm -f ./$(DEPDIR)/metadata.Po
+ -rm -f ./$(DEPDIR)/metadata_manip.Po
+ -rm -f ./$(DEPDIR)/metadata_object.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/bitreader.Po
+ -rm -f ./$(DEPDIR)/bitwriter.Po
+ -rm -f ./$(DEPDIR)/crc.Po
+ -rm -f ./$(DEPDIR)/decoders.Po
+ -rm -f ./$(DEPDIR)/encoders.Po
+ -rm -f ./$(DEPDIR)/endswap.Po
+ -rm -f ./$(DEPDIR)/format.Po
+ -rm -f ./$(DEPDIR)/main.Po
+ -rm -f ./$(DEPDIR)/md5.Po
+ -rm -f ./$(DEPDIR)/metadata.Po
+ -rm -f ./$(DEPDIR)/metadata_manip.Po
+ -rm -f ./$(DEPDIR)/metadata_object.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-checkPROGRAMS clean-generic clean-libtool cscopelist-am \
+ ctags ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/test_libFLAC/bitreader.c b/src/test_libFLAC/bitreader.c
new file mode 100644
index 0000000..d40bd1f
--- /dev/null
+++ b/src/test_libFLAC/bitreader.c
@@ -0,0 +1,355 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "FLAC/assert.h"
+#include "share/compat.h"
+#include "private/bitreader.h" /* from the libFLAC private include area */
+#include "bitreader.h"
+#include <stdio.h>
+#include <string.h> /* for memcpy() */
+
+/*
+ * WATCHOUT! Since FLAC__BitReader 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/bitreader.c
+ */
+#if (ENABLE_64_BIT_WORDS == 0)
+
+typedef FLAC__uint32 brword;
+#define FLAC__BYTES_PER_WORD 4
+#define FLAC__BITS_PER_WORD 32
+
+#else
+
+typedef FLAC__uint64 brword;
+#define FLAC__BYTES_PER_WORD 8
+#define FLAC__BITS_PER_WORD 64
+
+#endif
+
+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;
+ uint32_t capacity; /* in words */
+ uint32_t words; /* # of completed words in buffer */
+ uint32_t bytes; /* # of bytes in incomplete word at buffer[words] */
+ uint32_t consumed_words; /* #words ... */
+ uint32_t consumed_bits; /* ... + (#bits of head word) already consumed from the front of buffer */
+ uint32_t read_crc16; /* the running frame CRC */
+ uint32_t crc16_offset; /* the number of words in the current buffer that should not be CRC'd */
+ uint32_t crc16_align; /* the number of bits in the current consumed word that should not be CRC'd */
+ FLAC__bool read_limit_set; /* whether reads are limited */
+ uint32_t read_limit; /* the remaining size of what can be read */
+ uint32_t last_seen_framesync; /* the location of the last seen framesync, if it is in the buffer, in bits from front of buffer */
+ FLAC__BitReaderReadCallback read_callback;
+ void *client_data;
+};
+
+static FLAC__bool read_callback(FLAC__byte buffer[], size_t *bytes, void *data);
+
+static void FLAC__bitreader_dump(const FLAC__BitReader *br, FILE *out)
+{
+ uint32_t 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, "%01d", br->buffer[i] & ((brword)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, "%01d", br->buffer[i] & ((brword)1 << (br->bytes*8-j-1)) ? 1:0);
+ fprintf(out, "\n");
+ }
+ }
+}
+
+FLAC__bool test_bitreader(void)
+{
+ FLAC__BitReader *br;
+ FLAC__bool ok;
+ uint32_t i;
+ uint32_t words, bits; /* what we think br->consumed_words and br->consumed_bits should be */
+
+ FLAC__uint16 crc,expected_crcs[4] = { 0x5e4c, 0x7f6b, 0x2272, 0x42bf };
+ FLAC__byte data[32];
+
+ FLAC__uint32 val_uint32;
+ FLAC__uint64 val_uint64;
+
+ for (i = 0; i < 32; i++)
+ data[i] = i * 8 + 7;
+
+ printf("\n+++ libFLAC unit test: bitreader\n\n");
+
+ /*
+ * test new -> delete
+ */
+ printf("testing new... ");
+ br = FLAC__bitreader_new();
+ if(0 == br) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing delete... ");
+ FLAC__bitreader_delete(br);
+ printf("OK\n");
+
+ /*
+ * test new -> init -> delete
+ */
+ printf("testing new... ");
+ br = FLAC__bitreader_new();
+ if(0 == br) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing init... ");
+ if(!FLAC__bitreader_init(br, read_callback, data)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing delete... ");
+ FLAC__bitreader_delete(br);
+ printf("OK\n");
+
+ /*
+ * test new -> init -> clear -> delete
+ */
+ printf("testing new... ");
+ br = FLAC__bitreader_new();
+ if(0 == br) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing init... ");
+ if(!FLAC__bitreader_init(br, read_callback, data)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing clear... ");
+ if(!FLAC__bitreader_clear(br)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing delete... ");
+ FLAC__bitreader_delete(br);
+ printf("OK\n");
+
+ /*
+ * test normal usage
+ */
+ printf("testing new... ");
+ br = FLAC__bitreader_new();
+ if(0 == br) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing init... ");
+ if(!FLAC__bitreader_init(br, read_callback, data)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing clear... ");
+ if(!FLAC__bitreader_clear(br)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ printf("OK\n");
+
+ words = bits = 0;
+
+ printf("capacity = %u\n", br->capacity);
+
+ printf("testing raw reads... ");
+ ok =
+ FLAC__bitreader_read_raw_uint32(br, &val_uint32, 1) &&
+ FLAC__bitreader_read_raw_uint32(br, &val_uint32, 2) &&
+ FLAC__bitreader_read_raw_uint32(br, &val_uint32, 5) &&
+ FLAC__bitreader_read_raw_uint32(br, &val_uint32, 8) &&
+ FLAC__bitreader_read_raw_uint32(br, &val_uint32, 10) &&
+ FLAC__bitreader_read_raw_uint32(br, &val_uint32, 4) &&
+ FLAC__bitreader_read_raw_uint32(br, &val_uint32, 32) &&
+ FLAC__bitreader_read_raw_uint32(br, &val_uint32, 4) &&
+ FLAC__bitreader_read_raw_uint32(br, &val_uint32, 2) &&
+ FLAC__bitreader_read_raw_uint32(br, &val_uint32, 8) &&
+ FLAC__bitreader_read_raw_uint64(br, &val_uint64, 64) &&
+ FLAC__bitreader_read_raw_uint32(br, &val_uint32, 12)
+ ;
+ if(!ok) {
+ printf("FAILED\n");
+ FLAC__bitreader_dump(br, stdout);
+ return false;
+ }
+ /* we read 152 bits (=19 bytes) from the bitreader */
+ words = 152 / FLAC__BITS_PER_WORD;
+ bits = 152 - words*FLAC__BITS_PER_WORD;
+
+ if(br->consumed_words != words) {
+ printf("FAILED word count %u != %u\n", br->consumed_words, words);
+ FLAC__bitreader_dump(br, stdout);
+ return false;
+ }
+ if(br->consumed_bits != bits) {
+ printf("FAILED bit count %u != %u\n", br->consumed_bits, bits);
+ FLAC__bitreader_dump(br, stdout);
+ return false;
+ }
+ crc = FLAC__bitreader_get_read_crc16(br);
+ if(crc != expected_crcs[0]) {
+ printf("FAILED reported CRC 0x%04x does not match expected 0x%04x\n", crc, expected_crcs[0]);
+ FLAC__bitreader_dump(br, stdout);
+ return false;
+ }
+ printf("OK\n");
+ FLAC__bitreader_dump(br, stdout);
+
+ printf("testing CRC reset... ");
+ FLAC__bitreader_clear(br);
+ FLAC__bitreader_reset_read_crc16(br, 0xFFFF);
+ crc = FLAC__bitreader_get_read_crc16(br);
+ if(crc != 0xFFFF) {
+ printf("FAILED reported CRC 0x%04x does not match expected 0xFFFF\n", crc);
+ FLAC__bitreader_dump(br, stdout);
+ return false;
+ }
+ FLAC__bitreader_reset_read_crc16(br, 0);
+ crc = FLAC__bitreader_get_read_crc16(br);
+ if(crc != 0) {
+ printf("FAILED reported CRC 0x%04x does not match expected 0x0000\n", crc);
+ FLAC__bitreader_dump(br, stdout);
+ return false;
+ }
+ FLAC__bitreader_read_raw_uint32(br, &val_uint32, 16);
+ FLAC__bitreader_reset_read_crc16(br, 0);
+ FLAC__bitreader_read_raw_uint32(br, &val_uint32, 32);
+ crc = FLAC__bitreader_get_read_crc16(br);
+ if(crc != expected_crcs[1]) {
+ printf("FAILED reported CRC 0x%04x does not match expected 0x%04x\n", crc, expected_crcs[1]);
+ FLAC__bitreader_dump(br, stdout);
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing unaligned < 32 bit reads... ");
+ FLAC__bitreader_clear(br);
+ FLAC__bitreader_skip_bits_no_crc(br, 8);
+ FLAC__bitreader_reset_read_crc16(br, 0);
+ ok =
+ FLAC__bitreader_read_raw_uint32(br, &val_uint32, 1) &&
+ FLAC__bitreader_read_raw_uint32(br, &val_uint32, 2) &&
+ FLAC__bitreader_read_raw_uint32(br, &val_uint32, 5) &&
+ FLAC__bitreader_read_raw_uint32(br, &val_uint32, 8)
+ ;
+ if(!ok) {
+ printf("FAILED\n");
+ FLAC__bitreader_dump(br, stdout);
+ return false;
+ }
+ crc = FLAC__bitreader_get_read_crc16(br);
+ if(crc != expected_crcs[2]) {
+ printf("FAILED reported CRC 0x%04x does not match expected 0x%04x\n", crc, expected_crcs[2]);
+ FLAC__bitreader_dump(br, stdout);
+ return false;
+ }
+ printf("OK\n");
+ FLAC__bitreader_dump(br, stdout);
+
+ printf("testing unaligned < 64 bit reads... ");
+ FLAC__bitreader_clear(br);
+ FLAC__bitreader_skip_bits_no_crc(br, 8);
+ FLAC__bitreader_reset_read_crc16(br, 0);
+ ok =
+ FLAC__bitreader_read_raw_uint32(br, &val_uint32, 1) &&
+ FLAC__bitreader_read_raw_uint32(br, &val_uint32, 2) &&
+ FLAC__bitreader_read_raw_uint32(br, &val_uint32, 5) &&
+ FLAC__bitreader_read_raw_uint32(br, &val_uint32, 8) &&
+ FLAC__bitreader_read_raw_uint32(br, &val_uint32, 32)
+ ;
+ if(!ok) {
+ printf("FAILED\n");
+ FLAC__bitreader_dump(br, stdout);
+ return false;
+ }
+ crc = FLAC__bitreader_get_read_crc16(br);
+ if(crc != expected_crcs[3]) {
+ printf("FAILED reported CRC 0x%04x does not match expected 0x%04x\n", crc, expected_crcs[3]);
+ FLAC__bitreader_dump(br, stdout);
+ return false;
+ }
+ printf("OK\n");
+ FLAC__bitreader_dump(br, stdout);
+
+ printf("testing free... ");
+ FLAC__bitreader_free(br);
+ printf("OK\n");
+
+ printf("testing delete... ");
+ FLAC__bitreader_delete(br);
+ printf("OK\n");
+
+ printf("\nPASSED!\n");
+ return true;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static FLAC__bool read_callback(FLAC__byte buffer[], size_t *bytes, void *data)
+{
+ if (*bytes > 32)
+ *bytes = 32;
+
+ memcpy(buffer, data, *bytes);
+
+ return true;
+}
diff --git a/src/test_libFLAC/bitreader.h b/src/test_libFLAC/bitreader.h
new file mode 100644
index 0000000..f497acf
--- /dev/null
+++ b/src/test_libFLAC/bitreader.h
@@ -0,0 +1,27 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef FLAC__TEST_LIBFLAC_BITREADER_H
+#define FLAC__TEST_LIBFLAC_BITREADER_H
+
+#include "FLAC/ordinals.h"
+
+FLAC__bool test_bitreader(void);
+
+#endif
diff --git a/src/test_libFLAC/bitwriter.c b/src/test_libFLAC/bitwriter.c
new file mode 100644
index 0000000..0aafff2
--- /dev/null
+++ b/src/test_libFLAC/bitwriter.c
@@ -0,0 +1,688 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "FLAC/assert.h"
+#include "share/compat.h"
+#include "private/bitwriter.h" /* from the libFLAC private include area */
+#include "bitwriter.h"
+#include <stdio.h>
+#include <string.h> /* for memcmp() */
+
+/*
+ * 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
+ */
+#if (ENABLE_64_BIT_WORDS == 0)
+
+typedef FLAC__uint32 bwword;
+#define FLAC__BYTES_PER_WORD 4
+#define FLAC__BITS_PER_WORD 32
+#define PRI_BWWORD "08x"
+
+#else
+
+typedef FLAC__uint64 bwword;
+#define FLAC__BYTES_PER_WORD 8
+#define FLAC__BITS_PER_WORD 64
+#define PRI_BWWORD "016" PRIx64
+
+#endif
+
+struct FLAC__BitWriter {
+ bwword *buffer;
+ bwword accum; /* accumulator; bits are right-justified; when full, accum is appended to buffer */
+ uint32_t capacity; /* capacity of buffer in words */
+ uint32_t words; /* # of complete words in buffer */
+ uint32_t bits; /* # of used bits in accum */
+};
+
+#define WORDS_TO_BITS(words) ((words) * FLAC__BITS_PER_WORD)
+#define TOTAL_BITS(bw) (WORDS_TO_BITS((bw)->words) + (bw)->bits)
+
+static void FLAC__bitwriter_dump(const FLAC__BitWriter *bw, FILE *out)
+{
+ uint32_t 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, 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, "%01d", bw->buffer[i] & ((bwword)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, "%01d", bw->accum & ((bwword)1 << (bw->bits-j-1)) ? 1:0);
+ fprintf(out, "\n");
+ }
+ }
+}
+
+FLAC__bool test_bitwriter(void)
+{
+ FLAC__BitWriter *bw;
+ FLAC__bool ok;
+ uint32_t i, j;
+#if FLAC__BYTES_PER_WORD == 4
+#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
+#elif FLAC__BYTES_PER_WORD == 8
+#if WORDS_BIGENDIAN
+ static bwword test_pattern1[3] = { FLAC__U64L(0xaaf0aabeaaaaaaa8), FLAC__U64L(0x300aaaaaaaadeadb), FLAC__U64L(0x0000000000eeface) };
+#else
+ static bwword test_pattern1[3] = { FLAC__U64L(0xa8aaaaaabeaaf0aa), FLAC__U64L(0xdbeaadaaaaaa0a30), FLAC__U64L(0x0000000000eeface) };
+#endif
+#else
+#error FLAC__BYTES_PER_WORD is neither 4 nor 8 -- not implemented
+#endif
+ uint32_t 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... ");
+ if(!FLAC__bitwriter_init(bw)) {
+ printf("FAILED, returned false\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... ");
+ if(!FLAC__bitwriter_init(bw)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing clear... ");
+ FLAC__bitwriter_clear(bw);
+ 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... ");
+ if(!FLAC__bitwriter_init(bw)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ printf("OK\n");
+
+ 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;
+ }
+ /* we wrote 152 bits (=19 bytes) to the bitwriter */
+ words = 152 / FLAC__BITS_PER_WORD;
+ bits = 152 - words*FLAC__BITS_PER_WORD;
+
+ if(bw->words != words) {
+ printf("FAILED word 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=%" PRI_BWWORD " != %" PRI_BWWORD ")\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 word 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=%" PRI_BWWORD " != %" PRI_BWWORD ")\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 FLAC__BYTES_PER_WORD == 4
+#if WORDS_BIGENDIAN
+ ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xF0908080;
+#else
+ ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0x808090F0;
+#endif
+#elif FLAC__BYTES_PER_WORD == 8
+ ok = TOTAL_BITS(bw) == 32 && (bw->accum & 0xffffffff) == 0xF0908080;
+#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 FLAC__BYTES_PER_WORD == 4
+#if WORDS_BIGENDIAN
+ ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xF7BFBFBF;
+#else
+ ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xBFBFBFF7;
+#endif
+#elif FLAC__BYTES_PER_WORD == 8
+ ok = TOTAL_BITS(bw) == 32 && (bw->accum & 0xffffffff) == 0xF7BFBFBF;
+#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 FLAC__BYTES_PER_WORD == 4
+#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
+#elif FLAC__BYTES_PER_WORD == 8
+ ok = TOTAL_BITS(bw) == 40 && (bw->accum & FLAC__U64L(0xffffffffff)) == FLAC__U64L(0xF888808080);
+#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 FLAC__BYTES_PER_WORD == 4
+#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
+#elif FLAC__BYTES_PER_WORD == 8
+ ok = TOTAL_BITS(bw) == 40 && (bw->accum & FLAC__U64L(0xffffffffff)) == FLAC__U64L(0xFBBFBFBFBF);
+#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 FLAC__BYTES_PER_WORD == 4
+#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
+#elif FLAC__BYTES_PER_WORD == 8
+ ok = TOTAL_BITS(bw) == 48 && (bw->accum & FLAC__U64L(0xffffffffffff)) == FLAC__U64L(0xFC8480808080);
+#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 FLAC__BYTES_PER_WORD == 4
+#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
+#elif FLAC__BYTES_PER_WORD == 8
+ ok = TOTAL_BITS(bw) == 48 && (bw->accum & FLAC__U64L(0xffffffffffff)) == FLAC__U64L(0xFDBFBFBFBFBF);
+#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, FLAC__U64L(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, FLAC__U64L(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, FLAC__U64L(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, FLAC__U64L(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, FLAC__U64L(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, FLAC__U64L(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, FLAC__U64L(0x0000000000010000));
+#if FLAC__BYTES_PER_WORD == 4
+#if WORDS_BIGENDIAN
+ ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xF0908080;
+#else
+ ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0x808090F0;
+#endif
+#elif FLAC__BYTES_PER_WORD == 8
+ ok = TOTAL_BITS(bw) == 32 && (bw->accum & 0xffffffff) == 0xF0908080;
+#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, FLAC__U64L(0x00000000001FFFFF));
+#if FLAC__BYTES_PER_WORD == 4
+#if WORDS_BIGENDIAN
+ ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xF7BFBFBF;
+#else
+ ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xBFBFBFF7;
+#endif
+#elif FLAC__BYTES_PER_WORD == 8
+ ok = TOTAL_BITS(bw) == 32 && (bw->accum & 0xffffffff) == 0xF7BFBFBF;
+#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, FLAC__U64L(0x0000000000200000));
+#if FLAC__BYTES_PER_WORD == 4
+#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
+#elif FLAC__BYTES_PER_WORD == 8
+ ok = TOTAL_BITS(bw) == 40 && (bw->accum & FLAC__U64L(0xffffffffff)) == FLAC__U64L(0xF888808080);
+#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, FLAC__U64L(0x0000000003FFFFFF));
+#if FLAC__BYTES_PER_WORD == 4
+#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
+#elif FLAC__BYTES_PER_WORD == 8
+ ok = TOTAL_BITS(bw) == 40 && (bw->accum & FLAC__U64L(0xffffffffff)) == FLAC__U64L(0xFBBFBFBFBF);
+#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, FLAC__U64L(0x0000000004000000));
+#if FLAC__BYTES_PER_WORD == 4
+#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
+#elif FLAC__BYTES_PER_WORD == 8
+ ok = TOTAL_BITS(bw) == 48 && (bw->accum & FLAC__U64L(0xffffffffffff)) == FLAC__U64L(0xFC8480808080);
+#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, FLAC__U64L(0x000000007FFFFFFF));
+#if FLAC__BYTES_PER_WORD == 4
+#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
+#elif FLAC__BYTES_PER_WORD == 8
+ ok = TOTAL_BITS(bw) == 48 && (bw->accum & FLAC__U64L(0xffffffffffff)) == FLAC__U64L(0xFDBFBFBFBFBF);
+#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, FLAC__U64L(0x0000000080000000));
+#if FLAC__BYTES_PER_WORD == 4
+#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
+#elif FLAC__BYTES_PER_WORD == 8
+ ok = TOTAL_BITS(bw) == 56 && (bw->accum & FLAC__U64L(0xffffffffffffff)) == FLAC__U64L(0xFE828080808080);
+#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 FLAC__BYTES_PER_WORD == 4
+#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
+#elif FLAC__BYTES_PER_WORD == 8
+ ok = TOTAL_BITS(bw) == 56 && (bw->accum & FLAC__U64L(0xffffffffffffff)) == FLAC__U64L(0xFEBFBFBFBFBFBF);
+#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 FLAC__BYTES_PER_WORD == 4
+#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
+#elif FLAC__BYTES_PER_WORD == 8
+#if WORDS_BIGENDIAN
+ ok = TOTAL_BITS(bw) == i*32+4 && bw->buffer[0] == FLAC__U64L(0x5aaaaaaaaaaaaaaa) && (bw->accum & 0xf) == 0xa;
+#else
+ ok = TOTAL_BITS(bw) == i*32+4 && bw->buffer[0] == FLAC__U64L(0xaaaaaaaaaaaaaa5a) && (bw->accum & 0xf) == 0xa;
+#endif
+#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
index 0000000..9b6a824
--- /dev/null
+++ b/src/test_libFLAC/bitwriter.h
@@ -0,0 +1,27 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#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/crc.c b/src/test_libFLAC/crc.c
new file mode 100644
index 0000000..8b87671
--- /dev/null
+++ b/src/test_libFLAC/crc.c
@@ -0,0 +1,274 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2014-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#include "FLAC/assert.h"
+#include "share/compat.h"
+#include "private/crc.h"
+#include "crc.h"
+
+static FLAC__uint8 crc8_update_ref(FLAC__byte byte, FLAC__uint8 crc);
+static FLAC__uint16 crc16_update_ref(FLAC__byte byte, FLAC__uint16 crc);
+
+static FLAC__bool test_crc8(const FLAC__byte *data, size_t size);
+static FLAC__bool test_crc16(const FLAC__byte *data, size_t size);
+static FLAC__bool test_crc16_update(const FLAC__byte *data, size_t size);
+static FLAC__bool test_crc16_32bit_words(const FLAC__uint32 *words, size_t size);
+static FLAC__bool test_crc16_64bit_words(const FLAC__uint64 *words, size_t size);
+
+#define DATA_SIZE 32768
+
+FLAC__bool test_crc(void)
+{
+ uint32_t i;
+ FLAC__byte data[DATA_SIZE] = { 0 };
+
+ /* Initialize data reproducibly with pseudo-random values. */
+ for (i = 1; i < DATA_SIZE; i++)
+ data[i] = crc8_update_ref(i % 256, data[i - 1]);
+
+ printf("\n+++ libFLAC unit test: crc\n\n");
+
+ if (! test_crc8(data, DATA_SIZE))
+ return false;
+
+ if (! test_crc16(data, DATA_SIZE))
+ return false;
+
+ if (! test_crc16_update(data, DATA_SIZE))
+ return false;
+
+ if (! test_crc16_32bit_words((FLAC__uint32 *)data, DATA_SIZE / 4))
+ return false;
+
+ if (! test_crc16_64bit_words((FLAC__uint64 *)data, DATA_SIZE / 8))
+ return false;
+
+ printf("\nPASSED!\n");
+ return true;
+}
+
+/*----------------------------------------------------------------------------*/
+
+/* Reference implementations of CRC-8 and CRC-16 to check against. */
+
+#define CRC8_POLYNOMIAL 0x07
+
+static FLAC__uint8 crc8_update_ref(FLAC__byte byte, FLAC__uint8 crc)
+{
+ uint32_t i;
+
+ crc ^= byte;
+
+ for (i = 0; i < 8; i++) {
+ crc = (crc << 1) ^ ((crc >> 7) ? CRC8_POLYNOMIAL : 0);
+ }
+
+ return crc;
+}
+
+#define CRC16_POLYNOMIAL 0x8005
+
+static FLAC__uint16 crc16_update_ref(FLAC__byte byte, FLAC__uint16 crc)
+{
+ uint32_t i;
+
+ crc ^= byte << 8;
+
+ for (i = 0; i < 8; i++) {
+ crc = (crc << 1) ^ ((crc >> 15) ? CRC16_POLYNOMIAL : 0);
+ }
+
+ return crc;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static FLAC__bool test_crc8(const FLAC__byte *data, size_t size)
+{
+ uint32_t i;
+ FLAC__uint8 crc0,crc1;
+
+ printf("testing FLAC__crc8 ... ");
+
+ crc0 = 0;
+ crc1 = FLAC__crc8(data, 0);
+
+ if (crc1 != crc0) {
+ printf("FAILED, FLAC__crc8 returned non-zero CRC for zero bytes of data\n");
+ return false;
+ }
+
+ for (i = 0; i < size; i++) {
+ crc0 = crc8_update_ref(data[i], crc0);
+ crc1 = FLAC__crc8(data, i + 1);
+
+ if (crc1 != crc0) {
+ printf("FAILED, FLAC__crc8 result did not match reference CRC for %u bytes of test data\n", i + 1);
+ return false;
+ }
+ }
+
+ printf("OK\n");
+
+ return true;
+}
+
+static FLAC__bool test_crc16(const FLAC__byte *data, size_t size)
+{
+ uint32_t i;
+ FLAC__uint16 crc0,crc1;
+
+ printf("testing FLAC__crc16 ... ");
+
+ crc0 = 0;
+ crc1 = FLAC__crc16(data, 0);
+
+ if (crc1 != crc0) {
+ printf("FAILED, FLAC__crc16 returned non-zero CRC for zero bytes of data\n");
+ return false;
+ }
+
+ for (i = 0; i < size; i++) {
+ crc0 = crc16_update_ref(data[i], crc0);
+ crc1 = FLAC__crc16(data, i + 1);
+
+ if (crc1 != crc0) {
+ printf("FAILED, FLAC__crc16 result did not match reference CRC for %u bytes of test data\n", i + 1);
+ return false;
+ }
+ }
+
+ printf("OK\n");
+
+ return true;
+}
+
+static FLAC__bool test_crc16_update(const FLAC__byte *data, size_t size)
+{
+ uint32_t i;
+ FLAC__uint16 crc0,crc1;
+
+ printf("testing FLAC__CRC16_UPDATE macro ... ");
+
+ crc0 = 0;
+ crc1 = 0;
+
+ for (i = 0; i < size; i++) {
+ crc0 = crc16_update_ref(data[i], crc0);
+ crc1 = FLAC__CRC16_UPDATE(data[i], crc1);
+
+ if (crc1 != crc0) {
+ printf("FAILED, FLAC__CRC16_UPDATE result did not match reference CRC after %u bytes of test data\n", i + 1);
+ return false;
+ }
+ }
+
+ printf("OK\n");
+
+ return true;
+}
+
+static FLAC__bool test_crc16_32bit_words(const FLAC__uint32 *words, size_t size)
+{
+ uint32_t n,i,k;
+ FLAC__uint16 crc0,crc1;
+
+ for (n = 1; n <= 16; n++) {
+ printf("testing FLAC__crc16_update_words32 (length=%i) ... ", n);
+
+ crc0 = 0;
+ crc1 = 0;
+
+ for (i = 0; i <= size - n; i += n) {
+ for (k = 0; k < n; k++) {
+ crc0 = crc16_update_ref( words[i + k] >> 24, crc0);
+ crc0 = crc16_update_ref((words[i + k] >> 16) & 0xFF, crc0);
+ crc0 = crc16_update_ref((words[i + k] >> 8) & 0xFF, crc0);
+ crc0 = crc16_update_ref( words[i + k] & 0xFF, crc0);
+ }
+
+ crc1 = FLAC__crc16_update_words32(words + i, n, crc1);
+
+ if (crc1 != crc0) {
+ printf("FAILED, FLAC__crc16_update_words32 result did not match reference CRC after %u words of test data\n", i + n);
+ return false;
+ }
+ }
+
+ crc1 = FLAC__crc16_update_words32(words, 0, crc1);
+
+ if (crc1 != crc0) {
+ printf("FAILED, FLAC__crc16_update_words32 called with zero bytes changed CRC value\n");
+ return false;
+ }
+
+ printf("OK\n");
+ }
+
+ return true;
+}
+
+static FLAC__bool test_crc16_64bit_words(const FLAC__uint64 *words, size_t size)
+{
+ uint32_t n,i,k;
+ FLAC__uint16 crc0,crc1;
+
+ for (n = 1; n <= 16; n++) {
+ printf("testing FLAC__crc16_update_words64 (length=%i) ... ", n);
+
+ crc0 = 0;
+ crc1 = 0;
+
+ for (i = 0; i <= size - n; i += n) {
+ for (k = 0; k < n; k++) {
+ crc0 = crc16_update_ref( words[i + k] >> 56, crc0);
+ crc0 = crc16_update_ref((words[i + k] >> 48) & 0xFF, crc0);
+ crc0 = crc16_update_ref((words[i + k] >> 40) & 0xFF, crc0);
+ crc0 = crc16_update_ref((words[i + k] >> 32) & 0xFF, crc0);
+ crc0 = crc16_update_ref((words[i + k] >> 24) & 0xFF, crc0);
+ crc0 = crc16_update_ref((words[i + k] >> 16) & 0xFF, crc0);
+ crc0 = crc16_update_ref((words[i + k] >> 8) & 0xFF, crc0);
+ crc0 = crc16_update_ref( words[i + k] & 0xFF, crc0);
+ }
+
+ crc1 = FLAC__crc16_update_words64(words + i, n, crc1);
+
+ if (crc1 != crc0) {
+ printf("FAILED, FLAC__crc16_update_words64 result did not match reference CRC after %u words of test data\n", i + n);
+ return false;
+ }
+ }
+
+ crc1 = FLAC__crc16_update_words64(words, 0, crc1);
+
+ if (crc1 != crc0) {
+ printf("FAILED, FLAC__crc16_update_words64 called with zero bytes changed CRC value\n");
+ return false;
+ }
+
+ printf("OK\n");
+ }
+
+ return true;
+}
diff --git a/src/test_libFLAC/crc.h b/src/test_libFLAC/crc.h
new file mode 100644
index 0000000..11523cd
--- /dev/null
+++ b/src/test_libFLAC/crc.h
@@ -0,0 +1,26 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2014-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef FLAC__TEST_LIBFLAC_CRC_H
+#define FLAC__TEST_LIBFLAC_CRC_H
+
+#include "FLAC/ordinals.h"
+
+FLAC__bool test_crc(void);
+
+#endif
diff --git a/src/test_libFLAC/decoders.c b/src/test_libFLAC/decoders.c
new file mode 100644
index 0000000..ae114ce
--- /dev/null
+++ b/src/test_libFLAC/decoders.c
@@ -0,0 +1,1054 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "decoders.h"
+#include "FLAC/assert.h"
+#include "FLAC/stream_decoder.h"
+#include "share/grabbag.h"
+#include "share/compat.h"
+#include "share/safe_str.h"
+#include "test_libs_common/file_utils_flac.h"
+#include "test_libs_common/metadata_utils.h"
+
+typedef enum {
+ LAYER_STREAM = 0, /* FLAC__stream_decoder_init_[ogg_]stream() without seeking */
+ LAYER_SEEKABLE_STREAM, /* FLAC__stream_decoder_init_[ogg_]stream() with seeking */
+ LAYER_FILE, /* FLAC__stream_decoder_init_[ogg_]FILE() */
+ LAYER_FILENAME /* FLAC__stream_decoder_init_[ogg_]file() */
+} Layer;
+
+static const char * const LayerString[] = {
+ "Stream",
+ "Seekable Stream",
+ "FILE*",
+ "Filename"
+};
+
+typedef struct {
+ Layer layer;
+ FILE *file;
+ char filename[512];
+ uint32_t current_metadata_number;
+ FLAC__bool ignore_errors;
+ FLAC__bool error_occurred;
+} StreamDecoderClientData;
+
+static FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_;
+static FLAC__StreamMetadata *expected_metadata_sequence_[9];
+static uint32_t num_expected_;
+static FLAC__off_t flacfilesize_;
+
+static const char *flacfilename(FLAC__bool is_ogg)
+{
+ return is_ogg? "metadata.oga" : "metadata.flac";
+}
+
+static FLAC__bool die_(const char *msg)
+{
+ printf("ERROR: %s\n", msg);
+ return false;
+}
+
+static FLAC__bool die_s_(const char *msg, const FLAC__StreamDecoder *decoder)
+{
+ FLAC__StreamDecoderState state = FLAC__stream_decoder_get_state(decoder);
+
+ if(msg)
+ printf("FAILED, %s", msg);
+ else
+ printf("FAILED");
+
+ printf(", state = %u (%s)\n", (uint32_t)state, FLAC__StreamDecoderStateString[state]);
+
+ return false;
+}
+
+static void open_test_file(StreamDecoderClientData * pdcd, int is_ogg, const char * mode)
+{
+ pdcd->file = flac_fopen(flacfilename(is_ogg), mode);
+ safe_strncpy(pdcd->filename, flacfilename(is_ogg), sizeof (pdcd->filename));
+}
+
+static void init_metadata_blocks_(void)
+{
+ mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
+}
+
+static void free_metadata_blocks_(void)
+{
+ mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
+}
+
+static FLAC__bool generate_file_(FLAC__bool is_ogg)
+{
+ printf("\n\ngenerating %sFLAC file for decoder tests...\n", is_ogg? "Ogg ":"");
+
+ num_expected_ = 0;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &seektable_;
+ expected_metadata_sequence_[num_expected_++] = &application1_;
+ expected_metadata_sequence_[num_expected_++] = &application2_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ /* WATCHOUT: for Ogg FLAC the encoder should move the VORBIS_COMMENT block to the front, right after STREAMINFO */
+
+ if(!file_utils__generate_flacfile(is_ogg, flacfilename(is_ogg), &flacfilesize_, 512 * 1024, &streaminfo_, expected_metadata_sequence_, num_expected_))
+ return die_("creating the encoded file");
+
+ return true;
+}
+
+static FLAC__StreamDecoderReadStatus stream_decoder_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+ StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+ const size_t requested_bytes = *bytes;
+
+ (void)decoder;
+
+ if(0 == dcd) {
+ printf("ERROR: client_data in read callback is NULL\n");
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ }
+
+ if(dcd->error_occurred)
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+
+ if(feof(dcd->file)) {
+ *bytes = 0;
+ return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+ }
+ else if(requested_bytes > 0) {
+ *bytes = fread(buffer, 1, requested_bytes, dcd->file);
+ if(*bytes == 0) {
+ if(feof(dcd->file))
+ return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+ else
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ }
+ else {
+ return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+ }
+ }
+ else
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT; /* abort to avoid a deadlock */
+}
+
+static FLAC__StreamDecoderSeekStatus stream_decoder_seek_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+{
+ StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+
+ (void)decoder;
+
+ if(0 == dcd) {
+ printf("ERROR: client_data in seek callback is NULL\n");
+ return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+ }
+
+ if(dcd->error_occurred)
+ return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+
+ if(fseeko(dcd->file, (FLAC__off_t)absolute_byte_offset, SEEK_SET) < 0) {
+ dcd->error_occurred = true;
+ return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+ }
+
+ return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+}
+
+static FLAC__StreamDecoderTellStatus stream_decoder_tell_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+{
+ StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+ FLAC__off_t offset;
+
+ (void)decoder;
+
+ if(0 == dcd) {
+ printf("ERROR: client_data in tell callback is NULL\n");
+ return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+ }
+
+ if(dcd->error_occurred)
+ return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+
+ offset = ftello(dcd->file);
+ *absolute_byte_offset = (FLAC__uint64)offset;
+
+ if(offset < 0) {
+ dcd->error_occurred = true;
+ return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+ }
+
+ return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+}
+
+static FLAC__StreamDecoderLengthStatus stream_decoder_length_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
+{
+ StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+
+ (void)decoder;
+
+ if(0 == dcd) {
+ printf("ERROR: client_data in length callback is NULL\n");
+ return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+ }
+
+ if(dcd->error_occurred)
+ return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+
+ *stream_length = (FLAC__uint64)flacfilesize_;
+ return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+}
+
+static FLAC__bool stream_decoder_eof_callback_(const FLAC__StreamDecoder *decoder, void *client_data)
+{
+ StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+
+ (void)decoder;
+
+ if(0 == dcd) {
+ printf("ERROR: client_data in eof callback is NULL\n");
+ return true;
+ }
+
+ if(dcd->error_occurred)
+ return true;
+
+ return feof(dcd->file);
+}
+
+static FLAC__StreamDecoderWriteStatus stream_decoder_write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+ StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+
+ (void)decoder, (void)buffer;
+
+ if(0 == dcd) {
+ printf("ERROR: client_data in write callback is NULL\n");
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+ }
+
+ if(dcd->error_occurred)
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+
+ if(
+ (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
+ (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0)
+ ) {
+ printf("content... ");
+ fflush(stdout);
+ }
+
+ return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+static void stream_decoder_metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+ StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+
+ (void)decoder;
+
+ if(0 == dcd) {
+ printf("ERROR: client_data in metadata callback is NULL\n");
+ return;
+ }
+
+ if(dcd->error_occurred)
+ return;
+
+ if (metadata->type == FLAC__METADATA_TYPE_APPLICATION) {
+ printf ("%u ('%c%c%c%c')... ", dcd->current_metadata_number, metadata->data.application.id [0], metadata->data.application.id [1], metadata->data.application.id [2], metadata->data.application.id [3]);
+ }
+ else {
+ printf("%u... ", dcd->current_metadata_number);
+ }
+ fflush(stdout);
+
+
+ if(dcd->current_metadata_number >= num_expected_) {
+ (void)die_("got more metadata blocks than expected");
+ dcd->error_occurred = true;
+ }
+ else {
+ if(!mutils__compare_block(expected_metadata_sequence_[dcd->current_metadata_number], metadata)) {
+ (void)die_("metadata block mismatch");
+ dcd->error_occurred = true;
+ }
+ }
+ dcd->current_metadata_number++;
+}
+
+static void stream_decoder_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+ StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+
+ (void)decoder;
+
+ if(0 == dcd) {
+ printf("ERROR: client_data in error callback is NULL\n");
+ return;
+ }
+
+ if(!dcd->ignore_errors) {
+ printf("ERROR: got error callback: err = %u (%s)\n", (uint32_t)status, FLAC__StreamDecoderErrorStatusString[status]);
+ dcd->error_occurred = true;
+ }
+}
+
+static FLAC__bool stream_decoder_test_respond_(FLAC__StreamDecoder *decoder, StreamDecoderClientData *dcd, FLAC__bool is_ogg)
+{
+ FLAC__StreamDecoderInitStatus init_status;
+
+ if(!FLAC__stream_decoder_set_md5_checking(decoder, true))
+ return die_s_("at FLAC__stream_decoder_set_md5_checking(), returned false", decoder);
+
+ /* for FLAC__stream_encoder_init_FILE(), the FLAC__stream_encoder_finish() closes the file so we have to keep re-opening: */
+ if(dcd->layer == LAYER_FILE) {
+ printf("opening %sFLAC file... ", is_ogg? "Ogg ":"");
+ open_test_file(dcd, is_ogg, "rb");
+ if(0 == dcd->file) {
+ printf("ERROR (%s)\n", strerror(errno));
+ return false;
+ }
+ printf("OK\n");
+ }
+
+ switch(dcd->layer) {
+ case LAYER_STREAM:
+ printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":"");
+ init_status = is_ogg?
+ FLAC__stream_decoder_init_ogg_stream(decoder, stream_decoder_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd) :
+ FLAC__stream_decoder_init_stream(decoder, stream_decoder_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd)
+ ;
+ break;
+ case LAYER_SEEKABLE_STREAM:
+ printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":"");
+ init_status = is_ogg?
+ FLAC__stream_decoder_init_ogg_stream(decoder, stream_decoder_read_callback_, stream_decoder_seek_callback_, stream_decoder_tell_callback_, stream_decoder_length_callback_, stream_decoder_eof_callback_, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd) :
+ FLAC__stream_decoder_init_stream(decoder, stream_decoder_read_callback_, stream_decoder_seek_callback_, stream_decoder_tell_callback_, stream_decoder_length_callback_, stream_decoder_eof_callback_, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd);
+ break;
+ case LAYER_FILE:
+ printf("testing FLAC__stream_decoder_init_%sFILE()... ", is_ogg? "ogg_":"");
+ init_status = is_ogg?
+ FLAC__stream_decoder_init_ogg_FILE(decoder, dcd->file, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd) :
+ FLAC__stream_decoder_init_FILE(decoder, dcd->file, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd);
+ break;
+ case LAYER_FILENAME:
+ printf("testing FLAC__stream_decoder_init_%sfile()... ", is_ogg? "ogg_":"");
+ init_status = is_ogg?
+ FLAC__stream_decoder_init_ogg_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd) :
+ FLAC__stream_decoder_init_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd);
+ break;
+ default:
+ die_("internal error 000");
+ return false;
+ }
+ if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+ return die_s_(0, decoder);
+ printf("OK\n");
+
+ dcd->current_metadata_number = 0;
+
+ if(dcd->layer < LAYER_FILE && fseeko(dcd->file, 0, SEEK_SET) < 0) {
+ printf("FAILED rewinding input, errno = %d\n", errno);
+ return false;
+ }
+
+ printf("testing FLAC__stream_decoder_process_until_end_of_stream()... ");
+ if(!FLAC__stream_decoder_process_until_end_of_stream(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_finish()... ");
+ if(!FLAC__stream_decoder_finish(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ return true;
+}
+
+static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg)
+{
+ FLAC__StreamDecoder *decoder;
+ FLAC__StreamDecoderInitStatus init_status;
+ FLAC__StreamDecoderState state;
+ StreamDecoderClientData decoder_client_data;
+ FLAC__bool expect;
+
+ decoder_client_data.layer = layer;
+
+ printf("\n+++ libFLAC unit test: FLAC__StreamDecoder (layer: %s, format: %s)\n\n", LayerString[layer], is_ogg? "Ogg FLAC" : "FLAC");
+
+ printf("testing FLAC__stream_decoder_new()... ");
+ decoder = FLAC__stream_decoder_new();
+ if(0 == decoder) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_delete()... ");
+ FLAC__stream_decoder_delete(decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_new()... ");
+ decoder = FLAC__stream_decoder_new();
+ if(0 == decoder) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ printf("OK\n");
+
+ switch(layer) {
+ case LAYER_STREAM:
+ case LAYER_SEEKABLE_STREAM:
+ printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":"");
+ init_status = is_ogg?
+ FLAC__stream_decoder_init_ogg_stream(decoder, 0, 0, 0, 0, 0, 0, 0, 0, 0) :
+ FLAC__stream_decoder_init_stream(decoder, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ break;
+ case LAYER_FILE:
+ printf("testing FLAC__stream_decoder_init_%sFILE()... ", is_ogg? "ogg_":"");
+ init_status = is_ogg?
+ FLAC__stream_decoder_init_ogg_FILE(decoder, stdin, 0, 0, 0, 0) :
+ FLAC__stream_decoder_init_FILE(decoder, stdin, 0, 0, 0, 0);
+ break;
+ case LAYER_FILENAME:
+ printf("testing FLAC__stream_decoder_init_%sfile()... ", is_ogg? "ogg_":"");
+ init_status = is_ogg?
+ FLAC__stream_decoder_init_ogg_file(decoder, flacfilename(is_ogg), 0, 0, 0, 0) :
+ FLAC__stream_decoder_init_file(decoder, flacfilename(is_ogg), 0, 0, 0, 0);
+ break;
+ default:
+ die_("internal error 003");
+ return false;
+ }
+ if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS)
+ return die_s_(0, decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_delete()... ");
+ FLAC__stream_decoder_delete(decoder);
+ printf("OK\n");
+
+ num_expected_ = 0;
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+
+ printf("testing FLAC__stream_decoder_new()... ");
+ decoder = FLAC__stream_decoder_new();
+ if(0 == decoder) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ printf("OK\n");
+
+ if(is_ogg) {
+ printf("testing FLAC__stream_decoder_set_ogg_serial_number()... ");
+ if(!FLAC__stream_decoder_set_ogg_serial_number(decoder, file_utils__ogg_serial_number))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+ }
+
+ printf("testing FLAC__stream_decoder_set_md5_checking()... ");
+ if(!FLAC__stream_decoder_set_md5_checking(decoder, true))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ if(layer < LAYER_FILENAME) {
+ printf("opening %sFLAC file... ", is_ogg? "Ogg ":"");
+ open_test_file(&decoder_client_data, is_ogg, "rb");
+ if(0 == decoder_client_data.file) {
+ printf("ERROR (%s)\n", strerror(errno));
+ return false;
+ }
+ printf("OK\n");
+ }
+
+ switch(layer) {
+ case LAYER_STREAM:
+ printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":"");
+ init_status = is_ogg?
+ FLAC__stream_decoder_init_ogg_stream(decoder, stream_decoder_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) :
+ FLAC__stream_decoder_init_stream(decoder, stream_decoder_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data);
+ break;
+ case LAYER_SEEKABLE_STREAM:
+ printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":"");
+ init_status = is_ogg?
+ FLAC__stream_decoder_init_ogg_stream(decoder, stream_decoder_read_callback_, stream_decoder_seek_callback_, stream_decoder_tell_callback_, stream_decoder_length_callback_, stream_decoder_eof_callback_, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) :
+ FLAC__stream_decoder_init_stream(decoder, stream_decoder_read_callback_, stream_decoder_seek_callback_, stream_decoder_tell_callback_, stream_decoder_length_callback_, stream_decoder_eof_callback_, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data);
+ break;
+ case LAYER_FILE:
+ printf("testing FLAC__stream_decoder_init_%sFILE()... ", is_ogg? "ogg_":"");
+ init_status = is_ogg?
+ FLAC__stream_decoder_init_ogg_FILE(decoder, decoder_client_data.file, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) :
+ FLAC__stream_decoder_init_FILE(decoder, decoder_client_data.file, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data);
+ break;
+ case LAYER_FILENAME:
+ printf("testing FLAC__stream_decoder_init_%sfile()... ", is_ogg? "ogg_":"");
+ init_status = is_ogg?
+ FLAC__stream_decoder_init_ogg_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) :
+ FLAC__stream_decoder_init_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data);
+ break;
+ default:
+ die_("internal error 009");
+ return false;
+ }
+ if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+ return die_s_(0, decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_get_state()... ");
+ state = FLAC__stream_decoder_get_state(decoder);
+ printf("returned state = %u (%s)... OK\n", state, FLAC__StreamDecoderStateString[state]);
+
+ decoder_client_data.current_metadata_number = 0;
+ decoder_client_data.ignore_errors = false;
+ decoder_client_data.error_occurred = false;
+
+ printf("testing FLAC__stream_decoder_get_md5_checking()... ");
+ if(!FLAC__stream_decoder_get_md5_checking(decoder)) {
+ printf("FAILED, returned false, expected true\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_process_until_end_of_metadata()... ");
+ if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_process_single()... ");
+ if(!FLAC__stream_decoder_process_single(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_skip_single_frame()... ");
+ if(!FLAC__stream_decoder_skip_single_frame(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ if(layer < LAYER_FILE) {
+ printf("testing FLAC__stream_decoder_flush()... ");
+ if(!FLAC__stream_decoder_flush(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ decoder_client_data.ignore_errors = true;
+ printf("testing FLAC__stream_decoder_process_single()... ");
+ if(!FLAC__stream_decoder_process_single(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+ decoder_client_data.ignore_errors = false;
+ }
+
+ expect = (layer != LAYER_STREAM);
+ printf("testing FLAC__stream_decoder_seek_absolute()... ");
+ if(FLAC__stream_decoder_seek_absolute(decoder, 0) != expect)
+ return die_s_(expect? "returned false" : "returned true", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_process_until_end_of_stream()... ");
+ if(!FLAC__stream_decoder_process_until_end_of_stream(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ expect = (layer != LAYER_STREAM);
+ printf("testing FLAC__stream_decoder_seek_absolute()... ");
+ if(FLAC__stream_decoder_seek_absolute(decoder, 0) != expect)
+ return die_s_(expect? "returned false" : "returned true", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_get_channels()... ");
+ {
+ uint32_t channels = FLAC__stream_decoder_get_channels(decoder);
+ if(channels != streaminfo_.data.stream_info.channels) {
+ printf("FAILED, returned %u, expected %u\n", channels, streaminfo_.data.stream_info.channels);
+ return false;
+ }
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_get_bits_per_sample()... ");
+ {
+ uint32_t bits_per_sample = FLAC__stream_decoder_get_bits_per_sample(decoder);
+ if(bits_per_sample != streaminfo_.data.stream_info.bits_per_sample) {
+ printf("FAILED, returned %u, expected %u\n", bits_per_sample, streaminfo_.data.stream_info.bits_per_sample);
+ return false;
+ }
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_get_sample_rate()... ");
+ {
+ uint32_t sample_rate = FLAC__stream_decoder_get_sample_rate(decoder);
+ if(sample_rate != streaminfo_.data.stream_info.sample_rate) {
+ printf("FAILED, returned %u, expected %u\n", sample_rate, streaminfo_.data.stream_info.sample_rate);
+ return false;
+ }
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_get_blocksize()... ");
+ {
+ uint32_t blocksize = FLAC__stream_decoder_get_blocksize(decoder);
+ /* value could be anything since we're at the last block, so accept any reasonable answer */
+ printf("returned %u... %s\n", blocksize, blocksize>0? "OK" : "FAILED");
+ if(blocksize == 0)
+ return false;
+ }
+
+ printf("testing FLAC__stream_decoder_get_channel_assignment()... ");
+ {
+ FLAC__ChannelAssignment ca = FLAC__stream_decoder_get_channel_assignment(decoder);
+ printf("returned %u (%s)... OK\n", (uint32_t)ca, FLAC__ChannelAssignmentString[ca]);
+ }
+
+ if(layer < LAYER_FILE) {
+ printf("testing FLAC__stream_decoder_reset()... ");
+ if(!FLAC__stream_decoder_reset(decoder)) {
+ state = FLAC__stream_decoder_get_state(decoder);
+ printf("FAILED, returned false, state = %u (%s)\n", state, FLAC__StreamDecoderStateString[state]);
+ return false;
+ }
+ printf("OK\n");
+
+ if(layer == LAYER_STREAM) {
+ /* after a reset() we have to rewind the input ourselves */
+ printf("rewinding input... ");
+ if(fseeko(decoder_client_data.file, 0, SEEK_SET) < 0) {
+ printf("FAILED, errno = %d\n", errno);
+ return false;
+ }
+ printf("OK\n");
+ }
+
+ decoder_client_data.current_metadata_number = 0;
+
+ printf("testing FLAC__stream_decoder_process_until_end_of_stream()... ");
+ if(!FLAC__stream_decoder_process_until_end_of_stream(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+ }
+
+ printf("testing FLAC__stream_decoder_finish()... ");
+ if(!FLAC__stream_decoder_finish(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ /*
+ * respond all
+ */
+
+ printf("testing FLAC__stream_decoder_set_metadata_respond_all()... ");
+ if(!FLAC__stream_decoder_set_metadata_respond_all(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ num_expected_ = 0;
+ if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping. Also removes the seektable */
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &application1_;
+ expected_metadata_sequence_[num_expected_++] = &application2_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+ else {
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &seektable_;
+ expected_metadata_sequence_[num_expected_++] = &application1_;
+ expected_metadata_sequence_[num_expected_++] = &application2_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+
+ if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+ return false;
+
+ /*
+ * ignore all
+ */
+
+ printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... ");
+ if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ num_expected_ = 0;
+
+ if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+ return false;
+
+ /*
+ * respond all, ignore VORBIS_COMMENT
+ */
+
+ printf("testing FLAC__stream_decoder_set_metadata_respond_all()... ");
+ if(!FLAC__stream_decoder_set_metadata_respond_all(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_set_metadata_ignore(VORBIS_COMMENT)... ");
+ if(!FLAC__stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ num_expected_ = 0;
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ if(!is_ogg) /* encoder removes seektable for ogg */
+ expected_metadata_sequence_[num_expected_++] = &seektable_;
+ expected_metadata_sequence_[num_expected_++] = &application1_;
+ expected_metadata_sequence_[num_expected_++] = &application2_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+ if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+ return false;
+
+ /*
+ * respond all, ignore APPLICATION
+ */
+
+ printf("testing FLAC__stream_decoder_set_metadata_respond_all()... ");
+ if(!FLAC__stream_decoder_set_metadata_respond_all(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_set_metadata_ignore(APPLICATION)... ");
+ if(!FLAC__stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_APPLICATION))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ num_expected_ = 0;
+ if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping. Also removes the seektable */
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+ else {
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &seektable_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+
+ if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+ return false;
+
+ /*
+ * respond all, ignore APPLICATION id of app#1
+ */
+
+ printf("testing FLAC__stream_decoder_set_metadata_respond_all()... ");
+ if(!FLAC__stream_decoder_set_metadata_respond_all(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_set_metadata_ignore_application(of app block #1)... ");
+ if(!FLAC__stream_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ num_expected_ = 0;
+ if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping. Also removes the seektable */
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &application2_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+ else {
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &seektable_;
+ expected_metadata_sequence_[num_expected_++] = &application2_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+
+ if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+ return false;
+
+ /*
+ * respond all, ignore APPLICATION id of app#1 & app#2
+ */
+
+ printf("testing FLAC__stream_decoder_set_metadata_respond_all()... ");
+ if(!FLAC__stream_decoder_set_metadata_respond_all(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_set_metadata_ignore_application(of app block #1)... ");
+ if(!FLAC__stream_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_set_metadata_ignore_application(of app block #2)... ");
+ if(!FLAC__stream_decoder_set_metadata_ignore_application(decoder, application2_.data.application.id))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ num_expected_ = 0;
+ if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping. Also removes the seektable */
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+ else {
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &seektable_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+
+ if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+ return false;
+
+ /*
+ * ignore all, respond VORBIS_COMMENT
+ */
+
+ printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... ");
+ if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_set_metadata_respond(VORBIS_COMMENT)... ");
+ if(!FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ num_expected_ = 0;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+
+ if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+ return false;
+
+ /*
+ * ignore all, respond APPLICATION
+ */
+
+ printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... ");
+ if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_set_metadata_respond(APPLICATION)... ");
+ if(!FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_APPLICATION))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ num_expected_ = 0;
+ expected_metadata_sequence_[num_expected_++] = &application1_;
+ expected_metadata_sequence_[num_expected_++] = &application2_;
+
+ if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+ return false;
+
+ /*
+ * ignore all, respond APPLICATION id of app#1
+ */
+
+ printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... ");
+ if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_set_metadata_respond_application(of app block #1)... ");
+ if(!FLAC__stream_decoder_set_metadata_respond_application(decoder, application1_.data.application.id))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ num_expected_ = 0;
+ expected_metadata_sequence_[num_expected_++] = &application1_;
+
+ if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+ return false;
+
+ /*
+ * ignore all, respond APPLICATION id of app#1 & app#2
+ */
+
+ printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... ");
+ if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_set_metadata_respond_application(of app block #1)... ");
+ if(!FLAC__stream_decoder_set_metadata_respond_application(decoder, application1_.data.application.id))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_set_metadata_respond_application(of app block #2)... ");
+ if(!FLAC__stream_decoder_set_metadata_respond_application(decoder, application2_.data.application.id))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ num_expected_ = 0;
+ expected_metadata_sequence_[num_expected_++] = &application1_;
+ expected_metadata_sequence_[num_expected_++] = &application2_;
+
+ if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+ return false;
+
+ /*
+ * respond all, ignore APPLICATION, respond APPLICATION id of app#1
+ */
+
+ printf("testing FLAC__stream_decoder_set_metadata_respond_all()... ");
+ if(!FLAC__stream_decoder_set_metadata_respond_all(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_set_metadata_ignore(APPLICATION)... ");
+ if(!FLAC__stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_APPLICATION))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_set_metadata_respond_application(of app block #1)... ");
+ if(!FLAC__stream_decoder_set_metadata_respond_application(decoder, application1_.data.application.id))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ num_expected_ = 0;
+ if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping. Also removes the seektable */
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &application1_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+ else {
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &seektable_;
+ expected_metadata_sequence_[num_expected_++] = &application1_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+
+ if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+ return false;
+
+ /*
+ * ignore all, respond APPLICATION, ignore APPLICATION id of app#1
+ */
+
+ printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... ");
+ if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_set_metadata_respond(APPLICATION)... ");
+ if(!FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_APPLICATION))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_set_metadata_ignore_application(of app block #1)... ");
+ if(!FLAC__stream_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ num_expected_ = 0;
+ expected_metadata_sequence_[num_expected_++] = &application2_;
+
+ if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+ return false;
+
+ if(layer < LAYER_FILE) /* for LAYER_FILE, FLAC__stream_decoder_finish() closes the file */
+ fclose(decoder_client_data.file);
+
+ printf("testing FLAC__stream_decoder_delete()... ");
+ FLAC__stream_decoder_delete(decoder);
+ printf("OK\n");
+
+ printf("\nPASSED!\n");
+
+ return true;
+}
+
+FLAC__bool test_decoders(void)
+{
+ FLAC__bool is_ogg = false;
+
+ while(1) {
+ init_metadata_blocks_();
+
+ if(!generate_file_(is_ogg))
+ return false;
+
+ if(!test_stream_decoder(LAYER_STREAM, is_ogg))
+ return false;
+
+ if(!test_stream_decoder(LAYER_SEEKABLE_STREAM, is_ogg))
+ return false;
+
+ if(!test_stream_decoder(LAYER_FILE, is_ogg))
+ return false;
+
+ if(!test_stream_decoder(LAYER_FILENAME, is_ogg))
+ return false;
+
+ (void) grabbag__file_remove_file(flacfilename(is_ogg));
+
+ free_metadata_blocks_();
+
+ if(!FLAC_API_SUPPORTS_OGG_FLAC || is_ogg)
+ break;
+ is_ogg = true;
+ }
+
+ return true;
+}
diff --git a/src/test_libFLAC/decoders.h b/src/test_libFLAC/decoders.h
new file mode 100644
index 0000000..431eb17
--- /dev/null
+++ b/src/test_libFLAC/decoders.h
@@ -0,0 +1,27 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#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
index 0000000..d3fd39d
--- /dev/null
+++ b/src/test_libFLAC/encoders.c
@@ -0,0 +1,530 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "encoders.h"
+#include "FLAC/assert.h"
+#include "FLAC/stream_encoder.h"
+#include "share/grabbag.h"
+#include "share/compat.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 uint32_t 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", (uint32_t)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", (uint32_t)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, uint32_t samples, uint32_t 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(fseeko(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;
+ FLAC__off_t pos;
+ (void)encoder;
+ if((pos = ftello(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, uint32_t frames_written, uint32_t 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];
+ uint32_t 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, (uint32_t)(-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");
+
+ printf("testing FLAC__stream_encoder_set_limit_min_bitrate()... ");
+ if(!FLAC__stream_encoder_set_limit_min_bitrate(encoder, true))
+ return die_s_("returned false", encoder);
+ printf("OK\n");
+
+ if(layer < LAYER_FILENAME) {
+ printf("opening file for FLAC output... ");
+ file = flac_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", (uint32_t)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", (uint32_t)dstate, FLAC__StreamDecoderStateString[dstate]);
+
+ {
+ FLAC__uint64 absolute_sample;
+ uint32_t frame_number;
+ uint32_t channel;
+ uint32_t 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 %d, 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 %d, 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 %d, 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 %d, 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) {
+ printf("FAILED, expected %" PRIu64 ", got %" PRIu64 "\n", streaminfo_.data.stream_info.total_samples, FLAC__stream_encoder_get_total_samples_estimate(encoder));
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_get_limit_min_bitrate()... ");
+ if(FLAC__stream_encoder_get_limit_min_bitrate(encoder) != true) {
+ printf("FAILED, expected true, got false\n");
+ return false;
+ }
+
+ /* 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
index 0000000..7bdcaf5
--- /dev/null
+++ b/src/test_libFLAC/encoders.h
@@ -0,0 +1,27 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#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/endswap.c b/src/test_libFLAC/endswap.c
new file mode 100644
index 0000000..808f81f
--- /dev/null
+++ b/src/test_libFLAC/endswap.c
@@ -0,0 +1,111 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2014-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include "share/compat.h"
+#include "FLAC/assert.h"
+#include "share/endswap.h"
+#include "private/md5.h"
+#include "endswap.h"
+
+
+FLAC__bool test_endswap(void)
+{
+ int16_t i16 = 0x1234;
+ uint16_t u16 = 0xabcd;
+ int32_t i32 = 0x12345678;
+ uint32_t u32 = 0xabcdef01;
+
+ union {
+ uint8_t bytes[4];
+ uint16_t u16;
+ uint32_t u32;
+ } data;
+
+ printf("\n+++ libFLAC unit test: endswap (%s endian host)\n\n", CPU_IS_BIG_ENDIAN ? "big" : "little");
+
+ printf("testing ENDSWAP_16 on int16_t ... ");
+ if (((int16_t) ENDSWAP_16(i16)) == i16) {
+ printf("\nFAILED, ENDSWAP_16(0x%04x) -> 0x%04x == 0x%04x\n", i16, ENDSWAP_16(i16), i16);
+ return false;
+ }
+ if (((int16_t) ENDSWAP_16(ENDSWAP_16(i16))) != i16) {
+ printf("\nFAILED, ENDSWAP_16(ENDSWAP_16(0x%04x)) -> 0x%04x != 0x%04x\n", i16, ENDSWAP_16(ENDSWAP_16(i16)), i16);
+ return false;
+ }
+ puts("OK");
+
+ printf("testing ENDSWAP_16 on uint16_t ... ");
+ if (((uint16_t) ENDSWAP_16(u16)) == u16) {
+ printf("\nFAILED, ENDSWAP_16(0x%04x) -> 0x%04x == 0x%04x\n", u16, ENDSWAP_16(u16), u16);
+ return false;
+ }
+ if (((uint16_t) ENDSWAP_16(ENDSWAP_16(u16))) != u16) {
+ printf("\nFAILED, ENDSWAP_16(ENDSWAP_16(0x%04x)) -> 0x%04x != 0x%04x\n", u16, ENDSWAP_16(ENDSWAP_16(u16)), u16);
+ return false;
+ }
+ puts("OK");
+
+ printf("testing ENDSWAP_32 on int32_t ... ");
+ if (((int32_t) ENDSWAP_32 (i32)) == i32) {
+ printf("\nFAILED, ENDSWAP_32(0x%08x) -> 0x%08x == 0x%08x\n", i32, (uint32_t) ENDSWAP_32 (i32), i32);
+ return false;
+ }
+ if (((int32_t) ENDSWAP_32 (ENDSWAP_32 (i32))) != i32) {
+ printf("\nFAILED, ENDSWAP_32(ENDSWAP_32(0x%08x)) -> 0x%08x != 0x%08x\n", i32, (uint32_t) ENDSWAP_32(ENDSWAP_32 (i32)), i32);
+ return false;
+ }
+ puts("OK");
+
+ printf("testing ENDSWAP_32 on uint32_t ... ");
+ if (((uint32_t) ENDSWAP_32(u32)) == u32) {
+ printf("\nFAILED, ENDSWAP_32(0x%08x) -> 0x%08x == 0x%08x\n", u32, (uint32_t) ENDSWAP_32(u32), u32);
+ return false;
+ }
+ if (((uint32_t) ENDSWAP_32 (ENDSWAP_32(u32))) != u32) {
+ printf("\nFAILED, ENDSWAP_32(ENDSWAP_32(0x%08x)) -> 0x%08x != 0%08x\n", u32, (uint32_t) ENDSWAP_32(ENDSWAP_32(u32)), u32);
+ return false;
+ }
+ puts("OK");
+
+ printf("testing H2LE_16 on uint16_t ... ");
+ data.u16 = H2LE_16(0x1234);
+ if (data.bytes [0] != 0x34 || data.bytes [1] != 0x12) {
+ printf("\nFAILED, H2LE_16(0x%04x) -> { 0x%02x, 0x%02x }\n", data.u16, data.bytes [0] & 0xff, data.bytes [1] & 0xff);
+ return false;
+ }
+ puts("OK");
+
+ printf("testing H2LE_32 on uint32_t ... ");
+ data.u32 = H2LE_32(0x12345678);
+ if (data.bytes [0] != 0x78 || data.bytes [1] != 0x56 || data.bytes [2] != 0x34 || data.bytes [3] != 0x12) {
+ printf("\nFAILED, H2LE_32(0x%08x) -> { 0x%02x, 0x%02x, 0x%02x, 0x%02x }\n",
+ data.u32, data.bytes [0] & 0xff, data.bytes [1] & 0xff, data.bytes [2] & 0xff, data.bytes [3] & 0xff);
+ return false;
+ }
+ puts("OK");
+
+ printf("\nPASSED!\n");
+ return true;
+}
diff --git a/src/test_libFLAC/endswap.h b/src/test_libFLAC/endswap.h
new file mode 100644
index 0000000..952b17f
--- /dev/null
+++ b/src/test_libFLAC/endswap.h
@@ -0,0 +1,26 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2014-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef FLAC__TEST_LIBFLAC_ENDSWAP_H
+#define FLAC__TEST_LIBFLAC_ENDSWAP_H
+
+#include "FLAC/ordinals.h"
+
+FLAC__bool test_endswap(void);
+
+#endif
diff --git a/src/test_libFLAC/format.c b/src/test_libFLAC/format.c
new file mode 100644
index 0000000..c5e8bf2
--- /dev/null
+++ b/src/test_libFLAC/format.c
@@ -0,0 +1,260 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2004-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "FLAC/assert.h"
+#include "FLAC/format.h"
+#include "format.h"
+#include <stdio.h>
+
+static const char *true_false_string_[2] = { "false", "true" };
+
+static struct {
+ uint32_t rate;
+ FLAC__bool valid;
+ FLAC__bool subset;
+} SAMPLE_RATES[] = {
+ { 0 , true , true },
+ { 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 , true , false },
+ { 655360 , true , false },
+ { 700000 , true , false },
+ { 700010 , true , false },
+ { 705600 , true , false },
+ { 768000 , true , false },
+ { 1000000, true , false },
+ { 1048575, true , 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 {
+ uint32_t 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 {
+ uint32_t 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)
+{
+ uint32_t 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, (uint32_t)(-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
index 0000000..f78d55d
--- /dev/null
+++ b/src/test_libFLAC/format.h
@@ -0,0 +1,27 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2004-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#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
index 0000000..a4be0fe
--- /dev/null
+++ b/src/test_libFLAC/main.c
@@ -0,0 +1,64 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "bitreader.h"
+#include "bitwriter.h"
+#include "crc.h"
+#include "decoders.h"
+#include "encoders.h"
+#include "endswap.h"
+#include "format.h"
+#include "metadata.h"
+#include "md5.h"
+
+int main(void)
+{
+ if(!test_endswap())
+ return 1;
+
+ if(!test_crc())
+ return 1;
+
+ if(!test_md5())
+ return 1;
+
+ if(!test_bitreader())
+ return 1;
+
+ 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/md5.c b/src/test_libFLAC/md5.c
new file mode 100644
index 0000000..bac4a74
--- /dev/null
+++ b/src/test_libFLAC/md5.c
@@ -0,0 +1,221 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2014-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include "FLAC/assert.h"
+#include "share/compat.h"
+#include "private/md5.h"
+#include "md5.h"
+
+
+static FLAC__bool test_md5_clear_context(void);
+static FLAC__bool test_md5_codec(void);
+static FLAC__bool test_md5_accumulate(const FLAC__int32 * const * signal,uint32_t channels, uint32_t samples, uint32_t bytes_per_sample, const FLAC__byte target_digest [16]);
+
+FLAC__bool test_md5(void)
+{
+ printf("\n+++ libFLAC unit test: md5\n\n");
+
+ if (! test_md5_clear_context())
+ return false;
+
+ if (! test_md5_codec())
+ return false;
+
+ printf("\nPASSED!\n");
+ return true;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static FLAC__bool test_md5_clear_context(void)
+{
+ FLAC__MD5Context ctx;
+ FLAC__byte digest[16];
+ FLAC__byte target[16] = { 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e };
+ uint32_t k ;
+ char * cptr;
+
+ printf("testing FLAC__MD5Init ... ");
+ FLAC__MD5Init (&ctx);
+ if (ctx.buf[0] != 0x67452301) {
+ printf("FAILED!\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing that FLAC__MD5Final clears the MD5Context ... ");
+ FLAC__MD5Final(digest, &ctx);
+ cptr = (char*) &ctx ;
+ for (k = 0 ; k < sizeof (ctx) ; k++) {
+ if (cptr [k]) {
+ printf("FAILED, MD5 ctx has not been cleared after FLAC__MD5Final\n");
+ return false;
+ }
+ }
+ printf("OK\n");
+
+ printf("testing digest correct for zero data ... ");
+ if (memcmp(digest, target, sizeof (digest))) {
+ printf("\nFAILED, expected MD5 sum ");
+ for (k = 0 ; k < 16 ; k++)
+ printf("%02x", (target [k] & 0xff));
+ printf (" but got ");
+ for (k = 0 ; k < 16 ; k++)
+ printf("%02x", (digest [k] & 0xff));
+ puts("\n");
+ return false;
+ }
+ puts("OK");
+
+ return true;
+}
+
+static FLAC__byte target_digests [8][4][16] =
+{ /* 1 channel */
+ { /* 1 byte per sample */
+ { 0xc1, 0x9a, 0x5b, 0xeb, 0x57, 0x8f, 0x26, 0xeb, 0xfb, 0x34, 0x7c, 0xef, 0x04, 0x31, 0x6d, 0x7d },
+ /* 2 bytes per sample */
+ { 0xd4, 0x78, 0x90, 0xd3, 0xa9, 0x17, 0x4e, 0x76, 0xca, 0x4d, 0x27, 0x20, 0x98, 0x36, 0x8b, 0x2e },
+ /* 3 bytes per sample */
+ { 0x5a, 0x4b, 0xd6, 0xac, 0xa1, 0x70, 0x84, 0x19, 0x7c, 0x0d, 0xfb, 0x5b, 0xa9, 0x7b, 0xcb, 0x54 },
+ /* 4 bytes per sample */
+ { 0x79, 0xd5, 0x7a, 0x32, 0x06, 0x0b, 0xfe, 0x46, 0xa3, 0xe7, 0xba, 0xc5, 0xf7, 0x48, 0x6f, 0x50 }
+ },
+
+ /* 2 channels */
+ {
+ { 0x89, 0xac, 0xcf, 0x91, 0xf1, 0x8c, 0xea, 0xab, 0x46, 0x12, 0x74, 0xbc, 0x4e, 0x82, 0xbe, 0x7d },
+ { 0xb9, 0x17, 0x16, 0x5b, 0xd8, 0x1c, 0xc8, 0x4e, 0x5a, 0x28, 0xfb, 0xba, 0x87, 0x74, 0x76, 0x44 },
+ { 0xec, 0x63, 0x92, 0xca, 0x4f, 0x6b, 0x9e, 0xb1, 0x9f, 0xec, 0x3b, 0x2c, 0x15, 0x30, 0xfd, 0x2a },
+ { 0x05, 0x4d, 0xfd, 0xb8, 0x9d, 0x8a, 0xa2, 0xdd, 0x26, 0x47, 0xc6, 0xfb, 0x4f, 0x23, 0x67, 0x6d }
+ },
+
+ /* 3 channels */
+ {
+ { 0xad, 0x05, 0xda, 0xf3, 0x7a, 0xa1, 0x94, 0xdb, 0x0c, 0x61, 0x06, 0xb2, 0x94, 0x39, 0x6c, 0xa9 },
+ { 0x8b, 0xcc, 0x41, 0x4d, 0xe9, 0xe3, 0xc2, 0x61, 0x61, 0x8a, 0x8b, 0x22, 0xc6, 0x4e, 0xac, 0xa7 },
+ { 0x8a, 0xce, 0x97, 0xc1, 0x86, 0xae, 0xbc, 0x73, 0x88, 0x8b, 0x35, 0x5a, 0x37, 0x33, 0xf9, 0xcf },
+ { 0x69, 0x59, 0xe8, 0x38, 0x29, 0x80, 0x80, 0x21, 0xb1, 0xd2, 0xba, 0xf6, 0x28, 0xd6, 0x6a, 0x83 }
+ },
+
+ /* 4 channels */
+ {
+ { 0x61, 0x40, 0x75, 0xef, 0x22, 0xf1, 0x0f, 0xa6, 0x08, 0x6c, 0x88, 0xff, 0x2c, 0x4e, 0x98, 0x0b },
+ { 0xa0, 0x77, 0x3a, 0x59, 0x4a, 0xbf, 0xd0, 0x5c, 0xcc, 0xe3, 0xb9, 0x83, 0x2b, 0xf3, 0xdf, 0x1a },
+ { 0xdb, 0xd7, 0xf1, 0x82, 0x13, 0x60, 0x42, 0x7c, 0x84, 0xe6, 0xcf, 0x30, 0xab, 0xa2, 0x64, 0xf1 },
+ { 0x4a, 0x9a, 0xad, 0x53, 0x05, 0x74, 0xb1, 0x1c, 0xb8, 0xd4, 0xae, 0x78, 0x13, 0xf6, 0x2a, 0x11 }
+ },
+
+ /* 5 channels */
+ {
+ { 0xcc, 0xca, 0x44, 0xc0, 0x54, 0xe2, 0xc9, 0xba, 0x99, 0x32, 0xc9, 0x65, 0xf3, 0x3e, 0x44, 0x34},
+ { 0x40, 0x38, 0x6a, 0xdd, 0xde, 0x89, 0x10, 0x3c, 0x8e, 0xec, 0xdf, 0x15, 0x53, 0x4c, 0x2c, 0x92 },
+ { 0xc8, 0x95, 0x0a, 0x7c, 0x17, 0x30, 0xc0, 0xac, 0x8e, 0x34, 0xdb, 0x79, 0x76, 0x64, 0x7c, 0x6e },
+ { 0x3f, 0x06, 0x11, 0x8a, 0x8d, 0x80, 0xb5, 0x4f, 0x8b, 0xb5, 0x8e, 0xb3, 0x27, 0x3e, 0x41, 0xe8 }
+ },
+
+ /* 6 channels */
+ {
+ { 0x61, 0xe4, 0xbd, 0xb1, 0xc0, 0x2f, 0xf4, 0x4c, 0x6e, 0x09, 0x5a, 0xbd, 0x90, 0x18, 0x8b, 0x62 },
+ { 0x47, 0xe7, 0x6e, 0x3b, 0x18, 0x86, 0x60, 0x1b, 0x09, 0x62, 0xc6, 0xc9, 0x7c, 0x4c, 0x03, 0xb5 },
+ { 0x70, 0x57, 0xbf, 0x67, 0x66, 0x0f, 0xe3, 0x0a, 0x6c, 0xd2, 0x97, 0x66, 0xa2, 0xd2, 0xe4, 0x79 },
+ { 0xaa, 0x3f, 0xc7, 0xf5, 0x7a, 0xa5, 0x46, 0xf7, 0xea, 0xe3, 0xd5, 0x1a, 0xa4, 0x62, 0xbe, 0xfa }
+ },
+
+ /* 7 channels */
+ {
+ { 0x7c, 0x8d, 0xd2, 0x8c, 0xfd, 0x91, 0xbb, 0x77, 0x6f, 0x0e, 0xf0, 0x39, 0x1f, 0x39, 0xc4, 0xac },
+ { 0xfb, 0xab, 0x18, 0x3f, 0x1e, 0x1d, 0xa5, 0x77, 0xe0, 0x5c, 0xea, 0x45, 0x6f, 0x64, 0xa4, 0x64 },
+ { 0xe3, 0xac, 0x33, 0x50, 0xc1, 0xb1, 0x93, 0xfb, 0xca, 0x4b, 0x15, 0xcb, 0x2d, 0xcd, 0xd5, 0xef },
+ { 0x10, 0xfb, 0x02, 0x83, 0x76, 0x0d, 0xe5, 0xd2, 0x3b, 0xb1, 0x4c, 0x78, 0x3b, 0x73, 0xf7, 0x1a }
+ },
+
+ /* 8 channels */
+ {
+ { 0x65, 0x7b, 0xe5, 0x92, 0xe2, 0x1c, 0x95, 0x3e, 0xd7, 0x2f, 0x64, 0xa0, 0x86, 0xec, 0x1a, 0xed },
+ { 0x9d, 0x04, 0x8f, 0xa4, 0xea, 0x10, 0xec, 0xb8, 0xa3, 0x88, 0xe2, 0x5d, 0x3c, 0xe2, 0xfb, 0x94 },
+ { 0x5a, 0xd3, 0xd2, 0x75, 0x6a, 0xfa, 0xa7, 0x42, 0xf3, 0xbf, 0x0e, 0xbc, 0x90, 0x2a, 0xf8, 0x5f },
+ { 0x76, 0xe1, 0xe5, 0xf6, 0xe3, 0x44, 0x08, 0x29, 0xae, 0x79, 0x19, 0xeb, 0xa8, 0x57, 0x16, 0x2a }
+ }
+};
+
+#define MAX_CHANNEL_COUNT 8
+#define MD5_SAMPLE_COUNT 64
+
+static FLAC__bool test_md5_codec(void)
+{
+ FLAC__int32 arrays[MAX_CHANNEL_COUNT][MD5_SAMPLE_COUNT], *pointer[MAX_CHANNEL_COUNT], **signal;
+ uint32_t chan, byte_size, seed = 0x12345679;
+
+ /* Set up signal data using a trivial Linear Congruent PRNG. */
+ signal = &pointer[0];
+ for (chan = 0 ; chan < MAX_CHANNEL_COUNT ; chan ++) {
+ uint32_t k;
+ pointer[chan] = arrays [chan];
+ for (k = 0 ; k < MD5_SAMPLE_COUNT ; k++) {
+ seed = seed * 1103515245 + 12345;
+ arrays[chan][k] = seed;
+ }
+ }
+
+ for (chan = 1 ; chan <= MAX_CHANNEL_COUNT ; chan ++) {
+ for (byte_size = 1 ; byte_size <= 4 ; byte_size ++) {
+ if (! test_md5_accumulate((const FLAC__int32 * const *) signal, chan, MD5_SAMPLE_COUNT, byte_size, target_digests[chan-1][byte_size-1]))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static FLAC__bool test_md5_accumulate(const FLAC__int32 * const * signal, uint32_t channels, uint32_t samples, uint32_t bytes_per_sample, const FLAC__byte target_digest [16])
+{
+ FLAC__MD5Context ctx;
+ FLAC__byte digest[16];
+
+ memset(&ctx, 0, sizeof (ctx));
+
+ printf("testing FLAC__MD5Accumulate (samples=%u, channels=%u, bytes_per_sample=%u) ... ", samples, channels, bytes_per_sample);
+
+ FLAC__MD5Init(&ctx);
+ FLAC__MD5Accumulate(&ctx, signal, channels, samples, bytes_per_sample);
+ FLAC__MD5Final(digest, &ctx);
+
+ if (memcmp(digest, target_digest, sizeof (digest))) {
+ int k ;
+
+ printf("\nFAILED, expected MD5 sum ");
+ for (k = 0 ; k < 16 ; k++)
+ printf("%02x", (target_digest [k] & 0xff));
+ printf (" but got ");
+ for (k = 0 ; k < 16 ; k++)
+ printf("%02x", (digest [k] & 0xff));
+ puts("\n");
+ return false;
+ }
+
+ printf("OK\n");
+ return true;
+}
diff --git a/src/test_libFLAC/md5.h b/src/test_libFLAC/md5.h
new file mode 100644
index 0000000..6863268
--- /dev/null
+++ b/src/test_libFLAC/md5.h
@@ -0,0 +1,26 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2014-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef FLAC__TEST_LIBFLAC_MD5_H
+#define FLAC__TEST_LIBFLAC_MD5_H
+
+#include "FLAC/ordinals.h"
+
+FLAC__bool test_md5(void);
+
+#endif
diff --git a/src/test_libFLAC/metadata.c b/src/test_libFLAC/metadata.c
new file mode 100644
index 0000000..0347f6d
--- /dev/null
+++ b/src/test_libFLAC/metadata.c
@@ -0,0 +1,41 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "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
index 0000000..51bdf7a
--- /dev/null
+++ b/src/test_libFLAC/metadata.h
@@ -0,0 +1,29 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#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
index 0000000..334dc3a
--- /dev/null
+++ b/src/test_libFLAC/metadata_manip.c
@@ -0,0 +1,2146 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <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() */
+#else
+#include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
+#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 "share/compat.h"
+#include "share/macros.h"
+#include "share/safe_str.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];
+ uint32_t 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 uint32_t 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", (uint32_t)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, uint32_t position, FLAC__bool copy)
+{
+ uint32_t 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, uint32_t position, FLAC__bool copy)
+{
+ uint32_t 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_(uint32_t position)
+{
+ uint32_t 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";
+ size_t dest_len = strlen(filename) + strlen(tempfile_suffix) + 1;
+
+ *tempfilename = malloc(dest_len);
+ if (*tempfilename == NULL)
+ return false;
+ safe_strncpy(*tempfilename, filename, dest_len);
+ safe_strncat(*tempfilename, tempfile_suffix, dest_len);
+
+ *tempfile = flac_fopen(*tempfilename, "wb");
+ if (*tempfile == NULL)
+ return false;
+
+ return true;
+}
+
+static void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
+{
+ if (*tempfile != NULL) {
+ (void)fclose(*tempfile);
+ *tempfile = 0;
+ }
+
+ if (*tempfilename != NULL) {
+ (void)flac_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, flac_rename() will fail if the destination already exists */
+ if(flac_unlink(filename) < 0) {
+ cleanup_tempfile_(tempfile, tempfilename);
+ return false;
+ }
+#endif
+
+ if(0 != flac_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 flac_stat_s *stats)
+{
+ FLAC__ASSERT(0 != filename);
+ FLAC__ASSERT(0 != stats);
+ return (0 == flac_stat(filename, stats));
+}
+
+static void set_file_stats_(const char *filename, struct flac_stat_s *stats)
+{
+#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L) && !defined(_WIN32)
+ struct timespec srctime[2] = {};
+ srctime[0].tv_sec = stats->st_atime;
+ srctime[1].tv_sec = stats->st_mtime;
+#else
+ struct utimbuf srctime;
+ srctime.actime = stats->st_atime;
+ srctime.modtime = stats->st_mtime;
+#endif
+ FLAC__ASSERT(0 != filename);
+ FLAC__ASSERT(0 != stats);
+
+ (void)flac_chmod(filename, stats->st_mode);
+ (void)flac_utime(filename, &srctime);
+#if !defined _MSC_VER && !defined __MINGW32__
+ FLAC_CHECK_RETURN(chown(filename, stats->st_uid, -1));
+ FLAC_CHECK_RETURN(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)
+{
+ FLAC__off_t o = (FLAC__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 flac_stat_s stats;
+ FILE *file, *tempfile = 0;
+ char *tempfilename;
+ if(preserve_file_stats) {
+ if(!get_file_stats_(filename, &stats))
+ return false;
+ }
+ if(0 == (file = flac_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 = flac_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 = flac_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, uint32_t current_position, FLAC__StreamMetadata *current_block)
+{
+ uint32_t 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("%u... ", 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("%u... ", 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], (uint32_t)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];
+ uint32_t 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 uint32_t vendor_string_length = (uint32_t)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;
+ safe_strncpy(cuesheet->data.cue_sheet.media_catalog_number, "bogo-MCN", sizeof(cuesheet->data.cue_sheet.media_catalog_number));
+ 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=*/(uint32_t)(-1), /*max_height=*/(uint32_t)(-1), /*max_depth=*/(uint32_t)(-1), /*max_colors=*/(uint32_t)(-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];
+ uint32_t 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", (uint32_t)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", (uint32_t)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");
+
+ if(FLAC__metadata_simple_iterator_status(iterator) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT)
+ return die_("FLAC__metadata_simple_iterator_status() should have been FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT");
+
+ 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(FLAC__metadata_simple_iterator_status(iterator) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT)
+ return die_("FLAC__metadata_simple_iterator_status() should have been FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT");
+
+ 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];
+ uint32_t 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 = flac_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 = flac_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 = flac_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
index 0000000..ea6b69f
--- /dev/null
+++ b/src/test_libFLAC/metadata_object.c
@@ -0,0 +1,2291 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+#include "test_libs_common/metadata_utils.h"
+#include "share/compat.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, uint32_t len)
+{
+ FLAC__byte *ret;
+
+ if(0 == (ret = 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)
+{
+ uint32_t i;
+
+ if(from->offset != to->offset) {
+ printf("FAILED, track offset mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", to->offset, from->offset);
+ return false;
+ }
+ if(from->number != to->number) {
+ printf("FAILED, track number mismatch, expected %u, got %u\n", (uint32_t)to->number, (uint32_t)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", (uint32_t)to->type, (uint32_t)from->type);
+ return false;
+ }
+ if(from->pre_emphasis != to->pre_emphasis) {
+ printf("FAILED, track pre_emphasis mismatch, expected %u, got %u\n", (uint32_t)to->pre_emphasis, (uint32_t)from->pre_emphasis);
+ return false;
+ }
+ if(from->num_indices != to->num_indices) {
+ printf("FAILED, track num_indices mismatch, expected %u, got %u\n", (uint32_t)to->num_indices, (uint32_t)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) {
+ printf("FAILED, track indices[%u].offset mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", i, to->indices[i].offset, from->indices[i].offset);
+ return false;
+ }
+ if(from->indices[i].number != to->indices[i].number) {
+ printf("FAILED, track indices[%u].number mismatch, expected %u, got %u\n", i, (uint32_t)to->indices[i].number, (uint32_t)from->indices[i].number);
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+static FLAC__bool compare_seekpoint_array_(const FLAC__StreamMetadata_SeekPoint *from, const FLAC__StreamMetadata_SeekPoint *to, uint32_t n)
+{
+ uint32_t i;
+
+ FLAC__ASSERT(0 != from);
+ FLAC__ASSERT(0 != to);
+
+ for(i = 0; i < n; i++) {
+ if(from[i].sample_number != to[i].sample_number) {
+ printf("FAILED, point[%u].sample_number mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", i, to[i].sample_number, from[i].sample_number);
+ return false;
+ }
+ if(from[i].stream_offset != to[i].stream_offset) {
+ printf("FAILED, point[%u].stream_offset mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", i, to[i].stream_offset, from[i].stream_offset);
+ 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, uint32_t num_points, const FLAC__StreamMetadata_SeekPoint *array)
+{
+ const uint32_t 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 = 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 = 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;
+ uint32_t 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, uint32_t num)
+{
+ FLAC__StreamMetadata_VorbisComment *vc = &block->data.vorbis_comment;
+
+ if(vc->num_comments != 0) {
+ FLAC__ASSERT(0 != vc->comments);
+ if(num < vc->num_comments) {
+ uint32_t 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 {
+ uint32_t i;
+ vc->comments = realloc(vc->comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*num);
+ FLAC__ASSERT(0 != vc->comments);
+ for(i = vc->num_comments; i < num; i++) {
+ vc->comments[i].length = 0;
+ vc->comments[i].entry = malloc(1);
+ vc->comments[i].entry[0] = '\0';
+ }
+ }
+
+ vc->num_comments = num;
+ vc_calc_len_(block);
+}
+
+static int vc_find_from_(FLAC__StreamMetadata *block, const char *name, uint32_t start)
+{
+ const uint32_t n = strlen(name);
+ uint32_t 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, uint32_t 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, uint32_t pos, const char *field)
+{
+ FLAC__StreamMetadata_VorbisComment_Entry temp;
+ vc_resize_(block, block->data.vorbis_comment.num_comments+1);
+ temp = block->data.vorbis_comment.comments[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));
+ block->data.vorbis_comment.comments[pos] = temp;
+ vc_set_new_(entry, block, pos, field);
+ vc_calc_len_(block);
+}
+
+static void vc_delete_(FLAC__StreamMetadata *block, uint32_t 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 indx;
+ char field_name[256];
+ const char *eq = strchr(field, '=');
+ FLAC__ASSERT(eq>field && (uint32_t)(eq-field) < sizeof(field_name));
+ memcpy(field_name, field, eq-field);
+ field_name[eq-field]='\0';
+
+ indx = vc_find_from_(block, field_name, 0);
+ if(indx < 0)
+ vc_insert_new_(entry, block, block->data.vorbis_comment.num_comments, field);
+ else {
+ vc_set_new_(entry, block, (uint32_t)indx, field);
+ if(all) {
+ for(indx = indx+1; indx >= 0 && (uint32_t)indx < block->data.vorbis_comment.num_comments; )
+ if((indx = vc_find_from_(block, field_name, (uint32_t)indx)) >= 0)
+ vc_delete_(block, (uint32_t)indx);
+ }
+ }
+
+ 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 = 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;
+ uint32_t 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, uint32_t track_num, uint32_t 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 = 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, uint32_t track_num, uint32_t pos, FLAC__StreamMetadata_CueSheet_Index indx)
+{
+ 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] = indx;
+
+ cs_calc_len_(block);
+}
+
+static void tr_insert_new_(FLAC__StreamMetadata *block, uint32_t track_num, uint32_t pos, FLAC__StreamMetadata_CueSheet_Index indx)
+{
+ 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, indx);
+ cs_calc_len_(block);
+}
+
+static void tr_delete_(FLAC__StreamMetadata *block, uint32_t track_num, uint32_t 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, uint32_t num)
+{
+ FLAC__StreamMetadata_CueSheet *cs = &block->data.cue_sheet;
+
+ if(cs->num_tracks != 0) {
+ FLAC__ASSERT(0 != cs->tracks);
+ if(num < cs->num_tracks) {
+ uint32_t 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 = 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, uint32_t 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, uint32_t 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, uint32_t 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 indx;
+ FLAC__StreamMetadata_CueSheet_Track track;
+ uint32_t 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");
+
+ indx.offset = 0;
+ indx.number = 1;
+ printf("testing FLAC__metadata_object_cuesheet_track_insert_index() on empty array...");
+ tr_insert_new_(cuesheet, 0, 0, indx);
+ if(!FLAC__metadata_object_cuesheet_track_insert_index(block, 0, 0, indx)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ indx.offset = 10;
+ indx.number = 2;
+ printf("testing FLAC__metadata_object_cuesheet_track_insert_index() on beginning of non-empty array...");
+ tr_insert_new_(cuesheet, 0, 0, indx);
+ if(!FLAC__metadata_object_cuesheet_track_insert_index(block, 0, 0, indx)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ indx.offset = 20;
+ indx.number = 3;
+ printf("testing FLAC__metadata_object_cuesheet_track_insert_index() on middle of non-empty array...");
+ tr_insert_new_(cuesheet, 0, 1, indx);
+ if(!FLAC__metadata_object_cuesheet_track_insert_index(block, 0, 1, indx)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ indx.offset = 30;
+ indx.number = 4;
+ printf("testing FLAC__metadata_object_cuesheet_track_insert_index() on end of non-empty array...");
+ tr_insert_new_(cuesheet, 0, 3, indx);
+ if(!FLAC__metadata_object_cuesheet_track_insert_index(block, 0, 3, indx)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ indx.offset = 0;
+ indx.number = 0;
+ printf("testing FLAC__metadata_object_cuesheet_track_insert_blank_index() on end of non-empty array...");
+ tr_insert_new_(cuesheet, 0, 4, indx);
+ 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_libs_common/CMakeLists.txt b/src/test_libs_common/CMakeLists.txt
new file mode 100644
index 0000000..8a0c871
--- /dev/null
+++ b/src/test_libs_common/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_library(test_libs_common STATIC
+ file_utils_flac.c
+ metadata_utils.c)
+target_link_libraries(test_libs_common PUBLIC FLAC)
diff --git a/src/test_libs_common/Makefile.am b/src/test_libs_common/Makefile.am
new file mode 100644
index 0000000..30e1f15
--- /dev/null
+++ b/src/test_libs_common/Makefile.am
@@ -0,0 +1,29 @@
+# test_libs_common - Common code to library unit tests
+# Copyright (C) 2000-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+
+noinst_LTLIBRARIES = libtest_libs_common.la
+
+libtest_libs_common_la_SOURCES = \
+ file_utils_flac.c \
+ metadata_utils.c
+
+EXTRA_DIST = \
+ CMakeLists.txt \
+ README
diff --git a/src/test_libs_common/Makefile.in b/src/test_libs_common/Makefile.in
new file mode 100644
index 0000000..83af7f9
--- /dev/null
+++ b/src/test_libs_common/Makefile.in
@@ -0,0 +1,666 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in 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.
+
+@SET_MAKE@
+
+# test_libs_common - Common code to library unit tests
+# Copyright (C) 2000-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/test_libs_common
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/add_cflags.m4 \
+ $(top_srcdir)/m4/add_cxxflags.m4 \
+ $(top_srcdir)/m4/ax_add_fortify_source.m4 \
+ $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_enable_debug.m4 \
+ $(top_srcdir)/m4/bswap.m4 $(top_srcdir)/m4/clang.m4 \
+ $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gcc_version.m4 \
+ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/ogg.m4 \
+ $(top_srcdir)/m4/really_gcc.m4 \
+ $(top_srcdir)/m4/stack_protect.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libtest_libs_common_la_LIBADD =
+am_libtest_libs_common_la_OBJECTS = file_utils_flac.lo \
+ metadata_utils.lo
+libtest_libs_common_la_OBJECTS = $(am_libtest_libs_common_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/file_utils_flac.Plo \
+ ./$(DEPDIR)/metadata_utils.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libtest_libs_common_la_SOURCES)
+DIST_SOURCES = $(libtest_libs_common_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp README
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_64_BIT_WORDS = @ENABLE_64_BIT_WORDS@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLAC__HAS_OGG = @FLAC__HAS_OGG@
+FLAC__TEST_LEVEL = @FLAC__TEST_LEVEL@
+FLAC__TEST_WITH_VALGRIND = @FLAC__TEST_WITH_VALGRIND@
+GCC_MAJOR_VERSION = @GCC_MAJOR_VERSION@
+GCC_MINOR_VERSION = @GCC_MINOR_VERSION@
+GCC_VERSION = @GCC_VERSION@
+GIT_COMMIT_VERSION_HASH = @GIT_COMMIT_VERSION_HASH@
+GIT_FOUND = @GIT_FOUND@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_FUZZING_ENGINE = @LIB_FUZZING_ENGINE@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OBJ_FORMAT = @OBJ_FORMAT@
+OGG_CFLAGS = @OGG_CFLAGS@
+OGG_LIBS = @OGG_LIBS@
+OGG_PACKAGE = @OGG_PACKAGE@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+noinst_LTLIBRARIES = libtest_libs_common.la
+libtest_libs_common_la_SOURCES = \
+ file_utils_flac.c \
+ metadata_utils.c
+
+EXTRA_DIST = \
+ CMakeLists.txt \
+ README
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/test_libs_common/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/test_libs_common/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libtest_libs_common.la: $(libtest_libs_common_la_OBJECTS) $(libtest_libs_common_la_DEPENDENCIES) $(EXTRA_libtest_libs_common_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libtest_libs_common_la_OBJECTS) $(libtest_libs_common_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_utils_flac.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/metadata_utils.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/file_utils_flac.Plo
+ -rm -f ./$(DEPDIR)/metadata_utils.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/file_utils_flac.Plo
+ -rm -f ./$(DEPDIR)/metadata_utils.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/test_libs_common/README b/src/test_libs_common/README
new file mode 100644
index 0000000..6a704c2
--- /dev/null
+++ b/src/test_libs_common/README
@@ -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
index 0000000..3cc8c30
--- /dev/null
+++ b/src/test_libs_common/file_utils_flac.c
@@ -0,0 +1,155 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "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() */
+#include "share/compat.h"
+
+#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, uint32_t samples, uint32_t 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, FLAC__off_t *output_filesize, uint32_t length, const FLAC__StreamMetadata *streaminfo, FLAC__StreamMetadata **metadata, uint32_t num_metadata)
+{
+ FLAC__int32 samples[1024];
+ FLAC__StreamEncoder *encoder;
+ FLAC__StreamEncoderInitStatus init_status;
+ encoder_client_struct encoder_client_data;
+ uint32_t 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 = flac_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 flac_stat_s filestats;
+
+ if(flac_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
index 0000000..929ca63
--- /dev/null
+++ b/src/test_libs_common/metadata_utils.c
@@ -0,0 +1,636 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * These are not tests, just utility functions used by the metadata tests
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "FLAC/metadata.h"
+#include "test_libs_common/metadata_utils.h"
+#include "share/compat.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) {
+ printf("FAILED, total_samples mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", block->total_samples, blockcopy->total_samples);
+ 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",
+ (uint32_t)block->md5sum[0],
+ (uint32_t)block->md5sum[1],
+ (uint32_t)block->md5sum[2],
+ (uint32_t)block->md5sum[3],
+ (uint32_t)block->md5sum[4],
+ (uint32_t)block->md5sum[5],
+ (uint32_t)block->md5sum[6],
+ (uint32_t)block->md5sum[7],
+ (uint32_t)block->md5sum[8],
+ (uint32_t)block->md5sum[9],
+ (uint32_t)block->md5sum[10],
+ (uint32_t)block->md5sum[11],
+ (uint32_t)block->md5sum[12],
+ (uint32_t)block->md5sum[13],
+ (uint32_t)block->md5sum[14],
+ (uint32_t)block->md5sum[15],
+ (uint32_t)blockcopy->md5sum[0],
+ (uint32_t)blockcopy->md5sum[1],
+ (uint32_t)blockcopy->md5sum[2],
+ (uint32_t)blockcopy->md5sum[3],
+ (uint32_t)blockcopy->md5sum[4],
+ (uint32_t)blockcopy->md5sum[5],
+ (uint32_t)blockcopy->md5sum[6],
+ (uint32_t)blockcopy->md5sum[7],
+ (uint32_t)blockcopy->md5sum[8],
+ (uint32_t)blockcopy->md5sum[9],
+ (uint32_t)blockcopy->md5sum[10],
+ (uint32_t)blockcopy->md5sum[11],
+ (uint32_t)blockcopy->md5sum[12],
+ (uint32_t)blockcopy->md5sum[13],
+ (uint32_t)blockcopy->md5sum[14],
+ (uint32_t)blockcopy->md5sum[15]
+ );
+ return false;
+ }
+ return true;
+}
+
+FLAC__bool mutils__compare_block_data_padding(const FLAC__StreamMetadata_Padding *block, const FLAC__StreamMetadata_Padding *blockcopy, uint32_t 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, uint32_t 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",
+ (uint32_t)block->id[0],
+ (uint32_t)block->id[1],
+ (uint32_t)block->id[2],
+ (uint32_t)block->id[3],
+ (uint32_t)blockcopy->id[0],
+ (uint32_t)blockcopy->id[1],
+ (uint32_t)blockcopy->id[2],
+ (uint32_t)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)
+{
+ uint32_t 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) {
+ printf("FAILED, points[%u].sample_number mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", i, block->points[i].sample_number, blockcopy->points[i].sample_number);
+ return false;
+ }
+ if(blockcopy->points[i].stream_offset != block->points[i].stream_offset) {
+ printf("FAILED, points[%u].stream_offset mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", i, block->points[i].stream_offset, blockcopy->points[i].stream_offset);
+ 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)
+{
+ uint32_t 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)
+{
+ uint32_t 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) {
+ printf("FAILED, lead_in mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", block->lead_in, blockcopy->lead_in);
+ return false;
+ }
+ if(blockcopy->is_cd != block->is_cd) {
+ printf("FAILED, is_cd mismatch, expected %u, got %u\n", (uint32_t)block->is_cd, (uint32_t)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) {
+ printf("FAILED, tracks[%u].offset mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", i, block->tracks[i].offset, blockcopy->tracks[i].offset);
+ return false;
+ }
+ if(blockcopy->tracks[i].number != block->tracks[i].number) {
+ printf("FAILED, tracks[%u].number mismatch, expected %u, got %u\n", i, (uint32_t)block->tracks[i].number, (uint32_t)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, (uint32_t)block->tracks[i].num_indices, (uint32_t)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, (uint32_t)block->tracks[i].type, (uint32_t)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, (uint32_t)block->tracks[i].pre_emphasis, (uint32_t)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) {
+ printf("FAILED, tracks[%u].indices[%u].offset mismatch, expected %" PRIu64 ", got %" PRIu64 "\n", i, j, block->tracks[i].indices[j].offset, blockcopy->tracks[i].indices[j].offset);
+ 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, (uint32_t)block->tracks[i].indices[j].number, (uint32_t)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", (uint32_t)block->type, (uint32_t)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", (uint32_t)len, (uint32_t)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", (uint32_t)len, (uint32_t)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(block->data_length > 0 && 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, uint32_t 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", (uint32_t)block->is_last, (uint32_t)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", (uint32_t)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", (uint32_t)n * (uint32_t)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 = 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, "This", 4);
+ application1->data.application.data = 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, "Here", 4);
+ application2->data.application.data = 0;
+
+ {
+ const uint32_t vendor_string_length = (uint32_t)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 = 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 = 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 = 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 = malloc_or_die_(1);
+ vorbiscomment->data.vorbis_comment.comments[1].entry[0] = '\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 = 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 = 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 = 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 = 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_seeking/CMakeLists.txt b/src/test_seeking/CMakeLists.txt
new file mode 100644
index 0000000..5144291
--- /dev/null
+++ b/src/test_seeking/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_executable(test_seeking
+ main.c
+ $<$<BOOL:${WIN32}>:../../include/share/win_utf8_io.h>
+ $<$<BOOL:${WIN32}>:../share/win_utf8_io/win_utf8_io.c>)
+target_link_libraries(test_seeking FLAC)
diff --git a/src/test_seeking/Makefile.am b/src/test_seeking/Makefile.am
new file mode 100644
index 0000000..9c9b8da
--- /dev/null
+++ b/src/test_seeking/Makefile.am
@@ -0,0 +1,39 @@
+# test_seeking - Seeking tester for libFLAC
+# Copyright (C) 2004-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+EXTRA_DIST = \
+ CMakeLists.txt
+
+AM_CFLAGS = @OGG_CFLAGS@
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+
+check_PROGRAMS = test_seeking
+
+if OS_IS_WINDOWS
+win_utf8_lib = $(top_builddir)/src/share/win_utf8_io/libwin_utf8_io.la
+endif
+
+test_seeking_LDADD = \
+ $(top_builddir)/src/libFLAC/libFLAC.la \
+ $(win_utf8_lib)
+
+test_seeking_SOURCES = \
+ main.c
+
+CLEANFILES = test_seeking.exe
diff --git a/src/test_seeking/Makefile.in b/src/test_seeking/Makefile.in
new file mode 100644
index 0000000..531354c
--- /dev/null
+++ b/src/test_seeking/Makefile.in
@@ -0,0 +1,666 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in 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.
+
+@SET_MAKE@
+
+# test_seeking - Seeking tester for libFLAC
+# Copyright (C) 2004-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+check_PROGRAMS = test_seeking$(EXEEXT)
+subdir = src/test_seeking
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/add_cflags.m4 \
+ $(top_srcdir)/m4/add_cxxflags.m4 \
+ $(top_srcdir)/m4/ax_add_fortify_source.m4 \
+ $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_enable_debug.m4 \
+ $(top_srcdir)/m4/bswap.m4 $(top_srcdir)/m4/clang.m4 \
+ $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gcc_version.m4 \
+ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/ogg.m4 \
+ $(top_srcdir)/m4/really_gcc.m4 \
+ $(top_srcdir)/m4/stack_protect.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am_test_seeking_OBJECTS = main.$(OBJEXT)
+test_seeking_OBJECTS = $(am_test_seeking_OBJECTS)
+test_seeking_DEPENDENCIES = $(top_builddir)/src/libFLAC/libFLAC.la \
+ $(win_utf8_lib)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/main.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(test_seeking_SOURCES)
+DIST_SOURCES = $(test_seeking_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_64_BIT_WORDS = @ENABLE_64_BIT_WORDS@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLAC__HAS_OGG = @FLAC__HAS_OGG@
+FLAC__TEST_LEVEL = @FLAC__TEST_LEVEL@
+FLAC__TEST_WITH_VALGRIND = @FLAC__TEST_WITH_VALGRIND@
+GCC_MAJOR_VERSION = @GCC_MAJOR_VERSION@
+GCC_MINOR_VERSION = @GCC_MINOR_VERSION@
+GCC_VERSION = @GCC_VERSION@
+GIT_COMMIT_VERSION_HASH = @GIT_COMMIT_VERSION_HASH@
+GIT_FOUND = @GIT_FOUND@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_FUZZING_ENGINE = @LIB_FUZZING_ENGINE@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OBJ_FORMAT = @OBJ_FORMAT@
+OGG_CFLAGS = @OGG_CFLAGS@
+OGG_LIBS = @OGG_LIBS@
+OGG_PACKAGE = @OGG_PACKAGE@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = \
+ CMakeLists.txt
+
+AM_CFLAGS = @OGG_CFLAGS@
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+@OS_IS_WINDOWS_TRUE@win_utf8_lib = $(top_builddir)/src/share/win_utf8_io/libwin_utf8_io.la
+test_seeking_LDADD = \
+ $(top_builddir)/src/libFLAC/libFLAC.la \
+ $(win_utf8_lib)
+
+test_seeking_SOURCES = \
+ main.c
+
+CLEANFILES = test_seeking.exe
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/test_seeking/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/test_seeking/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+ @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+test_seeking$(EXEEXT): $(test_seeking_OBJECTS) $(test_seeking_DEPENDENCIES) $(EXTRA_test_seeking_DEPENDENCIES)
+ @rm -f test_seeking$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_seeking_OBJECTS) $(test_seeking_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/main.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/main.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-checkPROGRAMS clean-generic clean-libtool cscopelist-am \
+ ctags ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/test_seeking/main.c b/src/test_seeking/main.c
new file mode 100644
index 0000000..16ab9f4
--- /dev/null
+++ b/src/test_seeking/main.c
@@ -0,0 +1,473 @@
+/* test_seeking - Seeking tester for libFLAC
+ * Copyright (C) 2004-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <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"
+#include "share/compat.h"
+
+typedef struct {
+ FLAC__int32 **pcm;
+ FLAC__bool got_data;
+ FLAC__uint64 total_samples;
+ uint32_t channels;
+ uint32_t 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 signum)
+{
+ (void)signum;
+ 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", (uint32_t)state, FLAC__StreamDecoderStateString[state]);
+
+ return false;
+}
+
+static uint32_t 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 FLAC__off_t get_filesize_(const char *srcpath)
+{
+ struct flac_stat_s srcstat;
+
+ if(0 == flac_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;
+ uint32_t channels = 0, bps = 0, samples, i, j;
+
+ FLAC__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 = (uint32_t)(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] = malloc(sizeof(FLAC__int32)*samples))) {
+ printf("ERROR: allocating space for PCM samples\n");
+ return false;
+ }
+ }
+ if(0 == (f = flac_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++) {
+ if (fread(&c, 1, 1, f) == 1)
+ pcm[j][i] = c;
+ }
+ }
+ }
+ else { /* bps == 16 */
+ uint8_t c[2];
+ uint16_t value;
+ for(i = 0; i < samples; i++) {
+ for(j = 0; j < channels; j++) {
+ if (fread(&c, 1, 2, f) == 2) {
+ value = (c[0] << 8) | c[1];
+ pcm[j][i] = value & 0x8000 ? 0xffff0000 | value : value;
+ }
+ }
+ }
+ }
+ 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)
+ printf("frame@%" PRIu64 "(%u)... ", frame->header.number.sample_number, frame->header.blocksize);
+ fflush(stdout);
+
+ /* check against PCM data if we have it */
+ if (dcd->pcm) {
+ uint32_t c, i, j;
+ for (c = 0; c < frame->header.channels; c++)
+ for (i = (uint32_t)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", (uint32_t)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, FLAC__off_t filesize, uint32_t count, FLAC__int64 total_samples, uint32_t read_mode, FLAC__int32 **pcm)
+{
+ FLAC__StreamDecoder *decoder;
+ DecoderClientData decoder_client_data;
+ uint32_t 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);
+ }
+
+ printf("file's total_samples is %" PRIu64 "\n", decoder_client_data.total_samples);
+ 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 = (long int)(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);
+ }
+
+ printf("#%u:seek(%" PRIu64 ")... ", i, pos);
+ 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;
+}
+
+
+int main(int argc, char *argv[])
+{
+ const char *flacfilename, *rawfilename = 0;
+ uint32_t count = 0, read_mode;
+ FLAC__int64 samples = -1;
+ FLAC__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) {
+ fputs(usage, stderr);
+ return 1;
+ }
+
+ flacfilename = argv[1];
+
+ if (argc > 2)
+ count = strtoul(argv[2], 0, 10);
+ if (argc > 3)
+ samples = strtoull(argv[3], 0, 10);
+ 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((uint32_t)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_streams/CMakeLists.txt b/src/test_streams/CMakeLists.txt
new file mode 100644
index 0000000..f9fafb9
--- /dev/null
+++ b/src/test_streams/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_executable(test_streams main.c)
+target_link_libraries(test_streams FLAC grabbag)
diff --git a/src/test_streams/Makefile.am b/src/test_streams/Makefile.am
new file mode 100644
index 0000000..9aa4b02
--- /dev/null
+++ b/src/test_streams/Makefile.am
@@ -0,0 +1,29 @@
+# test_streams - Simple test pattern generator
+# Copyright (C) 2000-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+EXTRA_DIST = \
+ CMakeLists.txt
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+check_PROGRAMS = test_streams
+test_streams_SOURCES = \
+ main.c
+
+test_streams_LDADD = $(top_builddir)/src/share/grabbag/libgrabbag.la -lm
+
+CLEANFILES = test_streams.exe
diff --git a/src/test_streams/Makefile.in b/src/test_streams/Makefile.in
new file mode 100644
index 0000000..83c60e7
--- /dev/null
+++ b/src/test_streams/Makefile.in
@@ -0,0 +1,661 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in 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.
+
+@SET_MAKE@
+
+# test_streams - Simple test pattern generator
+# Copyright (C) 2000-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+check_PROGRAMS = test_streams$(EXEEXT)
+subdir = src/test_streams
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/add_cflags.m4 \
+ $(top_srcdir)/m4/add_cxxflags.m4 \
+ $(top_srcdir)/m4/ax_add_fortify_source.m4 \
+ $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_enable_debug.m4 \
+ $(top_srcdir)/m4/bswap.m4 $(top_srcdir)/m4/clang.m4 \
+ $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gcc_version.m4 \
+ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/ogg.m4 \
+ $(top_srcdir)/m4/really_gcc.m4 \
+ $(top_srcdir)/m4/stack_protect.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am_test_streams_OBJECTS = main.$(OBJEXT)
+test_streams_OBJECTS = $(am_test_streams_OBJECTS)
+test_streams_DEPENDENCIES = \
+ $(top_builddir)/src/share/grabbag/libgrabbag.la
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/main.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(test_streams_SOURCES)
+DIST_SOURCES = $(test_streams_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_64_BIT_WORDS = @ENABLE_64_BIT_WORDS@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLAC__HAS_OGG = @FLAC__HAS_OGG@
+FLAC__TEST_LEVEL = @FLAC__TEST_LEVEL@
+FLAC__TEST_WITH_VALGRIND = @FLAC__TEST_WITH_VALGRIND@
+GCC_MAJOR_VERSION = @GCC_MAJOR_VERSION@
+GCC_MINOR_VERSION = @GCC_MINOR_VERSION@
+GCC_VERSION = @GCC_VERSION@
+GIT_COMMIT_VERSION_HASH = @GIT_COMMIT_VERSION_HASH@
+GIT_FOUND = @GIT_FOUND@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_FUZZING_ENGINE = @LIB_FUZZING_ENGINE@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OBJ_FORMAT = @OBJ_FORMAT@
+OGG_CFLAGS = @OGG_CFLAGS@
+OGG_LIBS = @OGG_LIBS@
+OGG_PACKAGE = @OGG_PACKAGE@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = \
+ CMakeLists.txt
+
+AM_CPPFLAGS = -I$(top_builddir) -I$(srcdir)/include -I$(top_srcdir)/include
+test_streams_SOURCES = \
+ main.c
+
+test_streams_LDADD = $(top_builddir)/src/share/grabbag/libgrabbag.la -lm
+CLEANFILES = test_streams.exe
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/test_streams/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/test_streams/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+ @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+test_streams$(EXEEXT): $(test_streams_OBJECTS) $(test_streams_DEPENDENCIES) $(EXTRA_test_streams_DEPENDENCIES)
+ @rm -f test_streams$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_streams_OBJECTS) $(test_streams_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/main.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/main.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-checkPROGRAMS clean-generic clean-libtool cscopelist-am \
+ ctags ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/test_streams/main.c b/src/test_streams/main.c
new file mode 100644
index 0000000..466bf8e
--- /dev/null
+++ b/src/test_streams/main.c
@@ -0,0 +1,1398 @@
+/* test_streams - Simple test pattern generator
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "share/compat.h"
+#if defined _MSC_VER || defined __MINGW32__
+#include <time.h>
+#else
+#include <sys/time.h>
+#endif
+#include "FLAC/assert.h"
+#include "FLAC/ordinals.h"
+#include "share/compat.h"
+
+#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_unsigned(FILE *f, FLAC__uint32 x, size_t bytes)
+{
+ while(bytes) {
+ if(fputc(x, f) == EOF)
+ return false;
+ x >>= 8;
+ bytes--;
+ }
+ return true;
+}
+
+static FLAC__bool write_little_endian_signed(FILE *f, FLAC__int32 x, size_t bytes)
+{
+ return write_little_endian_unsigned(f, (FLAC__uint32) x, bytes);
+}
+
+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
+ ;
+}
+
+static FLAC__bool write_little_endian_int32(FILE *f, FLAC__int32 x)
+{
+ return write_little_endian_uint32(f, (FLAC__uint32)x);
+}
+
+#if defined(_MSC_VER)
+// silence 4 MSVC warnings 'conversion from 'FLAC__uint64' to 'int', possible loss of data'
+#pragma warning ( disable : 4244 )
+#endif
+static FLAC__bool write_little_endian_uint64(FILE *f, FLAC__uint64 x)
+{
+ return
+ fputc(x, f) != EOF &&
+ fputc(x >> 8, f) != EOF &&
+ fputc(x >> 16, f) != EOF &&
+ fputc(x >> 24, f) != EOF &&
+ fputc(x >> 32, f) != EOF &&
+ fputc(x >> 40, f) != EOF &&
+ fputc(x >> 48, f) != EOF &&
+ fputc(x >> 56, f) != EOF
+ ;
+}
+#if defined(_MSC_VER)
+#pragma warning ( default : 4244 )
+#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 full-scale deflection 32bps stream */
+static FLAC__bool generate_fsd32(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? 2147483647 : -2147483648;
+ if(!write_little_endian_int32(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;
+}
+
+/* a mono sine-wave 32bps stream */
+static FLAC__bool generate_sine32_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 = 0x7fffffff;
+ 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_int32(f, v))
+ goto foo;
+ }
+
+ fclose(f);
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+/* a stereo sine-wave 32bps stream */
+static FLAC__bool generate_sine32_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 = 0x7fffffff;
+ 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_int32(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_int32(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_signed_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_signed(f, v, bytes_per_sample))
+ goto foo;
+ }
+ }
+
+ fclose(f);
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+static FLAC__bool generate_unsigned_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);
+ const double half_scale = 0.5 * full_scale;
+ 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)(half_scale + val + 0.5) + ((GET_RANDOM_BYTE>>4)-8);
+ if(!write_little_endian_unsigned(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;
+}
+
+/* flavor is: 0:WAVE, 1:RF64, 2:WAVE64 */
+static FLAC__bool generate_wav(const char *filename, unsigned sample_rate, unsigned channels, unsigned bps, unsigned samples, FLAC__bool strict, int flavor)
+{
+ const FLAC__bool waveformatextensible = strict && (channels > 2 || (bps != 8 && bps != 16));
+
+ const unsigned bytes_per_sample = (bps+7)/8;
+ const unsigned shift = (bps%8)? 8 - (bps%8) : 0;
+ /* this rig is not going over 4G so we're ok with 32-bit sizes here */
+ const FLAC__uint32 true_size = channels * bytes_per_sample * samples;
+ const FLAC__uint32 padded_size = flavor<2? (true_size + 1) & (~1u) : (true_size + 7) & (~7u);
+ 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;
+ /* RIFFxxxxWAVE or equivalent: */
+ switch(flavor) {
+ case 0:
+ if(fwrite("RIFF", 1, 4, f) < 4)
+ goto foo;
+ /* +4 for WAVE */
+ /* +8+{40,16} for fmt chunk */
+ /* +8 for data chunk header */
+ if(!write_little_endian_uint32(f, 4 + 8+(waveformatextensible?40:16) + 8 + padded_size))
+ goto foo;
+ if(fwrite("WAVE", 1, 4, f) < 4)
+ goto foo;
+ break;
+ case 1:
+ if(fwrite("RF64", 1, 4, f) < 4)
+ goto foo;
+ if(!write_little_endian_uint32(f, 0xffffffff))
+ goto foo;
+ if(fwrite("WAVE", 1, 4, f) < 4)
+ goto foo;
+ break;
+ case 2:
+ /* RIFF GUID 66666972-912E-11CF-A5D6-28DB04C10000 */
+ if(fwrite("\x72\x69\x66\x66\x2E\x91\xCF\x11\xA5\xD6\x28\xDB\x04\xC1\x00\x00", 1, 16, f) < 16)
+ goto foo;
+ /* +(16+8) for RIFF GUID + size */
+ /* +16 for WAVE GUID */
+ /* +16+8+{40,16} for fmt chunk */
+ /* +16+8 for data chunk header */
+ if(!write_little_endian_uint64(f, (16+8) + 16 + 16+8+(waveformatextensible?40:16) + (16+8) + padded_size))
+ goto foo;
+ /* WAVE GUID 65766177-ACF3-11D3-8CD1-00C04F8EDB8A */
+ if(fwrite("\x77\x61\x76\x65\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 1, 16, f) < 16)
+ goto foo;
+ break;
+ default:
+ goto foo;
+ }
+ if(flavor == 1) { /* rf64 */
+ if(fwrite("ds64", 1, 4, f) < 4)
+ goto foo;
+ if(!write_little_endian_uint32(f, 28)) /* ds64 chunk size */
+ goto foo;
+ if(!write_little_endian_uint64(f, 36 + padded_size + (waveformatextensible?60:36)))
+ goto foo;
+ if(!write_little_endian_uint64(f, true_size))
+ goto foo;
+ if(!write_little_endian_uint64(f, samples))
+ goto foo;
+ if(!write_little_endian_uint32(f, 0)) /* table size */
+ goto foo;
+ }
+ /* fmt chunk */
+ if(flavor < 2) {
+ if(fwrite("fmt ", 1, 4, f) < 4)
+ goto foo;
+ /* chunk size */
+ if(!write_little_endian_uint32(f, waveformatextensible?40:16))
+ goto foo;
+ }
+ else { /* wave64 */
+ /* fmt GUID 20746D66-ACF3-11D3-8CD1-00C04F8EDB8A */
+ if(fwrite("\x66\x6D\x74\x20\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 1, 16, f) < 16)
+ goto foo;
+ /* chunk size (+16+8 for GUID and size fields) */
+ if(!write_little_endian_uint64(f, 16+8+(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;
+ }
+ /* data chunk */
+ if(flavor < 2) {
+ if(fwrite("data", 1, 4, f) < 4)
+ goto foo;
+ if(!write_little_endian_uint32(f, flavor==1? 0xffffffff : true_size))
+ goto foo;
+ }
+ else { /* wave64 */
+ /* data GUID 61746164-ACF3-11D3-8CD1-00C04F8EDB8A */
+ if(fwrite("\x64\x61\x74\x61\xF3\xAC\xD3\x11\x8C\xD1\x00\xC0\x4F\x8E\xDB\x8A", 1, 16, f) != 16)
+ goto foo;
+ /* +16+8 for GUID and size fields */
+ if(!write_little_endian_uint64(f, 16+8 + 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_signed(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', 'j', 'u', 'n', 'k',
+ 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,0x88,0x58,0x01, 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;
+}
+
+static FLAC__bool write_simple_wavex_header (FILE * f, unsigned samplerate, unsigned channels, unsigned bytespersample, unsigned frames)
+{
+ unsigned datalen = channels * bytespersample * frames ;
+
+ if (fwrite("RIFF", 1, 4, f) != 4)
+ return false;
+ if (!write_little_endian_uint32(f, 60 + datalen))
+ return false;
+
+ if (fwrite("WAVEfmt ", 8, 1, f) != 1)
+ return false;
+ if (!write_little_endian_uint32(f, 40))
+ return false;
+
+ if(!write_little_endian_uint16(f, 65534)) /* WAVEFORMATEXTENSIBLE tag */
+ return false;
+ if(!write_little_endian_uint16(f, channels))
+ return false;
+ if(!write_little_endian_uint32(f, samplerate))
+ return false;
+ if(!write_little_endian_uint32(f, samplerate * channels * bytespersample))
+ return false;
+ if(!write_little_endian_uint16(f, channels * bytespersample)) /* block align */
+ return false;
+ if(!write_little_endian_uint16(f, bytespersample * 8))
+ return false;
+
+ if(!write_little_endian_uint16(f, 22)) /* cbSize */
+ return false;
+ if(!write_little_endian_uint16(f, bytespersample * 8)) /* validBitsPerSample */
+ return false;
+ if(!write_little_endian_uint32(f, 0)) /* channelMask */
+ return false;
+ /* 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)
+ return false;
+
+ if (fwrite("data", 1, 4, f) != 4)
+ return false;
+ if (!write_little_endian_uint32(f, datalen))
+ return false;
+
+ return true;
+}
+
+static FLAC__bool generate_noisy_sine(void)
+{
+ FILE *f;
+ int64_t randstate = 0x1243456;
+ double sample, last_val = 0.0;
+ int k;
+ int seconds = 300;
+
+ if(0 == (f = fopen("noisy-sine.wav", "wb")))
+ return false;
+
+ if(!write_simple_wavex_header (f, 44100, 1, 2, 44100*seconds))
+ goto foo;
+
+ for (k = 0 ; k < seconds * 44100 ; k++) {
+ /* Obvioulsy not a crypto quality RNG. */
+ randstate = 11117 * randstate + 211231;
+ randstate = 11117 * randstate + 211231;
+ randstate = 11117 * randstate + 211231;
+
+ sample = ((int32_t) randstate) / (0x7fffffff * 1.000001);
+ sample = 0.2 * sample - 0.9 * last_val;
+
+ last_val = sample;
+
+ sample += sin (2.0 * k * M_PI * 1.0 / 32.0);
+ sample *= 0.4;
+#if !defined _MSC_VER
+ write_little_endian_int16(f, lrintf(sample * 32700.0));
+#else
+ write_little_endian_int16(f, (FLAC__int16)(sample * 32700.0));
+#endif
+ };
+
+ fclose(f);
+
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+static FLAC__bool generate_wackywav64s(void)
+{
+ FILE *f;
+ FLAC__byte wav[] = {
+ 0x72,0x69,0x66,0x66,0x2E,0x91,0xCF,0x11, /* RIFF GUID */
+ 0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00,
+ 152, 0, 0, 0, 0, 0, 0, 0,
+ 0x77,0x61,0x76,0x65,0xF3,0xAC,0xD3,0x11, /* WAVE GUID */
+ 0x8C,0xD1,0x00,0xC0,0x4F,0x8E,0xDB,0x8A,
+ 0x6A,0x75,0x6E,0x6B,0xF3,0xAC,0xD3,0x11, /* junk GUID */
+ 0x8C,0xD1,0x00,0xC0,0x4F,0x8E,0xDB,0x8A,
+ 32, 0, 0, 0 , 0, 0, 0, 0,
+ 'b', 'l', 'a', 'h', 'b', 'l', 'a', 'h',
+ 0x66,0x6D,0x74,0x20,0xF3,0xAC,0xD3,0x11, /* fmt GUID */
+ 0x8C,0xD1,0x00,0xC0,0x4F,0x8E,0xDB,0x8A,
+ 40, 0, 0, 0 , 0, 0, 0, 0,
+ 1, 0, 1, 0,0x44,0xAC, 0, 0,
+ 0x88,0x58,0x01, 0, 2, 0, 16, 0,
+ 0x64,0x61,0x74,0x61,0xF3,0xAC,0xD3,0x11, /* data GUID */
+ 0x8C,0xD1,0x00,0xC0,0x4F,0x8E,0xDB,0x8A,
+ 40, 0, 0, 0 , 0, 0, 0, 0,
+ 0, 0, 1, 0, 4, 0, 9, 0,
+ 16, 0, 25, 0, 36, 0, 49, 0,
+ 0x6A,0x75,0x6E,0x6B,0xF3,0xAC,0xD3,0x11, /* junk GUID */
+ 0x8C,0xD1,0x00,0xC0,0x4F,0x8E,0xDB,0x8A,
+ 32, 0, 0, 0 , 0, 0, 0, 0,
+ 'b', 'l', 'a', 'h', 'b', 'l', 'a', 'h'
+ };
+
+ if(0 == (f = fopen("wacky1.w64", "wb")))
+ return false;
+ if(fwrite(wav, 1, wav[16], f) < wav[16])
+ goto foo;
+ fclose(f);
+
+ wav[16] += 32;
+ if(0 == (f = fopen("wacky2.w64", "wb")))
+ return false;
+ if(fwrite(wav, 1, wav[16], f) < wav[16])
+ goto foo;
+ fclose(f);
+
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+static FLAC__bool generate_wackyrf64s(void)
+{
+ FILE *f;
+ FLAC__byte wav[] = {
+ 'R', 'F', '6', '4', 255, 255, 255, 255,
+ 'W', 'A', 'V', 'E', 'd', 's', '6', '4',
+ 28, 0, 0, 0, 112, 0, 0, 0,
+ 0, 0, 0, 0, 16, 0, 0, 0,
+ 0, 0, 0, 0, 8, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 'j', 'u', 'n', 'k',
+ 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,0x88,0x58,0x01, 0,
+ 2, 0, 16, 0, 'd', 'a', 't', 'a',
+ 255, 255, 255, 255, 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.rf64", "wb")))
+ return false;
+ if(fwrite(wav, 1, 120, f) < 120)
+ goto foo;
+ fclose(f);
+
+ wav[20] += 12;
+ if(0 == (f = fopen("wacky2.rf64", "wb")))
+ return false;
+ if(fwrite(wav, 1, 132, f) < 132)
+ goto foo;
+ fclose(f);
+
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+static FLAC__bool generate_replaygain_tone (unsigned samplerate)
+{
+ FILE *f;
+ char fname [256] ;
+ double tone, sample, samplerange;
+ int k;
+
+ flac_snprintf(fname, sizeof(fname), "rpg-tone-%u.wav", samplerate);
+
+ if(0 == (f = fopen(fname, "wb")))
+ return false;
+
+ if(!write_simple_wavex_header (f, samplerate, 1, 3, 220500))
+ goto foo;
+
+
+ samplerange = 0x7fffff; /* Largest sample value allowed for a 24 bit PCM file. */
+ tone = 1000.0; /* 1 kHz */
+
+ for (k = 0 ; k < 5 * 44100 ; k++) {
+ sample = sin(2 * M_PI * tone * k / samplerate);
+ sample *= samplerange;
+ if (!write_little_endian_uint24(f, (FLAC__int32) sample))
+ 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_fsd32("fsd32-01.raw", pattern01, 100)) return 1;
+ if(!generate_fsd32("fsd32-02.raw", pattern02, 100)) return 1;
+ if(!generate_fsd32("fsd32-03.raw", pattern03, 100)) return 1;
+ if(!generate_fsd32("fsd32-04.raw", pattern04, 100)) return 1;
+ if(!generate_fsd32("fsd32-05.raw", pattern05, 100)) return 1;
+ if(!generate_fsd32("fsd32-06.raw", pattern06, 100)) return 1;
+ if(!generate_fsd32("fsd32-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;
+
+ if(!generate_sine32_1("sine32-00.raw", 48000.0, 200000, 441.0, 0.50, 441.0, 0.49)) return 1;
+ if(!generate_sine32_1("sine32-01.raw", 96000.0, 200000, 441.0, 0.61, 661.5, 0.37)) return 1;
+ if(!generate_sine32_1("sine32-02.raw", 44100.0, 200000, 441.0, 0.50, 882.0, 0.49)) return 1;
+ if(!generate_sine32_1("sine32-03.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49)) return 1;
+ if(!generate_sine32_1("sine32-04.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29)) return 1;
+
+ if(!generate_sine32_2("sine32-10.raw", 48000.0, 200000, 441.0, 0.50, 441.0, 0.49, 1.0)) return 1;
+ if(!generate_sine32_2("sine32-11.raw", 48000.0, 200000, 441.0, 0.61, 661.5, 0.37, 1.0)) return 1;
+ if(!generate_sine32_2("sine32-12.raw", 96000.0, 200000, 441.0, 0.50, 882.0, 0.49, 1.0)) return 1;
+ if(!generate_sine32_2("sine32-13.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49, 1.0)) return 1;
+ if(!generate_sine32_2("sine32-14.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29, 1.0)) return 1;
+ if(!generate_sine32_2("sine32-15.raw", 44100.0, 200000, 441.0, 0.50, 441.0, 0.49, 0.5)) return 1;
+ if(!generate_sine32_2("sine32-16.raw", 44100.0, 200000, 441.0, 0.61, 661.5, 0.37, 2.0)) return 1;
+ if(!generate_sine32_2("sine32-17.raw", 44100.0, 200000, 441.0, 0.50, 882.0, 0.49, 0.7)) return 1;
+ if(!generate_sine32_2("sine32-18.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49, 1.3)) return 1;
+ if(!generate_sine32_2("sine32-19.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29, 0.1)) return 1;
+
+ if(!generate_replaygain_tone(8000)) return 1;
+ if(!generate_replaygain_tone(11025)) return 1;
+ if(!generate_replaygain_tone(12000)) return 1;
+ if(!generate_replaygain_tone(16000)) return 1;
+ if(!generate_replaygain_tone(18900)) return 1;
+ if(!generate_replaygain_tone(22050)) return 1;
+ if(!generate_replaygain_tone(24000)) return 1;
+ if(!generate_replaygain_tone(28000)) return 1;
+ if(!generate_replaygain_tone(32000)) return 1;
+ if(!generate_replaygain_tone(36000)) return 1;
+ if(!generate_replaygain_tone(37800)) return 1;
+ if(!generate_replaygain_tone(44100)) return 1;
+ if(!generate_replaygain_tone(48000)) return 1;
+ if(!generate_replaygain_tone(96000)) return 1;
+ if(!generate_replaygain_tone(192000)) 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;
+ if(!generate_wackywav64s()) return 1;
+ if(!generate_wackyrf64s()) return 1;
+ if(!generate_noisy_sine()) return 1;
+ for(channels = 1; channels <= 8; channels *= 2) {
+ unsigned bits_per_sample;
+ for(bits_per_sample = 8; bits_per_sample <= 24; bits_per_sample += 4) {
+ static const unsigned nsamples[] = { 1, 111, 4777 } ;
+ unsigned samples;
+ for(samples = 0; samples < sizeof(nsamples)/sizeof(nsamples[0]); samples++) {
+ char fn[64];
+
+ flac_snprintf(fn, sizeof (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;
+
+ flac_snprintf(fn, sizeof (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, /*flavor=*/0))
+ return 1;
+
+ flac_snprintf(fn, sizeof (fn), "rt-%u-%u-%u.rf64", channels, bits_per_sample, nsamples[samples]);
+ if(!generate_wav(fn, 44100, channels, bits_per_sample, nsamples[samples], /*strict=*/true, /*flavor=*/1))
+ return 1;
+
+ flac_snprintf(fn, sizeof (fn), "rt-%u-%u-%u.w64", channels, bits_per_sample, nsamples[samples]);
+ if(!generate_wav(fn, 44100, channels, bits_per_sample, nsamples[samples], /*strict=*/true, /*flavor=*/2))
+ return 1;
+
+ if(bits_per_sample % 8 == 0) {
+ flac_snprintf(fn, sizeof (fn), "rt-%u-%u-signed-%u.raw", channels, bits_per_sample, nsamples[samples]);
+ if(!generate_signed_raw(fn, channels, bits_per_sample/8, nsamples[samples]))
+ return 1;
+ flac_snprintf(fn, sizeof (fn), "rt-%u-%u-unsigned-%u.raw", channels, bits_per_sample, nsamples[samples]);
+ if(!generate_unsigned_raw(fn, channels, bits_per_sample/8, nsamples[samples]))
+ return 1;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/src/utils/Makefile.am b/src/utils/Makefile.am
new file mode 100644
index 0000000..5207b13
--- /dev/null
+++ b/src/utils/Makefile.am
@@ -0,0 +1,19 @@
+# FLAC - Free Lossless Audio Codec
+# Copyright (C) 2001-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This file is part the FLAC project. FLAC is comprised of several
+# components distributed under different 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 = flacdiff flactimer
diff --git a/src/utils/Makefile.in b/src/utils/Makefile.in
new file mode 100644
index 0000000..c433e15
--- /dev/null
+++ b/src/utils/Makefile.in
@@ -0,0 +1,676 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in 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.
+
+@SET_MAKE@
+
+# FLAC - Free Lossless Audio Codec
+# Copyright (C) 2001-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This file is part the FLAC project. FLAC is comprised of several
+# components distributed under different 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.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/utils
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/add_cflags.m4 \
+ $(top_srcdir)/m4/add_cxxflags.m4 \
+ $(top_srcdir)/m4/ax_add_fortify_source.m4 \
+ $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_enable_debug.m4 \
+ $(top_srcdir)/m4/bswap.m4 $(top_srcdir)/m4/clang.m4 \
+ $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gcc_version.m4 \
+ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/ogg.m4 \
+ $(top_srcdir)/m4/really_gcc.m4 \
+ $(top_srcdir)/m4/stack_protect.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_64_BIT_WORDS = @ENABLE_64_BIT_WORDS@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLAC__HAS_OGG = @FLAC__HAS_OGG@
+FLAC__TEST_LEVEL = @FLAC__TEST_LEVEL@
+FLAC__TEST_WITH_VALGRIND = @FLAC__TEST_WITH_VALGRIND@
+GCC_MAJOR_VERSION = @GCC_MAJOR_VERSION@
+GCC_MINOR_VERSION = @GCC_MINOR_VERSION@
+GCC_VERSION = @GCC_VERSION@
+GIT_COMMIT_VERSION_HASH = @GIT_COMMIT_VERSION_HASH@
+GIT_FOUND = @GIT_FOUND@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_FUZZING_ENGINE = @LIB_FUZZING_ENGINE@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OBJ_FORMAT = @OBJ_FORMAT@
+OGG_CFLAGS = @OGG_CFLAGS@
+OGG_LIBS = @OGG_LIBS@
+OGG_PACKAGE = @OGG_PACKAGE@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = flacdiff flactimer
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/utils/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/utils/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-generic clean-libtool cscopelist-am ctags \
+ ctags-am distclean distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/utils/flacdiff/CMakeLists.txt b/src/utils/flacdiff/CMakeLists.txt
new file mode 100644
index 0000000..ec9f771
--- /dev/null
+++ b/src/utils/flacdiff/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_executable(flacdiff
+ main.cpp
+ $<$<BOOL:${WIN32}>:../../../include/share/win_utf8_io.h>
+ $<$<BOOL:${WIN32}>:../../share/win_utf8_io/win_utf8_io.c>)
+target_link_libraries(flacdiff FLAC++)
diff --git a/src/utils/flacdiff/Makefile.am b/src/utils/flacdiff/Makefile.am
new file mode 100644
index 0000000..b181d98
--- /dev/null
+++ b/src/utils/flacdiff/Makefile.am
@@ -0,0 +1,21 @@
+# flacdiff - Displays where two FLAC streams differ
+# Copyright (C) 2007-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+EXTRA_DIST = \
+ CMakeLists.txt \
+ main.cpp
diff --git a/src/utils/flacdiff/Makefile.in b/src/utils/flacdiff/Makefile.in
new file mode 100644
index 0000000..2ff13fc
--- /dev/null
+++ b/src/utils/flacdiff/Makefile.in
@@ -0,0 +1,501 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in 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.
+
+@SET_MAKE@
+
+# flacdiff - Displays where two FLAC streams differ
+# Copyright (C) 2007-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/utils/flacdiff
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/add_cflags.m4 \
+ $(top_srcdir)/m4/add_cxxflags.m4 \
+ $(top_srcdir)/m4/ax_add_fortify_source.m4 \
+ $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_enable_debug.m4 \
+ $(top_srcdir)/m4/bswap.m4 $(top_srcdir)/m4/clang.m4 \
+ $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gcc_version.m4 \
+ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/ogg.m4 \
+ $(top_srcdir)/m4/really_gcc.m4 \
+ $(top_srcdir)/m4/stack_protect.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_64_BIT_WORDS = @ENABLE_64_BIT_WORDS@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLAC__HAS_OGG = @FLAC__HAS_OGG@
+FLAC__TEST_LEVEL = @FLAC__TEST_LEVEL@
+FLAC__TEST_WITH_VALGRIND = @FLAC__TEST_WITH_VALGRIND@
+GCC_MAJOR_VERSION = @GCC_MAJOR_VERSION@
+GCC_MINOR_VERSION = @GCC_MINOR_VERSION@
+GCC_VERSION = @GCC_VERSION@
+GIT_COMMIT_VERSION_HASH = @GIT_COMMIT_VERSION_HASH@
+GIT_FOUND = @GIT_FOUND@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_FUZZING_ENGINE = @LIB_FUZZING_ENGINE@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OBJ_FORMAT = @OBJ_FORMAT@
+OGG_CFLAGS = @OGG_CFLAGS@
+OGG_LIBS = @OGG_LIBS@
+OGG_PACKAGE = @OGG_PACKAGE@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = \
+ CMakeLists.txt \
+ main.cpp
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/utils/flacdiff/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/utils/flacdiff/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ cscopelist-am ctags-am distclean distclean-generic \
+ distclean-libtool distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/utils/flacdiff/main.cpp b/src/utils/flacdiff/main.cpp
new file mode 100644
index 0000000..358fe04
--- /dev/null
+++ b/src/utils/flacdiff/main.cpp
@@ -0,0 +1,230 @@
+/* flacdiff - Displays where two FLAC streams differ
+ * Copyright (C) 2007-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include "FLAC++/decoder.h"
+#include "share/compat.h"
+
+#ifdef _MSC_VER
+// warning C4800: 'int' : forcing to bool 'true' or 'false' (performance warning)
+#pragma warning ( disable : 4800 )
+#endif
+
+class AutoFILE {
+protected:
+ ::FILE *f_;
+public:
+ inline AutoFILE(const char *path, const char *mode): f_(::fopen(path, mode)) { }
+ inline virtual ~AutoFILE() { if (f_) (void)::fclose(f_); }
+
+ inline operator bool() const { return 0 != f_; }
+ inline operator const ::FILE *() const { return f_; }
+ inline operator ::FILE *() { return f_; }
+private:
+ AutoFILE();
+ AutoFILE(const AutoFILE &);
+ void operator=(const AutoFILE &);
+};
+
+class Decoder: public FLAC::Decoder::Stream {
+public:
+ Decoder(AutoFILE &f, FLAC__off_t tgt): tgtpos_((FLAC__uint64)tgt), curpos_(0), go_(true), err_(false), frame_(), f_(f) { memset(&frame_, 0, sizeof(::FLAC__Frame)); }
+ FLAC__uint64 tgtpos_, curpos_;
+ bool go_, err_;
+ ::FLAC__Frame frame_;
+protected:
+ AutoFILE &f_;
+ // from FLAC::Decoder::Stream
+ virtual ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes)
+ {
+ *bytes = fread(buffer, 1, *bytes, f_);
+ if(ferror((FILE*)f_))
+ return ::FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ else if(*bytes == 0 && feof((FILE*)f_))
+ return ::FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+ else
+ return ::FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+ }
+
+ virtual ::FLAC__StreamDecoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset)
+ {
+ FLAC__off_t off = ftello(f_);
+ if(off < 0)
+ return ::FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+ *absolute_byte_offset = off;
+ return ::FLAC__STREAM_DECODER_TELL_STATUS_OK;
+ }
+
+ virtual bool eof_callback()
+ {
+ return (bool)feof((FILE*)f_);
+ }
+
+ virtual ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const /*buffer*/[])
+ {
+ FLAC__uint64 pos;
+ if(!get_decode_position(&pos)) {
+ go_ = false;
+ err_ = true;
+ return ::FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+ }
+ if(pos > tgtpos_) {
+ go_ = false;
+ frame_ = *frame;
+ }
+ else
+ curpos_ = pos;
+ return ::FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+ }
+
+ virtual void error_callback(::FLAC__StreamDecoderErrorStatus status)
+ {
+ fprintf(stderr, "got error %d:%s\n", status, ::FLAC__StreamDecoderErrorStatusString[status]);
+ go_ = false;
+ err_ = true;
+ }
+};
+
+static bool show_diff(AutoFILE &f1, AutoFILE &f2, FLAC__off_t off)
+{
+ Decoder d1(f1, off), d2(f2, off);
+ if(!d1) {
+ fprintf(stderr, "ERROR: setting up decoder1, state=%s\n", d1.get_state().resolved_as_cstring(d1));
+ return false;
+ }
+ if(!d2) {
+ fprintf(stderr, "ERROR: setting up decoder2, state=%s\n", d2.get_state().resolved_as_cstring(d2));
+ return false;
+ }
+ ::FLAC__StreamDecoderInitStatus is;
+ if((is = d1.init()) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+ fprintf(stderr, "ERROR: initializing decoder1, status=%s state=%s\n", FLAC__StreamDecoderInitStatusString[is], d1.get_state().resolved_as_cstring(d1));
+ return false;
+ }
+ if((is = d2.init()) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+ fprintf(stderr, "ERROR: initializing decoder2, status=%s state=%s\n", FLAC__StreamDecoderInitStatusString[is], d2.get_state().resolved_as_cstring(d2));
+ return false;
+ }
+ if(!d1.process_until_end_of_metadata()) {
+ fprintf(stderr, "ERROR: skipping metadata in decoder1, state=%s\n", d1.get_state().resolved_as_cstring(d1));
+ return false;
+ }
+ if(!d2.process_until_end_of_metadata()) {
+ fprintf(stderr, "ERROR: skipping metadata in decoder2, state=%s\n", d2.get_state().resolved_as_cstring(d2));
+ return false;
+ }
+ while(d1.go_ && d2.go_) {
+ if(!d1.process_single()) {
+ fprintf(stderr, "ERROR: decoding frame in decoder1, state=%s\n", d1.get_state().resolved_as_cstring(d1));
+ return false;
+ }
+ if(!d2.process_single()) {
+ fprintf(stderr, "ERROR: decoding frame in decoder2, state=%s\n", d2.get_state().resolved_as_cstring(d2));
+ return false;
+ }
+ }
+ if(d1.err_) {
+ fprintf(stderr, "ERROR: got err_ in decoder1, state=%s\n", d1.get_state().resolved_as_cstring(d1));
+ return false;
+ }
+ if(d2.err_) {
+ fprintf(stderr, "ERROR: got err_ in decoder2, state=%s\n", d2.get_state().resolved_as_cstring(d2));
+ return false;
+ }
+ if(d1.go_ != d2.go_) {
+ fprintf(stderr, "ERROR: d1.go_(%s) != d2.go_(%s)\n", d1.go_?"true":"false", d2.go_?"true":"false");
+ return false;
+ }
+ fprintf(stdout, "pos1 = %" PRIu64 " blocksize=%u sample#%" PRIu64 " frame#%" PRIu64 "\n", d1.curpos_, d1.frame_.header.blocksize, d1.frame_.header.number.sample_number, d1.frame_.header.number.sample_number / d1.frame_.header.blocksize);
+ fprintf(stdout, "pos2 = %" PRIu64 " blocksize=%u sample#%" PRIu64 " frame#%" PRIu64 "\n", d2.curpos_, d2.frame_.header.blocksize, d2.frame_.header.number.sample_number, d2.frame_.header.number.sample_number / d2.frame_.header.blocksize);
+
+ return true;
+}
+
+static FLAC__off_t get_diff_offset(AutoFILE &f1, AutoFILE &f2)
+{
+ FLAC__off_t off = 0;
+ while(1) {
+ if(feof((FILE*)f1) && feof((FILE*)f2)) {
+ fprintf(stderr, "ERROR: files are identical\n");
+ return -1;
+ }
+ if(feof((FILE*)f1)) {
+ fprintf(stderr, "ERROR: file1 EOF\n");
+ return -1;
+ }
+ if(feof((FILE*)f2)) {
+ fprintf(stderr, "ERROR: file2 EOF\n");
+ return -1;
+ }
+ if(fgetc(f1) != fgetc(f2))
+ return off;
+ off++;
+ }
+}
+
+static bool run(const char *fn1, const char *fn2)
+{
+ FLAC__off_t off;
+ AutoFILE f1(fn1, "rb"), f2(fn2, "rb");
+
+ if(!f1) {
+ flac_fprintf(stderr, "ERROR: opening %s for reading\n", fn1);
+ return false;
+ }
+ if(!f2) {
+ flac_fprintf(stderr, "ERROR: opening %s for reading\n", fn2);
+ return false;
+ }
+
+ if((off = get_diff_offset(f1, f2)) < 0)
+ return false;
+
+ fprintf(stdout, "got diff offset = %" PRId64 "\n", off);
+
+ return show_diff(f1, f2, off);
+}
+
+int main(int argc, char *argv[])
+{
+ const char *usage = "usage: flacdiff flacfile1 flacfile2\n";
+
+#ifdef _WIN32
+ if (get_utf8_argv(&argc, &argv) != 0) {
+ fprintf(stderr, "ERROR: failed to convert command line parameters to UTF-8\n");
+ return 1;
+ }
+#endif
+
+ if(argc > 1 && 0 == strcmp(argv[1], "-h")) {
+ printf("%s", usage);
+ return 0;
+ }
+ else if(argc != 3) {
+ fprintf(stderr, "%s", usage);
+ return 255;
+ }
+
+ return run(argv[1], argv[2])? 0 : 1;
+}
diff --git a/src/utils/flactimer/CMakeLists.txt b/src/utils/flactimer/CMakeLists.txt
new file mode 100644
index 0000000..47bf1e5
--- /dev/null
+++ b/src/utils/flactimer/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_executable(flactimer main.cpp)
+target_link_libraries(flactimer FLAC++)
diff --git a/src/utils/flactimer/Makefile.am b/src/utils/flactimer/Makefile.am
new file mode 100644
index 0000000..0737863
--- /dev/null
+++ b/src/utils/flactimer/Makefile.am
@@ -0,0 +1,21 @@
+# flactimer - Runs a command and prints timing information
+# Copyright (C) 2007-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+EXTRA_DIST = \
+ CMakeLists.txt \
+ main.cpp
diff --git a/src/utils/flactimer/Makefile.in b/src/utils/flactimer/Makefile.in
new file mode 100644
index 0000000..da3119d
--- /dev/null
+++ b/src/utils/flactimer/Makefile.in
@@ -0,0 +1,501 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in 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.
+
+@SET_MAKE@
+
+# flactimer - Runs a command and prints timing information
+# Copyright (C) 2007-2009 Josh Coalson
+# Copyright (C) 2011-2023 Xiph.Org Foundation
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/utils/flactimer
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/add_cflags.m4 \
+ $(top_srcdir)/m4/add_cxxflags.m4 \
+ $(top_srcdir)/m4/ax_add_fortify_source.m4 \
+ $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_enable_debug.m4 \
+ $(top_srcdir)/m4/bswap.m4 $(top_srcdir)/m4/clang.m4 \
+ $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gcc_version.m4 \
+ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/ogg.m4 \
+ $(top_srcdir)/m4/really_gcc.m4 \
+ $(top_srcdir)/m4/stack_protect.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_64_BIT_WORDS = @ENABLE_64_BIT_WORDS@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLAC__HAS_OGG = @FLAC__HAS_OGG@
+FLAC__TEST_LEVEL = @FLAC__TEST_LEVEL@
+FLAC__TEST_WITH_VALGRIND = @FLAC__TEST_WITH_VALGRIND@
+GCC_MAJOR_VERSION = @GCC_MAJOR_VERSION@
+GCC_MINOR_VERSION = @GCC_MINOR_VERSION@
+GCC_VERSION = @GCC_VERSION@
+GIT_COMMIT_VERSION_HASH = @GIT_COMMIT_VERSION_HASH@
+GIT_FOUND = @GIT_FOUND@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_FUZZING_ENGINE = @LIB_FUZZING_ENGINE@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OBJ_FORMAT = @OBJ_FORMAT@
+OGG_CFLAGS = @OGG_CFLAGS@
+OGG_LIBS = @OGG_LIBS@
+OGG_PACKAGE = @OGG_PACKAGE@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = \
+ CMakeLists.txt \
+ main.cpp
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/utils/flactimer/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/utils/flactimer/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ cscopelist-am ctags-am distclean distclean-generic \
+ distclean-libtool distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/utils/flactimer/main.cpp b/src/utils/flactimer/main.cpp
new file mode 100644
index 0000000..120a37f
--- /dev/null
+++ b/src/utils/flactimer/main.cpp
@@ -0,0 +1,175 @@
+/* flactimer - Runs a command and prints timing information
+ * Copyright (C) 2007-2009 Josh Coalson
+ * Copyright (C) 2011-2023 Xiph.Org Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <windows.h>
+#include "share/compat.h"
+#include "share/safe_str.h"
+
+static inline uint64_t time2nsec(const FILETIME &t)
+{
+ uint64_t n = t.dwHighDateTime;
+ n <<= 32;
+ n |= (uint64_t)t.dwLowDateTime;
+ return n * 100;
+}
+
+static void printtime(FILE *fout, uint64_t nsec, uint64_t total)
+{
+ uint32_t pct = (uint32_t)(100.0 * ((double)nsec / (double)total));
+ uint64_t msec = nsec / 1000000; nsec -= msec * 1000000;
+ uint64_t sec = msec / 1000; msec -= sec * 1000;
+ uint64_t min = sec / 60; sec -= min * 60;
+ uint64_t hour = min / 60; min -= hour * 60;
+ fprintf(fout, " %5u.%03u = %02u:%02u:%02u.%03u = %3u%%\n",
+ (uint32_t)((hour*60+min)*60+sec),
+ (uint32_t)msec,
+ (uint32_t)hour,
+ (uint32_t)min,
+ (uint32_t)sec,
+ (uint32_t)msec,
+ pct
+ );
+}
+
+int main(int argc, char *argv[])
+{
+ const char *usage = "usage: flactimer [-1 | -2 | -o outputfile] command\n";
+ FILE *fout = stderr;
+
+ if(argc == 1 || (argc > 1 && 0 == strcmp(argv[1], "-h"))) {
+ fprintf(stderr, usage);
+ return 0;
+ }
+ argv++;
+ argc--;
+ if(0 == strcmp(argv[0], "-1") || 0 == strcmp(argv[0], "/1")) {
+ fout = stdout;
+ argv++;
+ argc--;
+ }
+ else if(0 == strcmp(argv[0], "-2") || 0 == strcmp(argv[0], "/2")) {
+ fout = stdout;
+ argv++;
+ argc--;
+ }
+ else if(0 == strcmp(argv[0], "-o")) {
+ if(argc < 2) {
+ fprintf(stderr, usage);
+ return 1;
+ }
+ fout = fopen(argv[1], "w");
+ if(!fout) {
+ fprintf(stderr, "ERROR opening file %s for writing\n", argv[1]);
+ return 1;
+ }
+ argv += 2;
+ argc -= 2;
+ }
+ if(argc <= 0) {
+ fprintf(fout, "ERROR, no command!\n\n");
+ fprintf(fout, usage);
+ fclose(fout);
+ return 1;
+ }
+
+ // improvement: double-quote all args
+ int i, n = 0;
+ for(i = 0; i < argc; i++) {
+ if(i > 0)
+ n++;
+ n += strlen(argv[i]);
+ }
+ char *args = (char*)malloc(n+1);
+ if(!args) {
+ fprintf(fout, "ERROR, no memory\n");
+ fclose(fout);
+ return 1;
+ }
+ args[0] = '\0';
+ for(i = 0; i < argc; i++) {
+ if(i > 0)
+ safe_strncat(args, " ", sizeof(args));
+ safe_strncat(args, argv[i], sizeof(args));
+ }
+
+ //fprintf(stderr, "@@@ cmd=[%s] args=[%s]\n", argv[0], args);
+
+ STARTUPINFOA si;
+ GetStartupInfoA(&si);
+
+ DWORD wallclock_msec = GetTickCount();
+
+ PROCESS_INFORMATION pi;
+ BOOL ok = CreateProcessA(
+ argv[0], // lpApplicationName
+ args, // lpCommandLine
+ NULL, // lpProcessAttributes
+ NULL, // lpThreadAttributes
+ FALSE, // bInheritHandles
+ 0, // dwCreationFlags
+ NULL, // lpEnvironment
+ NULL, // lpCurrentDirectory
+ &si, // lpStartupInfo (inherit from this proc?)
+ &pi // lpProcessInformation
+ );
+
+ if(!ok) {
+ fprintf(fout, "ERROR running command\n");
+ free(args); //@@@ ok to free here or have to wait to wait till process is reaped?
+ fclose(fout);
+ return 1;
+ }
+
+ //fprintf(stderr, "@@@ waiting...\n");
+ WaitForSingleObject(pi.hProcess, INFINITE);
+ //fprintf(stderr, "@@@ done\n");
+
+ wallclock_msec = GetTickCount() - wallclock_msec;
+
+ FILETIME creation_time;
+ FILETIME exit_time;
+ FILETIME kernel_time;
+ FILETIME user_time;
+ if(!GetProcessTimes(pi.hProcess, &creation_time, &exit_time, &kernel_time, &user_time)) {
+ fprintf(fout, "ERROR getting time info\n");
+ free(args); //@@@ ok to free here or have to wait to wait till process is reaped?
+ fclose(fout);
+ return 1;
+ }
+ uint64_t kernel_nsec = time2nsec(kernel_time);
+ uint64_t user_nsec = time2nsec(user_time);
+
+ fprintf(fout, "Kernel Time = "); printtime(fout, kernel_nsec, (uint64_t)wallclock_msec * 1000000);
+ fprintf(fout, "User Time = "); printtime(fout, user_nsec, (uint64_t)wallclock_msec * 1000000);
+ fprintf(fout, "Process Time = "); printtime(fout, kernel_nsec+user_nsec, (uint64_t)wallclock_msec * 1000000);
+ fprintf(fout, "Global Time = "); printtime(fout, (uint64_t)wallclock_msec * 1000000, (uint64_t)wallclock_msec * 1000000);
+
+ CloseHandle(pi.hThread);
+ CloseHandle(pi.hProcess);
+
+ free(args); //@@@ always causes crash, maybe CreateProcess takes ownership?
+ fclose(fout);
+ return 0;
+}