diff options
author | 2023-12-06 17:05:32 +1100 | |
---|---|---|
committer | 2023-12-06 17:12:45 +1100 | |
commit | faf991a563a9bf8adc7aeee80001606d58857b99 (patch) | |
tree | 5eb75ca6182e9816f4ac501c124712cd8e5ee353 /3rdparty/libflac/src/flac | |
parent | 2cf244ef3b53129d711aa5b663fb38e9133726c0 (diff) |
3rdparty/libflac: Updated to version 1.4.3.
Also removed FLAC documentation - it's a lot of bloat.
Diffstat (limited to '3rdparty/libflac/src/flac')
26 files changed, 4246 insertions, 3778 deletions
diff --git a/3rdparty/libflac/src/flac/CMakeLists.txt b/3rdparty/libflac/src/flac/CMakeLists.txt new file mode 100644 index 00000000000..da7ce8de9c7 --- /dev/null +++ b/3rdparty/libflac/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/3rdparty/libflac/src/flac/Makefile.am b/3rdparty/libflac/src/flac/Makefile.am index 638cd74d413..279a7cb9b64 100644 --- a/3rdparty/libflac/src/flac/Makefile.am +++ b/3rdparty/libflac/src/flac/Makefile.am @@ -1,5 +1,6 @@ # flac - Command-line FLAC encoder/decoder -# Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson +# 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 @@ -11,22 +12,26 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# You 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 = \ - Makefile.lite \ - Makefile.lite.iffscan \ - flac.dsp \ - flac.vcproj \ + CMakeLists.txt \ iffscan.c \ - iffscan.dsp \ - iffscan.vcproj + version.rc flac_SOURCES = \ analyze.c \ @@ -46,13 +51,19 @@ flac_SOURCES = \ vorbiscomment.h flac_LDADD = \ + $(top_builddir)/src/share/utf8/libutf8.la \ $(top_builddir)/src/share/grabbag/libgrabbag.la \ - $(top_builddir)/src/share/getopt/libgetopt.a \ + $(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/share/utf8/libutf8.la \ $(top_builddir)/src/libFLAC/libFLAC.la \ - @OGG_LIBS@ \ - @LIBICONV@ \ - @MINGW_WINSOCK_LIBS@ \ + $(win_utf8_lib) \ + @LTLIBICONV@ \ -lm + +flac_LDFLAGS = $(AM_LDFLAGS) $(windows_resource_link) + +CLEANFILES = flac.exe + +.rc.o: + $(RC) $(AM_CPPFLAGS) $< $@ diff --git a/3rdparty/libflac/src/flac/Makefile.in b/3rdparty/libflac/src/flac/Makefile.in index b828c301a86..bc1d11eb9b9 100644 --- a/3rdparty/libflac/src/flac/Makefile.in +++ b/3rdparty/libflac/src/flac/Makefile.in @@ -1,8 +1,8 @@ -# Makefile.in generated by automake 1.7.9 from Makefile.am. +# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ -# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 -# Free Software Foundation, Inc. +# 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. @@ -15,7 +15,8 @@ @SET_MAKE@ # flac - Command-line FLAC encoder/decoder -# Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson +# 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 @@ -27,20 +28,71 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# You 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. -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ 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@ -pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ -top_builddir = ../.. - +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -INSTALL = @INSTALL@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c @@ -52,12 +104,128 @@ 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@ -ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ -AMDEP_FALSE = @AMDEP_FALSE@ -AMDEP_TRUE = @AMDEP_TRUE@ AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ @@ -66,172 +234,152 @@ 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@ -DEBUG_FALSE = @DEBUG_FALSE@ -DEBUG_TRUE = @DEBUG_TRUE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ -DOCBOOK_TO_MAN = @DOCBOOK_TO_MAN@ +DLLTOOL = @DLLTOOL@ DOXYGEN = @DOXYGEN@ -ECHO = @ECHO@ +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@ -F77 = @F77@ -FFLAGS = @FFLAGS@ +FGREP = @FGREP@ +FLAC__HAS_OGG = @FLAC__HAS_OGG@ FLAC__TEST_LEVEL = @FLAC__TEST_LEVEL@ FLAC__TEST_WITH_VALGRIND = @FLAC__TEST_WITH_VALGRIND@ -FLaC__CPU_IA32_FALSE = @FLaC__CPU_IA32_FALSE@ -FLaC__CPU_IA32_TRUE = @FLaC__CPU_IA32_TRUE@ -FLaC__CPU_PPC_FALSE = @FLaC__CPU_PPC_FALSE@ -FLaC__CPU_PPC_TRUE = @FLaC__CPU_PPC_TRUE@ -FLaC__CPU_SPARC_FALSE = @FLaC__CPU_SPARC_FALSE@ -FLaC__CPU_SPARC_TRUE = @FLaC__CPU_SPARC_TRUE@ -FLaC__HAS_AS_FALSE = @FLaC__HAS_AS_FALSE@ -FLaC__HAS_AS_TRUE = @FLaC__HAS_AS_TRUE@ -FLaC__HAS_AS__TEMPORARILY_DISABLED_FALSE = @FLaC__HAS_AS__TEMPORARILY_DISABLED_FALSE@ -FLaC__HAS_AS__TEMPORARILY_DISABLED_TRUE = @FLaC__HAS_AS__TEMPORARILY_DISABLED_TRUE@ -FLaC__HAS_DOCBOOK_TO_MAN_FALSE = @FLaC__HAS_DOCBOOK_TO_MAN_FALSE@ -FLaC__HAS_DOCBOOK_TO_MAN_TRUE = @FLaC__HAS_DOCBOOK_TO_MAN_TRUE@ -FLaC__HAS_DOXYGEN_FALSE = @FLaC__HAS_DOXYGEN_FALSE@ -FLaC__HAS_DOXYGEN_TRUE = @FLaC__HAS_DOXYGEN_TRUE@ -FLaC__HAS_GAS_FALSE = @FLaC__HAS_GAS_FALSE@ -FLaC__HAS_GAS_TRUE = @FLaC__HAS_GAS_TRUE@ -FLaC__HAS_GAS__TEMPORARILY_DISABLED_FALSE = @FLaC__HAS_GAS__TEMPORARILY_DISABLED_FALSE@ -FLaC__HAS_GAS__TEMPORARILY_DISABLED_TRUE = @FLaC__HAS_GAS__TEMPORARILY_DISABLED_TRUE@ -FLaC__HAS_NASM_FALSE = @FLaC__HAS_NASM_FALSE@ -FLaC__HAS_NASM_TRUE = @FLaC__HAS_NASM_TRUE@ -FLaC__HAS_OGG_FALSE = @FLaC__HAS_OGG_FALSE@ -FLaC__HAS_OGG_TRUE = @FLaC__HAS_OGG_TRUE@ -FLaC__HAS_XMMS_FALSE = @FLaC__HAS_XMMS_FALSE@ -FLaC__HAS_XMMS_TRUE = @FLaC__HAS_XMMS_TRUE@ -FLaC__INSTALL_XMMS_PLUGIN_LOCALLY_FALSE = @FLaC__INSTALL_XMMS_PLUGIN_LOCALLY_FALSE@ -FLaC__INSTALL_XMMS_PLUGIN_LOCALLY_TRUE = @FLaC__INSTALL_XMMS_PLUGIN_LOCALLY_TRUE@ -FLaC__NO_ASM_FALSE = @FLaC__NO_ASM_FALSE@ -FLaC__NO_ASM_TRUE = @FLaC__NO_ASM_TRUE@ -FLaC__SSE_OS_FALSE = @FLaC__SSE_OS_FALSE@ -FLaC__SSE_OS_TRUE = @FLaC__SSE_OS_TRUE@ -FLaC__SYS_DARWIN_FALSE = @FLaC__SYS_DARWIN_FALSE@ -FLaC__SYS_DARWIN_TRUE = @FLaC__SYS_DARWIN_TRUE@ -FLaC__SYS_LINUX_FALSE = @FLaC__SYS_LINUX_FALSE@ -FLaC__SYS_LINUX_TRUE = @FLaC__SYS_LINUX_TRUE@ -FLaC__USE_3DNOW_FALSE = @FLaC__USE_3DNOW_FALSE@ -FLaC__USE_3DNOW_TRUE = @FLaC__USE_3DNOW_TRUE@ -FLaC__USE_ALTIVEC_FALSE = @FLaC__USE_ALTIVEC_FALSE@ -FLaC__USE_ALTIVEC_TRUE = @FLaC__USE_ALTIVEC_TRUE@ -FLaC__WITH_CPPLIBS_FALSE = @FLaC__WITH_CPPLIBS_FALSE@ -FLaC__WITH_CPPLIBS_TRUE = @FLaC__WITH_CPPLIBS_TRUE@ -GAS = @GAS@ +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@ -MAINT = @MAINT@ -MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ -MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ -MINGW_WINSOCK_LIBS = @MINGW_WINSOCK_LIBS@ -NASM = @NASM@ +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@ -XMMS_CFLAGS = @XMMS_CFLAGS@ -XMMS_CONFIG = @XMMS_CONFIG@ -XMMS_DATA_DIR = @XMMS_DATA_DIR@ -XMMS_EFFECT_PLUGIN_DIR = @XMMS_EFFECT_PLUGIN_DIR@ -XMMS_GENERAL_PLUGIN_DIR = @XMMS_GENERAL_PLUGIN_DIR@ -XMMS_INPUT_PLUGIN_DIR = @XMMS_INPUT_PLUGIN_DIR@ -XMMS_LIBS = @XMMS_LIBS@ -XMMS_OUTPUT_PLUGIN_DIR = @XMMS_OUTPUT_PLUGIN_DIR@ -XMMS_PLUGIN_DIR = @XMMS_PLUGIN_DIR@ -XMMS_VERSION = @XMMS_VERSION@ -XMMS_VISUALIZATION_PLUGIN_DIR = @XMMS_VISUALIZATION_PLUGIN_DIR@ +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_F77 = @ac_ct_F77@ -ac_ct_RANLIB = @ac_ct_RANLIB@ -ac_ct_STRIP = @ac_ct_STRIP@ -am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ -am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ -am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ -am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +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@ - -bin_PROGRAMS = flac - +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 = \ - Makefile.lite \ - Makefile.lite.iffscan \ - flac.dsp \ - flac.vcproj \ + CMakeLists.txt \ iffscan.c \ - iffscan.dsp \ - iffscan.vcproj - + version.rc flac_SOURCES = \ analyze.c \ @@ -250,149 +398,150 @@ flac_SOURCES = \ 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.a \ + $(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/share/utf8/libutf8.la \ $(top_builddir)/src/libFLAC/libFLAC.la \ - @OGG_LIBS@ \ - @LIBICONV@ \ - @MINGW_WINSOCK_LIBS@ \ + $(win_utf8_lib) \ + @LTLIBICONV@ \ -lm -subdir = src/flac -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs -CONFIG_HEADER = $(top_builddir)/config.h -CONFIG_CLEAN_FILES = -bin_PROGRAMS = flac$(EXEEXT) -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) -flac_DEPENDENCIES = $(top_builddir)/src/share/grabbag/libgrabbag.la \ - $(top_builddir)/src/share/getopt/libgetopt.a \ - $(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \ - $(top_builddir)/src/share/replaygain_synthesis/libreplaygain_synthesis.la \ - $(top_builddir)/src/share/utf8/libutf8.la \ - $(top_builddir)/src/libFLAC/libFLAC.la -flac_LDFLAGS = - -DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -depcomp = $(SHELL) $(top_srcdir)/depcomp -am__depfiles_maybe = depfiles -@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/analyze.Po ./$(DEPDIR)/decode.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/encode.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/foreign_metadata.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/local_string_utils.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/main.Po ./$(DEPDIR)/utils.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/vorbiscomment.Po -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) \ - $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -CCLD = $(CC) -LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(AM_LDFLAGS) $(LDFLAGS) -o $@ -DIST_SOURCES = $(flac_SOURCES) -DIST_COMMON = $(srcdir)/Makefile.in Makefile.am -SOURCES = $(flac_SOURCES) - +flac_LDFLAGS = $(AM_LDFLAGS) $(windows_resource_link) +CLEANFILES = flac.exe all: all-am .SUFFIXES: -.SUFFIXES: .c .lo .o .obj -$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) - cd $(top_srcdir) && \ - $(AUTOMAKE) --gnu src/flac/Makefile -Makefile: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.in $(top_builddir)/config.status - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) -binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +.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) - $(mkinstalldirs) $(DESTDIR)$(bindir) - @list='$(bin_PROGRAMS)'; for p in $$list; do \ - p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ - if test -f $$p \ - || test -f $$p1 \ - ; then \ - f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ - echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f"; \ - $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f || exit 1; \ - else :; fi; \ - done + @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)'; for p in $$list; do \ - f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ - echo " rm -f $(DESTDIR)$(bindir)/$$f"; \ - rm -f $(DESTDIR)$(bindir)/$$f; \ - done + @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)'; for p in $$list; do \ - f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ - echo " rm -f $$p $$f"; \ - rm -f $$p $$f ; \ - done -flac$(EXEEXT): $(flac_OBJECTS) $(flac_DEPENDENCIES) + @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) - $(LINK) $(flac_LDFLAGS) $(flac_OBJECTS) $(flac_LDADD) $(LIBS) + $(AM_V_CCLD)$(flac_LINK) $(flac_OBJECTS) $(flac_LDADD) $(LIBS) mostlyclean-compile: - -rm -f *.$(OBJEXT) core *.core + -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/analyze.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decode.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/encode.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/foreign_metadata.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/local_string_utils.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vorbiscomment.Po@am__quote@ +@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@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ -@am__fastdepCC_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ -@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ -@am__fastdepCC_TRUE@ fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$< +@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@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ -@am__fastdepCC_TRUE@ -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ -@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ -@am__fastdepCC_TRUE@ fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` +@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@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ -@am__fastdepCC_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; \ -@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ -@am__fastdepCC_TRUE@ fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< +@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 @@ -400,101 +549,97 @@ mostlyclean-libtool: clean-libtool: -rm -rf .libs _libs -distclean-libtool: - -rm -f libtool -uninstall-info-am: - -ETAGS = etags -ETAGSFLAGS = - -CTAGS = ctags -CTAGSFLAGS = - -tags: TAGS +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags -ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - mkid -fID $$unique - -TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - tags=; \ - here=`pwd`; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - test -z "$(ETAGS_ARGS)$$tags$$unique" \ - || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$tags $$unique - -ctags: CTAGS -CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - tags=; \ +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ here=`pwd`; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - test -z "$(CTAGS_ARGS)$$tags$$unique" \ + $(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) \ - $$tags $$unique + $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ - && cd $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) $$here + && $(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 -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) - -top_distdir = ../.. -distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) - -distdir: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ - list='$(DISTFILES)'; for file in $$list; do \ - case $$file in \ - $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ - $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ - esac; \ +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; \ - dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test "$$dir" != "$$file" && test "$$dir" != "."; then \ - dir="/$$dir"; \ - $(mkinstalldirs) "$(distdir)$$dir"; \ - else \ - dir=''; \ - 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 -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ - cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ - test -f $(distdir)/$$file \ - || cp -p $$d/$$file $(distdir)/$$file \ + 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: - $(mkinstalldirs) $(DESTDIR)$(bindir) + 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 @@ -505,16 +650,23 @@ install-am: all-am installcheck: installcheck-am install-strip: - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - `test -z '$(STRIP)' || \ - echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install + 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: - -rm -f $(CONFIG_CLEAN_FILES) + -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" @@ -524,31 +676,67 @@ clean: clean-am clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am distclean: distclean-am - -rm -rf ./$(DEPDIR) + -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-libtool distclean-tags + 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 -rf ./$(DEPDIR) + -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 @@ -565,19 +753,29 @@ ps: ps-am ps-am: -uninstall-am: uninstall-binPROGRAMS uninstall-info-am +uninstall-am: uninstall-binPROGRAMS + +.MAKE: install-am install-strip -.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ - clean-generic clean-libtool ctags distclean distclean-compile \ - distclean-generic distclean-libtool distclean-tags distdir dvi \ - dvi-am info info-am install install-am install-binPROGRAMS \ - install-data install-data-am install-exec install-exec-am \ - install-info install-info-am install-man 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 uninstall uninstall-am uninstall-binPROGRAMS \ - uninstall-info-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. diff --git a/3rdparty/libflac/src/flac/Makefile.lite b/3rdparty/libflac/src/flac/Makefile.lite deleted file mode 100644 index 9e8a0cc90a4..00000000000 --- a/3rdparty/libflac/src/flac/Makefile.lite +++ /dev/null @@ -1,47 +0,0 @@ -# flac - Command-line FLAC encoder/decoder -# Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -# -# GNU makefile -# - -topdir = ../.. -libdir = $(topdir)/obj/$(BUILD)/lib - -PROGRAM_NAME = flac - -INCLUDES = -I./include -I$(topdir)/include -I$(OGG_INCLUDE_DIR) - -ifeq ($(DARWIN_BUILD),yes) -EXPLICIT_LIBS = $(libdir)/libgrabbag.a $(libdir)/libFLAC.a $(libdir)/libreplaygain_analysis.a $(libdir)/libreplaygain_synthesis.a $(libdir)/libgetopt.a $(libdir)/libutf8.a $(OGG_LIB_DIR)/libogg.a -liconv -lm -else -LIBS = -lgrabbag -lFLAC -lreplaygain_analysis -lreplaygain_synthesis -lgetopt -lutf8 -L$(OGG_LIB_DIR) -logg -lm -endif - -SRCS_C = \ - analyze.c \ - decode.c \ - encode.c \ - foreign_metadata.c \ - local_string_utils.c \ - main.c \ - utils.c \ - vorbiscomment.c - -include $(topdir)/build/exe.mk - -# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/3rdparty/libflac/src/flac/Makefile.lite.iffscan b/3rdparty/libflac/src/flac/Makefile.lite.iffscan deleted file mode 100644 index b12bb10a60e..00000000000 --- a/3rdparty/libflac/src/flac/Makefile.lite.iffscan +++ /dev/null @@ -1,41 +0,0 @@ -# flac - Command-line FLAC encoder/decoder -# Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -# -# GNU makefile -# - -topdir = ../.. -libdir = $(topdir)/obj/$(BUILD)/lib - -PROGRAM_NAME = iffscan - -INCLUDES = -I./include -I$(topdir)/include -I$(OGG_INCLUDE_DIR) - -ifeq ($(DARWIN_BUILD),yes) -EXPLICIT_LIBS = $(libdir)/libFLAC.a $(OGG_LIB_DIR)/libogg.a -liconv -lm -else -LIBS = -lFLAC -L$(OGG_LIB_DIR) -logg -lm -endif - -SRCS_C = \ - foreign_metadata.c \ - iffscan.c - -include $(topdir)/build/exe.mk - -# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/3rdparty/libflac/src/flac/analyze.c b/3rdparty/libflac/src/flac/analyze.c index 47a5e76d7a9..0a85565e89b 100644 --- a/3rdparty/libflac/src/flac/analyze.c +++ b/3rdparty/libflac/src/flac/analyze.c @@ -1,5 +1,6 @@ /* flac - Command-line FLAC encoder/decoder - * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson + * 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 @@ -11,12 +12,12 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * You 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 HAVE_CONFIG_H +#ifdef HAVE_CONFIG_H # include <config.h> #endif @@ -25,19 +26,22 @@ #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; - unsigned count; + uint32_t count; } pair_t; typedef struct { pair_t buckets[FLAC__MAX_BLOCK_SIZE]; int peak_index; - unsigned nbuckets; - unsigned nsamples; + uint32_t nbuckets; + uint32_t nsamples; double sum, sos; double variance; double mean; @@ -47,7 +51,7 @@ typedef struct { static subframe_stats_t all_; static void init_stats(subframe_stats_t *stats); -static void update_stats(subframe_stats_t *stats, FLAC__int32 residual, unsigned incr); +static void 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); @@ -58,36 +62,32 @@ void flac__analyze_init(analysis_options aopts) } } -void flac__analyze_frame(const FLAC__Frame *frame, unsigned frame_number, FLAC__uint64 frame_offset, unsigned frame_bytes, analysis_options aopts, FILE *fout) +void flac__analyze_frame(const FLAC__Frame *frame, uint32_t frame_number, FLAC__uint64 frame_offset, FLAC__uint64 frame_bytes, analysis_options aopts, FILE *fout) { - const unsigned channels = frame->header.channels; + const uint32_t channels = frame->header.channels; char outfilename[1024]; subframe_stats_t stats; - unsigned i, channel, partitions; + uint32_t i, channel, partitions; /* do the human-readable part first */ -#ifdef _MSC_VER - fprintf(fout, "frame=%u\toffset=%I64u\tbits=%u\tblocksize=%u\tsample_rate=%u\tchannels=%u\tchannel_assignment=%s\n", frame_number, frame_offset, frame_bytes*8, frame->header.blocksize, frame->header.sample_rate, channels, FLAC__ChannelAssignmentString[frame->header.channel_assignment]); -#else - fprintf(fout, "frame=%u\toffset=%llu\tbits=%u\tblocksize=%u\tsample_rate=%u\tchannels=%u\tchannel_assignment=%s\n", frame_number, (unsigned long long)frame_offset, frame_bytes*8, frame->header.blocksize, frame->header.sample_rate, channels, FLAC__ChannelAssignmentString[frame->header.channel_assignment]); -#endif + 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 unsigned pesc = is_rice2? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER; + 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=%d\n", subframe->data.constant.value); + 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]=%d\n", i, subframe->data.fixed.warmup[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++) { - unsigned parameter = subframe->data.fixed.entropy_coding_method.data.partitioned_rice.contents->parameters[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 @@ -104,10 +104,10 @@ void flac__analyze_frame(const FLAC__Frame *frame, unsigned frame_number, FLAC__ for(i = 0; i < subframe->data.lpc.order; i++) fprintf(fout, "\t\tqlp_coeff[%u]=%d\n", i, subframe->data.lpc.qlp_coeff[i]); for(i = 0; i < subframe->data.lpc.order; i++) - fprintf(fout, "\t\twarmup[%u]=%d\n", i, subframe->data.lpc.warmup[i]); + 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++) { - unsigned parameter = subframe->data.lpc.entropy_coding_method.data.partitioned_rice.contents->parameters[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 @@ -128,7 +128,7 @@ void flac__analyze_frame(const FLAC__Frame *frame, unsigned frame_number, FLAC__ if(aopts.do_residual_gnuplot) { for(channel = 0; channel < channels; channel++) { const FLAC__Subframe *subframe = frame->subframes+channel; - unsigned residual_samples; + uint32_t residual_samples; init_stats(&stats); @@ -152,18 +152,20 @@ void flac__analyze_frame(const FLAC__Frame *frame, unsigned frame_number, FLAC__ update_stats(&all_, stats.buckets[i].residual, stats.buckets[i].count); } - /* write the subframe */ - sprintf(outfilename, "f%06u.s%u.gp", frame_number, channel); - compute_stats(&stats); + 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)dump_stats(&stats, outfilename); + } } } } void flac__analyze_finish(analysis_options aopts) { - if(aopts.do_residual_gnuplot) { + if(aopts.do_residual_gnuplot && all_.nsamples > 0) { compute_stats(&all_); (void)dump_stats(&all_, "all"); } @@ -178,9 +180,9 @@ void init_stats(subframe_stats_t *stats) stats->sos = 0.0; } -void update_stats(subframe_stats_t *stats, FLAC__int32 residual, unsigned incr) +void update_stats(subframe_stats_t *stats, FLAC__int32 residual, uint32_t incr) { - unsigned i; + uint32_t i; const double r = (double)residual, a = r*incr; stats->nsamples += incr; @@ -213,12 +215,12 @@ void compute_stats(subframe_stats_t *stats) FLAC__bool dump_stats(const subframe_stats_t *stats, const char *filename) { FILE *outfile; - unsigned i; + 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 = fopen(filename, "w"); + outfile = flac_fopen(filename, "w"); if(0 == outfile) { fprintf(stderr, "ERROR opening %s: %s\n", filename, strerror(errno)); @@ -243,5 +245,8 @@ FLAC__bool dump_stats(const subframe_stats_t *stats, const char *filename) fprintf(outfile, "pause -1 'waiting...'\n"); fclose(outfile); +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + unlink(filename); +#endif return true; } diff --git a/3rdparty/libflac/src/flac/analyze.h b/3rdparty/libflac/src/flac/analyze.h index b58b6b875ff..ce07b145ec8 100644 --- a/3rdparty/libflac/src/flac/analyze.h +++ b/3rdparty/libflac/src/flac/analyze.h @@ -1,5 +1,6 @@ /* flac - Command-line FLAC encoder/decoder - * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson + * 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 @@ -11,9 +12,9 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * You 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 @@ -25,7 +26,7 @@ typedef struct { } analysis_options; void flac__analyze_init(analysis_options aopts); -void flac__analyze_frame(const FLAC__Frame *frame, unsigned frame_number, FLAC__uint64 frame_offset, unsigned frame_bytes, analysis_options aopts, FILE *fout); +void flac__analyze_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/3rdparty/libflac/src/flac/decode.c b/3rdparty/libflac/src/flac/decode.c index 1e537c064e2..90f7a6c8607 100644 --- a/3rdparty/libflac/src/flac/decode.c +++ b/3rdparty/libflac/src/flac/decode.c @@ -1,5 +1,6 @@ /* flac - Command-line FLAC encoder/decoder - * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson + * 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 @@ -11,35 +12,24 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * You 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 HAVE_CONFIG_H +#ifdef HAVE_CONFIG_H # include <config.h> #endif -#if defined _WIN32 && !defined __CYGWIN__ -/* where MSVC puts unlink() */ -# include <io.h> -#else -# include <unistd.h> -#endif -#if defined _MSC_VER || defined __MINGW32__ -#include <sys/types.h> /* for off_t */ -#if _MSC_VER <= 1600 /* @@@ [2G limit] */ -#define fseeko fseek -#define ftello ftell -#endif -#endif #include <errno.h> #include <math.h> /* for floor() */ #include <stdio.h> /* for FILE etc. */ #include <string.h> /* for strcmp(), strerror() */ +#include <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 { @@ -49,11 +39,12 @@ typedef struct { long serial_number; #endif - FLAC__bool is_aiff_out; - FLAC__bool is_wave_out; + 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; @@ -74,10 +65,12 @@ typedef struct { const char *outfilename; FLAC__uint64 samples_processed; - unsigned frame_counter; + 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; @@ -86,9 +79,9 @@ typedef struct { FLAC__bool got_stream_info; FLAC__bool has_md5sum; FLAC__uint64 total_samples; - unsigned bps; - unsigned channels; - unsigned sample_rate; + uint32_t bps; + uint32_t channels; + uint32_t sample_rate; FLAC__uint32 channel_mask; /* these are used only in analyze mode */ @@ -99,7 +92,9 @@ typedef struct { FILE *fout; foreign_metadata_t *foreign_metadata; /* NULL unless --keep-foreign-metadata requested */ - off_t fm_offset1, fm_offset2, fm_offset3; + FLAC__off_t fm_offset1, fm_offset2, fm_offset3; + + clock_t old_clock_t; } DecoderSession; @@ -109,21 +104,22 @@ static FLAC__bool is_big_endian_host_; /* * local routines */ -static FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool is_ogg, FLAC__bool use_first_serial_number, long serial_number, FLAC__bool is_aiff_out, FLAC__bool is_wave_out, FLAC__bool treat_warnings_as_errors, FLAC__bool continue_through_decode_errors, FLAC__bool channel_map_none, replaygain_synthesis_spec_t replaygain_synthesis_spec, FLAC__bool analysis_mode, analysis_options aopts, utils__SkipUntilSpecification *skip_specification, utils__SkipUntilSpecification *until_specification, utils__CueSpecification *cue_specification, foreign_metadata_t *foreign_metadata, const char *infilename, const char *outfilename); +static 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, unsigned sample_rate, FLAC__uint64 skip, FLAC__uint64 total_samples_in_input); +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(FILE *f, FLAC__bool is_waveformatextensible, unsigned bps, unsigned channels, unsigned sample_rate, FLAC__uint32 channel_mask); -static FLAC__bool write_aiff_form_comm_chunk(FILE *f, FLAC__uint64 samples, unsigned bps, unsigned channels, unsigned sample_rate); +static FLAC__bool write_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, unsigned 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); @@ -136,129 +132,56 @@ static void print_stats(const DecoderSession *decoder_session); /* * public routines */ -int flac__decode_aiff(const char *infilename, const char *outfilename, FLAC__bool analysis_mode, analysis_options aopts, wav_decode_options_t options) +int flac__decode_file(const char *infilename, const char *outfilename, FLAC__bool analysis_mode, analysis_options aopts, decode_options_t options) { DecoderSession decoder_session; - if(! - DecoderSession_construct( - &decoder_session, -#if FLAC__HAS_OGG - options.common.is_ogg, - options.common.use_first_serial_number, - options.common.serial_number, -#else - /*is_ogg=*/false, - /*use_first_serial_number=*/false, - /*serial_number=*/0, -#endif - /*is_aiff_out=*/true, - /*is_wave_out=*/false, - options.common.treat_warnings_as_errors, - options.common.continue_through_decode_errors, - options.common.channel_map_none, - options.common.replaygain_synthesis_spec, - analysis_mode, - aopts, - &options.common.skip_specification, - &options.common.until_specification, - options.common.has_cue_specification? &options.common.cue_specification : 0, - options.foreign_metadata, - infilename, - outfilename - ) - ) - return 1; - - if(!DecoderSession_init_decoder(&decoder_session, infilename)) - return DecoderSession_finish_error(&decoder_session); - - if(!DecoderSession_process(&decoder_session)) - return DecoderSession_finish_error(&decoder_session); - - return DecoderSession_finish_ok(&decoder_session); -} - -int flac__decode_wav(const char *infilename, const char *outfilename, FLAC__bool analysis_mode, analysis_options aopts, wav_decode_options_t options) -{ - DecoderSession decoder_session; - - if(! - DecoderSession_construct( - &decoder_session, -#if FLAC__HAS_OGG - options.common.is_ogg, - options.common.use_first_serial_number, - options.common.serial_number, -#else - /*is_ogg=*/false, - /*use_first_serial_number=*/false, - /*serial_number=*/0, -#endif - /*is_aiff_out=*/false, - /*is_wave_out=*/true, - options.common.treat_warnings_as_errors, - options.common.continue_through_decode_errors, - options.common.channel_map_none, - options.common.replaygain_synthesis_spec, - analysis_mode, - aopts, - &options.common.skip_specification, - &options.common.until_specification, - options.common.has_cue_specification? &options.common.cue_specification : 0, - options.foreign_metadata, - infilename, - outfilename - ) - ) - return 1; - - if(!DecoderSession_init_decoder(&decoder_session, infilename)) - return DecoderSession_finish_error(&decoder_session); - - if(!DecoderSession_process(&decoder_session)) - return DecoderSession_finish_error(&decoder_session); - - return DecoderSession_finish_ok(&decoder_session); -} - -int flac__decode_raw(const char *infilename, const char *outfilename, FLAC__bool analysis_mode, analysis_options aopts, raw_decode_options_t options) -{ - DecoderSession decoder_session; - - decoder_session.is_big_endian = options.is_big_endian; - decoder_session.is_unsigned_samples = options.is_unsigned_samples; + 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.common.is_ogg, - options.common.use_first_serial_number, - options.common.serial_number, + options.is_ogg, + options.use_first_serial_number, + options.serial_number, #else /*is_ogg=*/false, /*use_first_serial_number=*/false, /*serial_number=*/0, #endif - /*is_aiff_out=*/false, - /*is_wave_out=*/false, - options.common.treat_warnings_as_errors, - options.common.continue_through_decode_errors, - options.common.channel_map_none, - options.common.replaygain_synthesis_spec, + 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.common.skip_specification, - &options.common.until_specification, - options.common.has_cue_specification? &options.common.cue_specification : 0, - /*foreign_metadata=*/NULL, + &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); @@ -268,7 +191,7 @@ int flac__decode_raw(const char *infilename, const char *outfilename, FLAC__bool return DecoderSession_finish_ok(&decoder_session); } -FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool is_ogg, FLAC__bool use_first_serial_number, long serial_number, FLAC__bool is_aiff_out, FLAC__bool is_wave_out, FLAC__bool treat_warnings_as_errors, FLAC__bool continue_through_decode_errors, FLAC__bool channel_map_none, replaygain_synthesis_spec_t replaygain_synthesis_spec, FLAC__bool analysis_mode, analysis_options aopts, utils__SkipUntilSpecification *skip_specification, utils__SkipUntilSpecification *until_specification, utils__CueSpecification *cue_specification, foreign_metadata_t *foreign_metadata, const char *infilename, const char *outfilename) +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; @@ -280,11 +203,12 @@ FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool is_ogg, FLAC__ (void)serial_number; #endif - d->is_aiff_out = is_aiff_out; - d->is_wave_out = is_wave_out; + 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; @@ -305,6 +229,11 @@ FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool is_ogg, FLAC__ 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; @@ -313,7 +242,7 @@ FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool is_ogg, FLAC__ d->has_md5sum = false; d->bps = 0; d->channels = 0; - d->sample_rate = 0; + d->sample_rate = UINT32_MAX; d->channel_mask = 0; d->decode_position = 0; @@ -324,6 +253,8 @@ FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool is_ogg, FLAC__ d->foreign_metadata = foreign_metadata; + d->old_clock_t = 0; + FLAC__ASSERT(!(d->test_only && d->analysis_mode)); if(!d->test_only) { @@ -331,7 +262,7 @@ FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool is_ogg, FLAC__ d->fout = grabbag__file_get_binary_stdout(); } else { - if(0 == (d->fout = fopen(outfilename, "wb"))) { + 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; @@ -348,9 +279,30 @@ FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool is_ogg, FLAC__ 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) - unlink(d->outfilename); +#endif + flac_unlink(d->outfilename); } } @@ -361,14 +313,30 @@ FLAC__bool DecoderSession_init_decoder(DecoderSession *decoder_session, const ch is_big_endian_host_ = (*((FLAC__byte*)(&test)))? false : true; - if(!decoder_session->analysis_mode && !decoder_session->test_only && (decoder_session->is_wave_out || decoder_session->is_aiff_out)) { - if(decoder_session->foreign_metadata) { - const char *error; - if(!flac__foreign_metadata_read_from_flac(decoder_session->foreign_metadata, infilename, &error)) { - flac__utils_printf(stderr, 1, "%s: ERROR reading foreign metadata: %s\n", decoder_session->inbasefilename, error); + 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(); @@ -381,9 +349,16 @@ FLAC__bool DecoderSession_init_decoder(DecoderSession *decoder_session, const ch 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) + 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) @@ -418,41 +393,70 @@ FLAC__bool DecoderSession_process(DecoderSession *d) 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 */ - if(!d->channel_map_none) { - /* currently FLAC order matches SMPTE/WAVEFORMATEXTENSIBLE order, so no reordering is necessary; see encode.c */ - /* only the channel mask must be set if it was not already picked up from the WAVEFORMATEXTENSIBLE_CHANNEL_MASK tag */ + /* 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) { - if(d->channel_mask == 0) - d->channel_mask = 0x0001; + d->channel_mask = 0x0004; } else if(d->channels == 2) { - if(d->channel_mask == 0) - d->channel_mask = 0x0003; + d->channel_mask = 0x0003; } else if(d->channels == 3) { - if(d->channel_mask == 0) - d->channel_mask = 0x0007; + d->channel_mask = 0x0007; } else if(d->channels == 4) { - if(d->channel_mask == 0) - d->channel_mask = 0x0033; + d->channel_mask = 0x0033; } else if(d->channels == 5) { - if(d->channel_mask == 0) - d->channel_mask = 0x0607; + d->channel_mask = 0x0607; } else if(d->channels == 6) { - if(d->channel_mask == 0) - d->channel_mask = 0x060f; + 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->is_wave_out || d->is_aiff_out)) { + 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; @@ -482,13 +486,28 @@ FLAC__bool DecoderSession_process(DecoderSession *d) return false; } - if(!d->analysis_mode && !d->test_only && (d->is_wave_out || d->is_aiff_out) && ((d->total_samples * d->channels * ((d->bps+7)/8)) & 1)) { - if(flac__utils_fwrite("\000", 1, 1, d->fout) != 1) { - print_error_with_state(d, d->is_wave_out? - "ERROR writing pad byte to WAVE data chunk" : - "ERROR writing pad byte to AIFF SSND chunk" - ); - return false; + /* 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; + } } } @@ -507,22 +526,36 @@ int DecoderSession_finish_ok(DecoderSession *d) if(d->analysis_mode) flac__analyze_finish(d->aopts); if(md5_failure) { - flac__utils_printf(stderr, 1, "\r%s: ERROR, MD5 signature mismatch\n", d->inbasefilename); + 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) { - flac__utils_printf(stderr, 1, "\r%s: WARNING, cannot check MD5 signature since there was no STREAMINFO\n", d->inbasefilename); + 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) { - flac__utils_printf(stderr, 1, "\r%s: WARNING, cannot check MD5 signature since it was unset in the STREAMINFO\n", d->inbasefilename); + 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; } - flac__utils_printf(stderr, 2, "\r%s: %s \n", d->inbasefilename, d->test_only? "ok ":d->analysis_mode?"done ":"done"); + 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->is_wave_out || d->is_aiff_out)) { + 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; @@ -533,6 +566,10 @@ int DecoderSession_finish_ok(DecoderSession *d) 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; @@ -550,10 +587,13 @@ int DecoderSession_finish_error(DecoderSession *d) return 1; } -FLAC__bool canonicalize_until_specification(utils__SkipUntilSpecification *spec, const char *inbasefilename, unsigned sample_rate, FLAC__uint64 skip, FLAC__uint64 total_samples_in_input) +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 */ - flac__utils_canonicalize_skip_until_specification(spec, sample_rate); + 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) { @@ -597,15 +637,42 @@ FLAC__bool canonicalize_until_specification(utils__SkipUntilSpecification *spec, FLAC__bool write_iff_headers(FILE *f, DecoderSession *decoder_session, FLAC__uint64 samples) { - const char *fmt_desc = decoder_session->is_wave_out? "WAVE" : "AIFF"; - const FLAC__bool is_waveformatextensible = decoder_session->is_wave_out && (decoder_session->channel_mask == 2 || decoder_session->channel_mask > 3 || decoder_session->bps%8 || decoder_session->channels > 2); - FLAC__uint64 data_size = samples * decoder_session->channels * ((decoder_session->bps+7)/8); - const FLAC__uint32 aligned_data_size = (FLAC__uint32)((data_size+1) & (~1U)); /* we'll check for overflow later */ - - unsigned foreign_metadata_size = 0; /* size of all non-audio non-fmt/COMM foreign metadata chunks */ + 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); @@ -623,33 +690,96 @@ FLAC__bool write_iff_headers(FILE *f, DecoderSession *decoder_session, FLAC__uin FLAC__ASSERT(fm->format_block); FLAC__ASSERT(fm->audio_block); FLAC__ASSERT(fm->format_block < fm->audio_block); - /* calc foreign metadata size; for RIFF/AIFF we always skip the first chunk, format chunk, and sound chunk since we write our own */ - for(i = 1; i < fm->num_blocks; i++) { + /* 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(data_size + foreign_metadata_size + 60/*worst-case*/ >= 0xFFFFFFF4) { + 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(decoder_session->is_wave_out) { - if(flac__utils_fwrite("RIFF", 1, 4, f) != 4) - 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; + } - if(!write_little_endian_uint32(f, foreign_metadata_size + aligned_data_size + (is_waveformatextensible?60:36))) /* filesize-8 */ - return false; + /* ds64 chunk for RF64 */ + if(format == FORMAT_RF64) { + if(flac__utils_fwrite("ds64", 1, 4, f) != 4) + return false; - if(flac__utils_fwrite("WAVE", 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 = 1; i < fm->format_block; i++) { + 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; @@ -657,7 +787,22 @@ FLAC__bool write_iff_headers(FILE *f, DecoderSession *decoder_session, FLAC__uin } } - if(!write_riff_wave_fmt_chunk(f, is_waveformatextensible, decoder_session->bps, decoder_session->channels, decoder_session->sample_rate, decoder_session->channel_mask)) + 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); @@ -672,25 +817,37 @@ FLAC__bool write_iff_headers(FILE *f, DecoderSession *decoder_session, FLAC__uin } } - if(flac__utils_fwrite("data", 1, 4, f) != 4) - return false; - - if(!write_little_endian_uint32(f, (FLAC__uint32)data_size)) /* data size */ - return false; + 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 { - FLAC__uint32 ssnd_offset_size = (fm? fm->ssnd_offset_size : 0); - if(flac__utils_fwrite("FORM", 1, 4, f) != 4) return false; - if(!write_big_endian_uint32(f, foreign_metadata_size + aligned_data_size + 46 + ssnd_offset_size)) /* filesize-8 */ + if(!write_big_endian_uint32(f, (FLAC__uint32)iff_size)) /* filesize-8 */ return false; - if(flac__utils_fwrite("AIFF", 1, 4, f) != 4) - 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); @@ -704,7 +861,7 @@ FLAC__bool write_iff_headers(FILE *f, DecoderSession *decoder_session, FLAC__uin } } - if(!write_aiff_form_comm_chunk(f, samples, decoder_session->bps, decoder_session->channels, decoder_session->sample_rate)) + 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); @@ -722,37 +879,23 @@ FLAC__bool write_iff_headers(FILE *f, DecoderSession *decoder_session, FLAC__uin if(flac__utils_fwrite("SSND", 1, 4, f) != 4) return false; - if(!write_big_endian_uint32(f, (FLAC__uint32)data_size + 8 + ssnd_offset_size)) /* data size */ + if(!write_big_endian_uint32(f, (FLAC__uint32)data_size + 8)) /* data size */ return false; - if(!write_big_endian_uint32(f, ssnd_offset_size)) + if(!write_big_endian_uint32(f, 0/*offset_size*/)) return false; if(!write_big_endian_uint32(f, 0/*block_size*/)) return false; - if(ssnd_offset_size) { - /* seek forward to {allocate} or {skip over already-written} SSND offset */ - if(fseeko(f, ssnd_offset_size, SEEK_CUR) < 0) { - flac__utils_printf(stderr, 1, "%s: ERROR: allocating/skipping \"SSND\" offset\n", decoder_session->inbasefilename); - return false; - } - } - decoder_session->fm_offset3 = ftello(f) + aligned_data_size; } return true; } -FLAC__bool write_riff_wave_fmt_chunk(FILE *f, FLAC__bool is_waveformatextensible, unsigned bps, unsigned channels, unsigned sample_rate, FLAC__uint32 channel_mask) +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(flac__utils_fwrite("fmt ", 1, 4, f) != 4) - return false; - - if(!write_little_endian_uint32(f, is_waveformatextensible? 40 : 16)) /* chunk size */ - return false; - if(!write_little_endian_uint16(f, (FLAC__uint16)(is_waveformatextensible? 65534 : 1))) /* compression code */ return false; @@ -789,14 +932,22 @@ FLAC__bool write_riff_wave_fmt_chunk(FILE *f, FLAC__bool is_waveformatextensible return true; } -FLAC__bool write_aiff_form_comm_chunk(FILE *f, FLAC__uint64 samples, unsigned bps, unsigned channels, unsigned sample_rate) +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, 18)) /* chunk size = 18 */ + if(!write_big_endian_uint32(f, comm_length-12)) /* chunk size = 18 */ return false; if(!write_big_endian_uint16(f, (FLAC__uint16)channels)) @@ -811,6 +962,23 @@ FLAC__bool write_aiff_form_comm_chunk(FILE *f, FLAC__uint64 samples, unsigned bp 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; } @@ -835,6 +1003,19 @@ FLAC__bool write_little_endian_uint32(FILE *f, FLAC__uint32 val) 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); @@ -856,7 +1037,7 @@ FLAC__bool write_big_endian_uint32(FILE *f, FLAC__uint32 val) return flac__utils_fwrite(b, 1, 4, f) == 4; } -FLAC__bool write_sane_extended(FILE *f, unsigned val) +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. * @@ -864,13 +1045,19 @@ FLAC__bool write_sane_extended(FILE *f, unsigned val) * 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; + uint32_t shift, exponent; - FLAC__ASSERT(val!=0U); /* handling 0 would require a special case */ + 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) ; @@ -889,8 +1076,12 @@ FLAC__bool write_sane_extended(FILE *f, unsigned val) FLAC__bool fixup_iff_headers(DecoderSession *d) { - const char *fmt_desc = (d->is_wave_out? "WAVE" : "AIFF"); - FILE *f = fopen(d->outfilename, "r+b"); /* stream is positioned at beginning of file */ + 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)); @@ -910,18 +1101,31 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder { DecoderSession *decoder_session = (DecoderSession*)client_data; FILE *fout = decoder_session->fout; - const unsigned bps = frame->header.bits_per_sample, channels = frame->header.channels; - const unsigned shift = ((decoder_session->is_wave_out || decoder_session->is_aiff_out) && (bps%8)? 8-(bps%8): 0); - FLAC__bool is_big_endian = (decoder_session->is_aiff_out? true : (decoder_session->is_wave_out? false : decoder_session->is_big_endian)); - FLAC__bool is_unsigned_samples = (decoder_session->is_aiff_out? false : (decoder_session->is_wave_out? bps<=8 : decoder_session->is_unsigned_samples)); - unsigned wide_samples = frame->header.blocksize, wide_sample, sample, channel, byte; - unsigned frame_bytes = 0; - static FLAC__int8 s8buffer[FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS * sizeof(FLAC__int32)]; /* WATCHOUT: can be up to 2 megs */ - FLAC__uint8 *u8buffer = (FLAC__uint8 *)s8buffer; - FLAC__int16 *s16buffer = (FLAC__int16 *)s8buffer; - FLAC__uint16 *u16buffer = (FLAC__uint16 *)s8buffer; - FLAC__int32 *s32buffer = (FLAC__int32 *)s8buffer; - FLAC__uint32 *u32buffer = (FLAC__uint32 *)s8buffer; + 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; @@ -943,6 +1147,10 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder 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; } @@ -964,7 +1172,7 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder } /* sanity-check the sample rate */ - if(decoder_session->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); @@ -983,9 +1191,8 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder /* * limit the number of samples to accept based on --until */ - FLAC__ASSERT(!decoder_session->skip_specification->is_relative); /* if we never got the total_samples from the metadata, the skip and until specs would never have been canonicalized, so protect against that: */ - if(decoder_session->skip_specification->is_relative) { + if(decoder_session->skip_specification->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 { @@ -993,7 +1200,7 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; } } - if(decoder_session->until_specification->is_relative) { + 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 { @@ -1009,7 +1216,7 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder const FLAC__uint64 input_samples_passed = skip + decoder_session->samples_processed; FLAC__ASSERT(until >= input_samples_passed); if(input_samples_passed + wide_samples > until) - wide_samples = (unsigned)(until - input_samples_passed); + wide_samples = (uint32_t)(until - input_samples_passed); if (wide_samples == 0) { decoder_session->abort_flag = true; decoder_session->aborting_due_to_until = true; @@ -1020,7 +1227,7 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder if(decoder_session->analysis_mode) { FLAC__uint64 dpos; FLAC__stream_decoder_get_decode_position(decoder_session->decoder, &dpos); - frame_bytes = (unsigned)(dpos-decoder_session->decode_position); + frame_bytes = (dpos-decoder_session->decode_position); decoder_session->decode_position = dpos; } @@ -1028,8 +1235,16 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder decoder_session->samples_processed += wide_samples; decoder_session->frame_counter++; - if(!(decoder_session->frame_counter & 0x3f)) +#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); @@ -1038,11 +1253,11 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder if(shift && !decoder_session->replaygain.apply) { for(wide_sample = 0; wide_sample < wide_samples; wide_sample++) for(channel = 0; channel < channels; channel++) - ((FLAC__int32**)buffer)[channel][wide_sample] <<= shift;/*@@@@@@un-const'ing the buffer is hacky but safe*/ + ((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( - u8buffer, + ubuf.u8buffer, !is_big_endian, is_unsigned_samples, buffer, @@ -1058,17 +1273,17 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder } /* first some special code for common cases */ else if(is_big_endian == is_big_endian_host_ && !is_unsigned_samples && channels == 2 && bps+shift == 16) { - FLAC__int16 *buf1_ = s16buffer + 1; + FLAC__int16 *buf1_ = ubuf.s16buffer + 1; if(is_big_endian) - memcpy(s16buffer, ((FLAC__byte*)(buffer[0]))+2, sizeof(FLAC__int32) * wide_samples - 2); + memcpy(ubuf.s16buffer, ((FLAC__byte*)(buffer[0]))+2, sizeof(FLAC__int32) * wide_samples - 2); else - memcpy(s16buffer, buffer[0], sizeof(FLAC__int32) * wide_samples); + 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_ = s16buffer; + FLAC__int16 *buf1_ = ubuf.s16buffer; for(sample = 0; sample < wide_samples; sample++) *buf1_++ = (FLAC__int16)buffer[0][sample]; bytes_to_write = 2 * sample; @@ -1078,44 +1293,45 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder if(is_unsigned_samples) { if(channels == 2) { for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) { - u16buffer[sample++] = (FLAC__uint16)(buffer[0][wide_sample] + 0x8000); - u16buffer[sample++] = (FLAC__uint16)(buffer[1][wide_sample] + 0x8000); + 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++) - u16buffer[sample++] = (FLAC__uint16)(buffer[0][wide_sample] + 0x8000); + 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++) - u16buffer[sample] = (FLAC__uint16)(buffer[channel][wide_sample] + 0x8000); + 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++) { - s16buffer[sample++] = (FLAC__int16)(buffer[0][wide_sample]); - s16buffer[sample++] = (FLAC__int16)(buffer[1][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++) - s16buffer[sample++] = (FLAC__int16)(buffer[0][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++) - s16buffer[sample] = (FLAC__int16)(buffer[channel][wide_sample]); + ubuf.s16buffer[sample] = (FLAC__int16)(buffer[channel][wide_sample]); } } if(is_big_endian != is_big_endian_host_) { - unsigned char tmp; - const unsigned bytes = sample * 2; - for(byte = 0; byte < bytes; byte += 2) { - tmp = u8buffer[byte]; - u8buffer[byte] = u8buffer[byte+1]; - u8buffer[byte+1] = tmp; + 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; @@ -1124,43 +1340,44 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder if(is_unsigned_samples) { for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) for(channel = 0; channel < channels; channel++, sample++) - u32buffer[sample] = buffer[channel][wide_sample] + 0x800000; + 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++) - s32buffer[sample] = buffer[channel][wide_sample]; + ubuf.s32buffer[sample] = buffer[channel][wide_sample]; } if(is_big_endian != is_big_endian_host_) { - unsigned char tmp; - const unsigned bytes = sample * 4; - for(byte = 0; byte < bytes; byte += 4) { - tmp = u8buffer[byte]; - u8buffer[byte] = u8buffer[byte+3]; - u8buffer[byte+3] = tmp; - tmp = u8buffer[byte+1]; - u8buffer[byte+1] = u8buffer[byte+2]; - u8buffer[byte+2] = tmp; + 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) { - unsigned lbyte; - const unsigned bytes = sample * 4; - for(lbyte = byte = 0; byte < bytes; ) { - byte++; - u8buffer[lbyte++] = u8buffer[byte++]; - u8buffer[lbyte++] = u8buffer[byte++]; - u8buffer[lbyte++] = u8buffer[byte++]; + 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 { - unsigned lbyte; - const unsigned bytes = sample * 4; - for(lbyte = byte = 0; byte < bytes; ) { - u8buffer[lbyte++] = u8buffer[byte++]; - u8buffer[lbyte++] = u8buffer[byte++]; - u8buffer[lbyte++] = u8buffer[byte++]; - byte++; + 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; @@ -1169,15 +1386,41 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder if(is_unsigned_samples) { for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) for(channel = 0; channel < channels; channel++, sample++) - u8buffer[sample] = (FLAC__uint8)(buffer[channel][wide_sample] + 0x80); + 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++) - s8buffer[sample] = (FLAC__int8)(buffer[channel][wide_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 */ @@ -1187,7 +1430,7 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder } } if(bytes_to_write > 0) { - if(flac__utils_fwrite(u8buffer, 1, bytes_to_write, fout) != bytes_to_write) { + 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; @@ -1202,18 +1445,30 @@ void metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMet { DecoderSession *decoder_session = (DecoderSession*)client_data; - if(decoder_session->analysis_mode) - FLAC__stream_decoder_get_decode_position(decoder, &decoder_session->decode_position); + (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); + 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; - flac__utils_canonicalize_skip_until_specification(decoder_session->skip_specification, decoder_session->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; @@ -1245,8 +1500,14 @@ void metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMet decoder_session->total_samples -= (metadata->data.stream_info.total_samples - until); } - if(decoder_session->bps < 4 || decoder_session->bps > 24) { - flac__utils_printf(stderr, 1, "%s: ERROR: bits per sample is %u, must be 4-24\n", decoder_session->inbasefilename, decoder_session->bps); + 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; } @@ -1284,6 +1545,13 @@ void metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMet 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" }; @@ -1297,17 +1565,39 @@ void metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMet } (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; - flac__utils_printf(stderr, 1, "%s: *** Got error code %d:%s\n", decoder_session->inbasefilename, status, FLAC__StreamDecoderErrorStatusString[status]); + 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) { - decoder_session->abort_flag = true; - if(status == FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM) + /* 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; } } @@ -1323,8 +1613,13 @@ void print_error_with_init_status(const DecoderSession *d, const char *message, 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 ); } } @@ -1346,7 +1641,7 @@ void print_error_with_state(const DecoderSession *d, const char *message) "not able to decode the file. If the version number is not, the file\n" "may be corrupted, or you may have found a bug. In this case please\n" "submit a bug report to\n" - " http://sourceforge.net/bugs/?func=addbug&group_id=13478\n" + " 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 ); @@ -1356,24 +1651,23 @@ void print_error_with_state(const DecoderSession *d, const char *message) void print_stats(const DecoderSession *decoder_session) { if(flac__utils_verbosity_ >= 2) { -#if defined _MSC_VER || defined __MINGW32__ - /* with MSVC you have to spoon feed it the casting */ - const double progress = (double)(FLAC__int64)decoder_session->samples_processed / (double)(FLAC__int64)decoder_session->total_samples * 100.0; -#else const double progress = (double)decoder_session->samples_processed / (double)decoder_session->total_samples * 100.0; -#endif + if(decoder_session->total_samples > 0) { - fprintf(stderr, "\r%s: %s%u%% complete", - decoder_session->inbasefilename, + 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, " : "", - (unsigned)floor(progress + 0.5) + (uint32_t)floor(progress + 0.5) ); } else { - fprintf(stderr, "\r%s: %s %u samples", - decoder_session->inbasefilename, + 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", - (unsigned)decoder_session->samples_processed + decoder_session->samples_processed ); } } diff --git a/3rdparty/libflac/src/flac/decode.h b/3rdparty/libflac/src/flac/decode.h index 2ab9deb6605..24f5723dada 100644 --- a/3rdparty/libflac/src/flac/decode.h +++ b/3rdparty/libflac/src/flac/decode.h @@ -1,5 +1,6 @@ /* flac - Command-line FLAC encoder/decoder - * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson + * 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 @@ -11,15 +12,15 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * You 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 -#if HAVE_CONFIG_H +#ifdef HAVE_CONFIG_H # include <config.h> #endif @@ -51,24 +52,22 @@ typedef struct { FLAC__bool has_cue_specification; utils__CueSpecification cue_specification; FLAC__bool channel_map_none; /* --channel-map=none specified, eventually will expand to take actual channel map */ -} decode_options_t; - -/* used for AIFF also */ -typedef struct { - decode_options_t common; - foreign_metadata_t *foreign_metadata; /* NULL unless --keep-foreign-metadata requested */ -} wav_decode_options_t; + FLAC__bool relaxed_foreign_metadata_handling; + FileSubFormat force_subformat; -typedef struct { - decode_options_t common; - - FLAC__bool is_big_endian; - FLAC__bool is_unsigned_samples; -} raw_decode_options_t; + 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_aiff(const char *infilename, const char *outfilename, FLAC__bool analysis_mode, analysis_options aopts, wav_decode_options_t options); -int flac__decode_wav(const char *infilename, const char *outfilename, FLAC__bool analysis_mode, analysis_options aopts, wav_decode_options_t options); -int flac__decode_raw(const char *infilename, const char *outfilename, FLAC__bool analysis_mode, analysis_options aopts, raw_decode_options_t options); +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/3rdparty/libflac/src/flac/encode.c b/3rdparty/libflac/src/flac/encode.c index 8d2434993e5..a945b356a52 100644 --- a/3rdparty/libflac/src/flac/encode.c +++ b/3rdparty/libflac/src/flac/encode.c @@ -1,5 +1,6 @@ /* flac - Command-line FLAC encoder/decoder - * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson + * 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 @@ -11,37 +12,30 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * You 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 HAVE_CONFIG_H +#ifdef HAVE_CONFIG_H # include <config.h> #endif -#if defined _WIN32 && !defined __CYGWIN__ -/* where MSVC puts unlink() */ -# include <io.h> -#else -# include <unistd.h> -#endif -#if defined _MSC_VER || defined __MINGW32__ -#include <sys/types.h> /* for off_t */ -#if _MSC_VER <= 1600 /* @@@ [2G limit] */ -#define fseeko fseek -#define ftello ftell -#endif -#endif #include <errno.h> #include <limits.h> /* for LONG_MAX */ #include <math.h> /* for floor() */ #include <stdio.h> /* for FILE etc. */ #include <stdlib.h> /* for malloc */ #include <string.h> /* for strcmp(), strerror() */ +#include <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 @@ -53,10 +47,32 @@ #endif #define max(x,y) ((x)>(y)?(x):(y)) -/* this MUST be >= 588 so that sector aligning can take place with one read */ +/* 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 @@ -67,73 +83,75 @@ typedef struct { const char *infilename; const char *outfilename; - FLAC__uint64 skip; - FLAC__uint64 until; /* a value of 0 mean end-of-stream (i.e. --until=-0) */ FLAC__bool treat_warnings_as_errors; FLAC__bool continue_through_decode_errors; FLAC__bool replay_gain; - unsigned channels; - unsigned bits_per_sample; - unsigned sample_rate; - FLAC__uint64 unencoded_size; - FLAC__uint64 total_samples_to_encode; + FLAC__uint64 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; - unsigned stats_mask; +#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; -/* this is data attached to the FLAC decoder when encoding from a FLAC file */ -typedef struct { - EncoderSession *encoder_session; - off_t filesize; - const FLAC__byte *lookahead; - unsigned lookahead_length; - size_t num_metadata_blocks; - FLAC__StreamMetadata *metadata_blocks[1024]; /*@@@ BAD MAGIC number */ - FLAC__uint64 samples_left_to_process; - FLAC__bool fatal_error; -} FLACDecoderData; - const int FLAC_ENCODE__DEFAULT_PADDING = 8192; static FLAC__bool is_big_endian_host_; -static unsigned char ucbuffer_[CHUNK_OF_SAMPLES*FLAC__MAX_CHANNELS*((FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE+7)/8)]; -static signed char *scbuffer_ = (signed char *)ucbuffer_; -static FLAC__uint16 *usbuffer_ = (FLAC__uint16 *)ucbuffer_; -static FLAC__int16 *ssbuffer_ = (FLAC__int16 *)ucbuffer_; +#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]; /* - * unpublished debug routines from the FLAC libs - */ -extern FLAC__bool FLAC__stream_encoder_disable_constant_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value); -extern FLAC__bool FLAC__stream_encoder_disable_fixed_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value); -extern FLAC__bool FLAC__stream_encoder_disable_verbatim_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value); -extern FLAC__bool FLAC__stream_encoder_set_do_md5(FLAC__StreamEncoder *encoder, FLAC__bool value); - -/* * local routines */ -static FLAC__bool EncoderSession_construct(EncoderSession *e, FLAC__bool use_ogg, FLAC__bool verify, FLAC__bool treat_warnings_as_errors, FLAC__bool continue_through_decode_errors, FILE *infile, const char *infilename, const char *outfilename); +static 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, int info_align_carry, int info_align_zero, foreign_metadata_t *foreign_metadata); +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, FLAC__uint32 channel_mask, unsigned channels, unsigned bps, unsigned sample_rate, const foreign_metadata_t *foreign_metadata, FLACDecoderData *flac_decoder_data); -static FLAC__bool EncoderSession_process(EncoderSession *e, const FLAC__int32 * const buffer[], unsigned samples); +static FLAC__bool 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, unsigned sample_rate, FLAC__uint64 skip, FLAC__uint64 total_samples_in_input); -static FLAC__bool verify_metadata(const EncoderSession *e, FLAC__StreamMetadata **metadata, unsigned num_metadata); -static FLAC__bool format_input(FLAC__int32 *dest[], unsigned wide_samples, FLAC__bool is_big_endian, FLAC__bool is_unsigned_samples, unsigned channels, unsigned bps, unsigned shift, size_t *channel_map); -static void encoder_progress_callback(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data); +static FLAC__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); @@ -142,530 +160,121 @@ static FLAC__bool flac_decoder_eof_callback(const FLAC__StreamDecoder *decoder, static FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); static void flac_decoder_metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); static void flac_decoder_error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); -static FLAC__bool parse_cuesheet(FLAC__StreamMetadata **cuesheet, const char *cuesheet_filename, const char *inbasefilename, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset, FLAC__bool treat_warnings_as_errors); +static 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_little_endian_uint16(FILE *f, FLAC__uint16 *val, FLAC__bool eof_ok, const char *fn); -static FLAC__bool read_little_endian_uint32(FILE *f, FLAC__uint32 *val, FLAC__bool eof_ok, const char *fn); -static FLAC__bool read_big_endian_uint16(FILE *f, FLAC__uint16 *val, FLAC__bool eof_ok, const char *fn); -static FLAC__bool read_big_endian_uint32(FILE *f, FLAC__uint32 *val, FLAC__bool eof_ok, const char *fn); -static FLAC__bool read_sane_extended(FILE *f, FLAC__uint32 *val, FLAC__bool eof_ok, const char *fn); +static FLAC__bool 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 unsigned count_channel_mask_bits(FLAC__uint32 mask); -#if 0 -static FLAC__uint32 limit_channel_mask(FLAC__uint32 mask, unsigned channels); -#endif +static uint32_t count_channel_mask_bits(FLAC__uint32 mask); -/* - * public routines - */ -int flac__encode_aif(FILE *infile, off_t infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, unsigned lookahead_length, wav_encode_options_t options, FLAC__bool is_aifc) +static FLAC__bool get_sample_info_raw(EncoderSession *e, encode_options_t options) { - EncoderSession encoder_session; - FLAC__uint16 x; - FLAC__uint32 xx; - unsigned int channels= 0U, bps= 0U, shift= 0U, sample_rate= 0U, sample_frames= 0U; - size_t channel_map[FLAC__MAX_CHANNELS]; - FLAC__bool got_comm_chunk= false, got_ssnd_chunk= false; - int info_align_carry= -1, info_align_zero= -1; - FLAC__bool is_big_endian_pcm = true; + 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; - (void)infilesize; /* silence compiler warning about unused parameter */ - (void)lookahead; /* silence compiler warning about unused parameter */ - (void)lookahead_length; /* silence compiler warning about unused parameter */ + return true; +} - if(! - EncoderSession_construct( - &encoder_session, -#if FLAC__HAS_OGG - options.common.use_ogg, -#else - /*use_ogg=*/false, -#endif - options.common.verify, - options.common.treat_warnings_as_errors, - options.common.continue_through_decode_errors, - infile, - infilename, - outfilename - ) - ) - return 1; +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; - /* 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; - } + e->info.is_unsigned_samples = false; + e->info.is_big_endian = false; - if(options.foreign_metadata) { - const char *error; - if(!flac__foreign_metadata_read_from_aiff(options.foreign_metadata, infilename, &error)) { - flac__utils_printf(stderr, 1, "%s: ERROR reading foreign metadata: %s\n", encoder_session.inbasefilename, error); - return EncoderSession_finish_error(&encoder_session); + 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" */ - /* lookahead[] already has "FORMxxxxAIFF", do sub-chunks */ - - while(1) { - size_t c= 0U; - char chunk_id[5] = { '\0', '\0', '\0', '\0', '\0' }; /* one extra byte for terminating NUL so we can also treat it like a C string */ - - /* chunk identifier; really conservative about behavior of fread() and feof() */ - if(feof(infile) || ((c= fread(chunk_id, 1U, 4U, infile)), c==0U && feof(infile))) - break; - else if(c<4U || feof(infile)) { - flac__utils_printf(stderr, 1, "%s: ERROR: incomplete chunk identifier\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); - } - - if(got_comm_chunk==false && !memcmp(chunk_id, "COMM", 4)) { /* common chunk */ - unsigned long skip; - const FLAC__uint32 minimum_comm_size = (is_aifc? 22 : 18); + 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' }; - /* COMM chunk size */ - if(!read_big_endian_uint32(infile, &xx, false, encoder_session.inbasefilename)) - return EncoderSession_finish_error(&encoder_session); - else if(xx<minimum_comm_size) { - flac__utils_printf(stderr, 1, "%s: ERROR: non-standard %s 'COMM' chunk has length = %u\n", encoder_session.inbasefilename, is_aifc? "AIFF-C" : "AIFF", (unsigned int)xx); - return EncoderSession_finish_error(&encoder_session); - } - else if(!is_aifc && xx!=minimum_comm_size) { - flac__utils_printf(stderr, 1, "%s: WARNING: non-standard %s 'COMM' chunk has length = %u, expected %u\n", encoder_session.inbasefilename, is_aifc? "AIFF-C" : "AIFF", (unsigned int)xx, minimum_comm_size); - if(encoder_session.treat_warnings_as_errors) - return EncoderSession_finish_error(&encoder_session); - } - skip= (xx-minimum_comm_size)+(xx & 1U); - - /* number of channels */ - if(!read_big_endian_uint16(infile, &x, false, encoder_session.inbasefilename)) - return EncoderSession_finish_error(&encoder_session); - else if(x==0U || x>FLAC__MAX_CHANNELS) { - flac__utils_printf(stderr, 1, "%s: ERROR: unsupported number channels %u\n", encoder_session.inbasefilename, (unsigned int)x); - return EncoderSession_finish_error(&encoder_session); - } - else if(x>2U && !options.common.channel_map_none) { - flac__utils_printf(stderr, 1, "%s: ERROR: unsupported number channels %u for AIFF\n", encoder_session.inbasefilename, (unsigned int)x); - return EncoderSession_finish_error(&encoder_session); - } - else if(options.common.sector_align && x!=2U) { - flac__utils_printf(stderr, 1, "%s: ERROR: file has %u channels, must be 2 for --sector-align\n", encoder_session.inbasefilename, (unsigned int)x); - return EncoderSession_finish_error(&encoder_session); - } - channels= x; - - /* number of sample frames */ - if(!read_big_endian_uint32(infile, &xx, false, encoder_session.inbasefilename)) - return EncoderSession_finish_error(&encoder_session); - sample_frames= xx; - - /* bits per sample */ - if(!read_big_endian_uint16(infile, &x, false, encoder_session.inbasefilename)) - return EncoderSession_finish_error(&encoder_session); - else if(x<4U || x>24U) { - flac__utils_printf(stderr, 1, "%s: ERROR: unsupported bits-per-sample %u\n", encoder_session.inbasefilename, (unsigned int)x); - return EncoderSession_finish_error(&encoder_session); - } - else if(options.common.sector_align && x!=16U) { - flac__utils_printf(stderr, 1, "%s: ERROR: file has %u bits-per-sample, must be 16 for --sector-align\n", encoder_session.inbasefilename, (unsigned int)x); - return EncoderSession_finish_error(&encoder_session); - } - bps= x; - shift= (bps%8)? 8-(bps%8) : 0; /* SSND data is always byte-aligned, left-justified but format_input() will double-check */ - bps+= shift; - - /* sample rate */ - if(!read_sane_extended(infile, &xx, false, encoder_session.inbasefilename)) - return EncoderSession_finish_error(&encoder_session); - else if(!FLAC__format_sample_rate_is_valid(xx)) { - flac__utils_printf(stderr, 1, "%s: ERROR: unsupported sample rate %u\n", encoder_session.inbasefilename, (unsigned int)xx); - return EncoderSession_finish_error(&encoder_session); - } - else if(options.common.sector_align && xx!=44100U) { - flac__utils_printf(stderr, 1, "%s: ERROR: file's sample rate is %u, must be 44100 for --sector-align\n", encoder_session.inbasefilename, (unsigned int)xx); - return EncoderSession_finish_error(&encoder_session); - } - sample_rate= xx; - - /* check compression type for AIFF-C */ - if(is_aifc) { - if(!read_big_endian_uint32(infile, &xx, false, encoder_session.inbasefilename)) - return EncoderSession_finish_error(&encoder_session); - if(xx == 0x736F7774) /* "sowt" */ - is_big_endian_pcm = false; - else if(xx == 0x4E4F4E45) /* "NONE" */ - ; /* nothing to do, we already default to big-endian */ - else { - flac__utils_printf(stderr, 1, "%s: ERROR: can't handle AIFF-C compression type \"%c%c%c%c\"\n", encoder_session.inbasefilename, (char)(xx>>24), (char)((xx>>16)&8), (char)((xx>>8)&8), (char)(xx&8)); - return EncoderSession_finish_error(&encoder_session); - } - } - - /* set channel mapping */ - /* FLAC order follows SMPTE and WAVEFORMATEXTENSIBLE but with fewer channels, which are: */ - /* front left, front right, center, LFE, back left, back right, surround left, surround right */ - /* specs say the channel ordering is: - * 1 2 3 4 5 6 - * ___________________________________________________ - * 2 stereo l r - * 3 l r c - * 4 l c r S - * quad (ambiguous with 4ch) Fl Fr Bl Br - * 5 Fl Fr Fc Sl Sr - * 6 l lc c r rc S - * l:left r:right c:center Fl:front-left Fr:front-right Bl:back-left Br:back-right Lc:left-center Rc:right-center S:surround - * so we only have unambiguous mappings for 2, 3, and 5 channels - */ - if( - options.common.channel_map_none || - channels == 1 || /* 1 channel: (mono) */ - channels == 2 || /* 2 channels: left, right */ - channels == 3 || /* 3 channels: left, right, center */ - channels == 5 /* 5 channels: front left, front right, center, surround left, surround right */ - ) { - /* keep default channel order */ - } - else { - flac__utils_printf(stderr, 1, "%s: ERROR: unsupported number channels %u for AIFF\n", encoder_session.inbasefilename, channels); - return EncoderSession_finish_error(&encoder_session); - } - - /* skip any extra data in the COMM chunk */ - if(!fskip_ahead(infile, skip)) { - flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping over extra COMM data\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); - } - - /* - * now that we know the sample rate, canonicalize the - * --skip string to a number of samples: - */ - flac__utils_canonicalize_skip_until_specification(&options.common.skip_specification, sample_rate); - FLAC__ASSERT(options.common.skip_specification.value.samples >= 0); - encoder_session.skip = (FLAC__uint64)options.common.skip_specification.value.samples; - FLAC__ASSERT(!options.common.sector_align || encoder_session.skip == 0); - - got_comm_chunk= true; + 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; } - else if(got_ssnd_chunk==false && !memcmp(chunk_id, "SSND", 4)) { /* sound data chunk */ - unsigned int offset= 0U, block_size= 0U, align_remainder= 0U, data_bytes; - const size_t bytes_per_frame= channels*(bps>>3); - FLAC__uint64 total_samples_in_input, trim = 0; - FLAC__bool pad= false; - - if(got_comm_chunk==false) { - flac__utils_printf(stderr, 1, "%s: ERROR: got 'SSND' chunk before 'COMM' chunk\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); - } - - /* SSND chunk size */ - if(!read_big_endian_uint32(infile, &xx, false, encoder_session.inbasefilename)) - return EncoderSession_finish_error(&encoder_session); - if(options.common.ignore_chunk_sizes) { - FLAC__ASSERT(!options.common.sector_align); - data_bytes = (unsigned)(-(int)bytes_per_frame); /* max out data_bytes; we'll use EOF as signal to stop reading */ - } - else { - data_bytes= xx; - data_bytes-= 8U; /* discount the offset and block size fields */ - } - pad= (data_bytes & 1U) ? true : false; - - /* offset */ - if(!read_big_endian_uint32(infile, &xx, false, encoder_session.inbasefilename)) - return EncoderSession_finish_error(&encoder_session); - offset= xx; - data_bytes-= offset; - - /* block size */ - if(!read_big_endian_uint32(infile, &xx, false, encoder_session.inbasefilename)) - return EncoderSession_finish_error(&encoder_session); - else if(xx!=0U) { - flac__utils_printf(stderr, 1, "%s: ERROR: block size is %u; must be 0\n", encoder_session.inbasefilename, (unsigned int)xx); - return EncoderSession_finish_error(&encoder_session); - } - block_size= xx; - - /* skip any SSND offset bytes */ - FLAC__ASSERT(offset<=LONG_MAX); - if(!fskip_ahead(infile, offset)) { - flac__utils_printf(stderr, 1, "%s: ERROR: skipping offset in SSND chunk\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); - } - if(data_bytes!=(sample_frames*bytes_per_frame)) { - flac__utils_printf(stderr, 1, "%s: ERROR: SSND chunk size inconsistent with sample frame count\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); - } - - /* *options.common.align_reservoir_samples will be 0 unless --sector-align is used */ - FLAC__ASSERT(options.common.sector_align || *options.common.align_reservoir_samples == 0); - total_samples_in_input = data_bytes / bytes_per_frame + *options.common.align_reservoir_samples; - - /* - * now that we know the input size, canonicalize the - * --until string to an absolute sample number: - */ - if(!canonicalize_until_specification(&options.common.until_specification, encoder_session.inbasefilename, sample_rate, encoder_session.skip, total_samples_in_input)) - return EncoderSession_finish_error(&encoder_session); - encoder_session.until = (FLAC__uint64)options.common.until_specification.value.samples; - FLAC__ASSERT(!options.common.sector_align || encoder_session.until == 0); - - if(encoder_session.skip>0U) { - if(!fskip_ahead(infile, encoder_session.skip*bytes_per_frame)) { - flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping samples\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); - } - } - - data_bytes-= (unsigned int)encoder_session.skip*bytes_per_frame; /*@@@ WATCHOUT: 4GB limit */ - if(options.common.ignore_chunk_sizes) { - encoder_session.total_samples_to_encode= 0; - flac__utils_printf(stderr, 2, "(No runtime statistics possible; please wait for encoding to finish...)\n"); - FLAC__ASSERT(0 == encoder_session.until); - } - else { - encoder_session.total_samples_to_encode= total_samples_in_input - encoder_session.skip; - } - if(encoder_session.until > 0) { - trim = total_samples_in_input - encoder_session.until; - FLAC__ASSERT(total_samples_in_input > 0); - FLAC__ASSERT(!options.common.sector_align); - data_bytes-= (unsigned int)trim*bytes_per_frame; - encoder_session.total_samples_to_encode-= trim; - } - if(options.common.sector_align) { - align_remainder= (unsigned int)(encoder_session.total_samples_to_encode % 588U); - if(options.common.is_last_file) - encoder_session.total_samples_to_encode+= (588U-align_remainder); /* will pad with zeroes */ - else - encoder_session.total_samples_to_encode-= align_remainder; /* will stop short and carry over to next file */ - } - - /* +54 for the size of the AIFF headers; this is just an estimate for the progress indicator and doesn't need to be exact */ - encoder_session.unencoded_size= encoder_session.total_samples_to_encode*bytes_per_frame+54; - - if(!EncoderSession_init_encoder(&encoder_session, options.common, /*channel_mask=*/0, channels, bps-shift, sample_rate, options.foreign_metadata, /*flac_decoder_data=*/0)) - return EncoderSession_finish_error(&encoder_session); - - /* first do any samples in the reservoir */ - if(options.common.sector_align && *options.common.align_reservoir_samples>0U) { + if(feof(e->fin)) + break; - if(!EncoderSession_process(&encoder_session, (const FLAC__int32 *const *)options.common.align_reservoir, *options.common.align_reservoir_samples)) { - print_error_with_state(&encoder_session, "ERROR during encoding"); - return EncoderSession_finish_error(&encoder_session); - } - } + if(e->format == FORMAT_RF64 && !memcmp(chunk_id, "ds64", 4)) { /* RF64 64-bit sizes chunk */ + FLAC__uint32 xx, data_bytes; - /* decrement the data_bytes counter if we need to align the file */ - if(options.common.sector_align) { - if(options.common.is_last_file) - *options.common.align_reservoir_samples= 0U; - else { - *options.common.align_reservoir_samples= align_remainder; - data_bytes-= (*options.common.align_reservoir_samples)*bytes_per_frame; - } + if(got_ds64_chunk) { + flac__utils_printf(stderr, 1, "%s: ERROR: file has multiple 'ds64' chunks\n", e->inbasefilename); + return false; } - - /* now do from the file */ - while(data_bytes>0) { - size_t bytes_read= fread(ucbuffer_, 1U, min(data_bytes, CHUNK_OF_SAMPLES*bytes_per_frame), infile); - - if(bytes_read==0U) { - if(ferror(infile)) { - flac__utils_printf(stderr, 1, "%s: ERROR during read\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); - } - else if(feof(infile)) { - if(options.common.ignore_chunk_sizes) { - flac__utils_printf(stderr, 1, "%s: INFO: hit EOF with --ignore-chunk-sizes, got %u samples\n", encoder_session.inbasefilename, (unsigned)encoder_session.samples_written); - } - else { - flac__utils_printf(stderr, 1, "%s: WARNING: unexpected EOF; expected %u samples, got %u samples\n", encoder_session.inbasefilename, (unsigned)encoder_session.total_samples_to_encode, (unsigned)encoder_session.samples_written); - if(encoder_session.treat_warnings_as_errors) - return EncoderSession_finish_error(&encoder_session); - } - data_bytes= 0; - } - } - else { - if(bytes_read % bytes_per_frame != 0U) { - flac__utils_printf(stderr, 1, "%s: ERROR: got partial sample\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); - } - else { - unsigned int frames= bytes_read/bytes_per_frame; - if(!format_input(input_, frames, is_big_endian_pcm, /*is_unsigned_samples=*/false, channels, bps, shift, channel_map)) - return EncoderSession_finish_error(&encoder_session); - - if(!EncoderSession_process(&encoder_session, (const FLAC__int32 *const *)input_, frames)) { - print_error_with_state(&encoder_session, "ERROR during encoding"); - return EncoderSession_finish_error(&encoder_session); - } - else - data_bytes-= bytes_read; - } - } + if(got_fmt_chunk) { + flac__utils_printf(stderr, 1, "%s: ERROR: 'ds64' chunk appears after 'fmt ' or 'data' chunk\n", e->inbasefilename); + return false; } - if(trim>0) { - FLAC__ASSERT(!options.common.sector_align); - if(!fskip_ahead(infile, trim*bytes_per_frame)) { - flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping samples\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); - } + /* 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++; - /* now read unaligned samples into reservoir or pad with zeroes if necessary */ - if(options.common.sector_align) { - if(options.common.is_last_file) { - unsigned int pad_frames= 588U-align_remainder; - - if(pad_frames<588U) { - unsigned int i; - - info_align_zero= pad_frames; - for(i= 0U; i<channels; ++i) - memset(input_[i], 0, sizeof(input_[0][0])*pad_frames); - - if(!EncoderSession_process(&encoder_session, (const FLAC__int32 *const *)input_, pad_frames)) { - print_error_with_state(&encoder_session, "ERROR during encoding"); - return EncoderSession_finish_error(&encoder_session); - } - } - } - else { - if(*options.common.align_reservoir_samples > 0) { - size_t bytes_read= fread(ucbuffer_, 1U, (*options.common.align_reservoir_samples)*bytes_per_frame, infile); + /* 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; - FLAC__ASSERT(CHUNK_OF_SAMPLES>=588U); - if(bytes_read==0U && ferror(infile)) { - flac__utils_printf(stderr, 1, "%s: ERROR during read\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); - } - else if(bytes_read != (*options.common.align_reservoir_samples) * bytes_per_frame) { - flac__utils_printf(stderr, 1, "%s: WARNING: unexpected EOF; read %u bytes; expected %u samples, got %u samples\n", encoder_session.inbasefilename, (unsigned int)bytes_read, (unsigned int)encoder_session.total_samples_to_encode, (unsigned int)encoder_session.samples_written); - if(encoder_session.treat_warnings_as_errors) - return EncoderSession_finish_error(&encoder_session); - } - else { - info_align_carry= *options.common.align_reservoir_samples; - if(!format_input(options.common.align_reservoir, *options.common.align_reservoir_samples, is_big_endian_pcm, /*is_unsigned_samples=*/false, channels, bps, shift, channel_map)) - return EncoderSession_finish_error(&encoder_session); - } - } - } - } + /* 'data' 64-bit size */ + if(!read_uint64(e->fin, /*big_endian=*/false, &ds64_data_size, e->inbasefilename)) + return false; - if(pad==true) { - unsigned char tmp; + data_bytes -= 16; - if(fread(&tmp, 1U, 1U, infile)<1U) { - flac__utils_printf(stderr, 1, "%s: ERROR during read of SSND pad byte\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); - } + /* 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_ssnd_chunk= true; + got_ds64_chunk = true; } - else { /* other chunk */ - if(!options.foreign_metadata) { - if(!memcmp(chunk_id, "COMM", 4)) - flac__utils_printf(stderr, 1, "%s: WARNING: skipping extra 'COMM' chunk (use --keep-foreign-metadata to keep)\n", encoder_session.inbasefilename); - else if(!memcmp(chunk_id, "SSND", 4)) - flac__utils_printf(stderr, 1, "%s: WARNING: skipping extra 'SSND' chunk (use --keep-foreign-metadata to keep)\n", encoder_session.inbasefilename); - else if(!options.foreign_metadata) - flac__utils_printf(stderr, 1, "%s: WARNING: skipping unknown chunk '%s' (use --keep-foreign-metadata to keep)\n", encoder_session.inbasefilename, chunk_id); - if(encoder_session.treat_warnings_as_errors) - return EncoderSession_finish_error(&encoder_session); - } - - /* chunk size */ - if(!read_big_endian_uint32(infile, &xx, false, encoder_session.inbasefilename)) - return EncoderSession_finish_error(&encoder_session); - else { - unsigned long skip= xx+(xx & 1U); - - FLAC__ASSERT(skip<=LONG_MAX); - if(!fskip_ahead(infile, skip)) { - fprintf(stderr, "%s: ERROR during read while skipping over unknown chunk\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); - } + 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; } - } - } - - if(got_ssnd_chunk==false && sample_frames!=0U) { - flac__utils_printf(stderr, 1, "%s: ERROR: missing SSND chunk\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); - } - - return EncoderSession_finish_ok(&encoder_session, info_align_carry, info_align_zero, options.foreign_metadata); -} - -int flac__encode_wav(FILE *infile, off_t infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, unsigned lookahead_length, wav_encode_options_t options) -{ - EncoderSession encoder_session; - FLAC__bool is_unsigned_samples = false; - unsigned channels = 0, bps = 0, sample_rate = 0, shift = 0; - size_t bytes_read; - size_t channel_map[FLAC__MAX_CHANNELS]; - FLAC__uint16 x, format; /* format is the wFormatTag word from the 'fmt ' chunk */ - FLAC__uint32 xx, channel_mask = 0; - FLAC__bool got_fmt_chunk = false, got_data_chunk = false; - unsigned align_remainder = 0; - int info_align_carry = -1, info_align_zero = -1; - - (void)infilesize; - (void)lookahead; - (void)lookahead_length; - - if(! - EncoderSession_construct( - &encoder_session, -#if FLAC__HAS_OGG - options.common.use_ogg, -#else - /*use_ogg=*/false, -#endif - options.common.verify, - options.common.treat_warnings_as_errors, - options.common.continue_through_decode_errors, - infile, - infilename, - outfilename - ) - ) - return 1; - - /* initialize default channel map that preserves channel order */ - { - size_t i; - for(i = 0; i < sizeof(channel_map)/sizeof(channel_map[0]); i++) - channel_map[i] = i; - } - - if(options.foreign_metadata) { - const char *error; - if(!flac__foreign_metadata_read_from_wave(options.foreign_metadata, infilename, &error)) { - flac__utils_printf(stderr, 1, "%s: ERROR reading foreign metadata: %s\n", encoder_session.inbasefilename, error); - return EncoderSession_finish_error(&encoder_session); - } - } - - /* - * lookahead[] already has "RIFFxxxxWAVE", do sub-chunks - */ - while(!feof(infile)) { - if(!read_little_endian_uint32(infile, &xx, true, encoder_session.inbasefilename)) - return EncoderSession_finish_error(&encoder_session); - if(feof(infile)) - break; - if(xx == 0x20746d66 && !got_fmt_chunk) { /* "fmt " */ - unsigned block_align, data_bytes; /* see * http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html @@ -673,7 +282,7 @@ int flac__encode_wav(FILE *infile, off_t infilesize, const char *infilename, con * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/audio_r/hh/Audio_r/aud-prop_d40f094e-44f9-4baa-8a15-03e4fb369501.xml.asp * * WAVEFORMAT is - * 4 byte: subchunk size + * 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) @@ -695,910 +304,1071 @@ int flac__encode_wav(FILE *infile, off_t infilesize, const char *infilename, con * If the channel mask has more set bits than # of channels, the extra MSBs are ignored. * If the channel mask has less set bits than # of channels, the extra channels are unassigned to any speaker. * - * Data is supposed to be unsigned for bps <= 8 else signed. + * Data is supposed to be uint32_t for bps <= 8 else signed. */ - /* fmt sub-chunk size */ - if(!read_little_endian_uint32(infile, &xx, false, encoder_session.inbasefilename)) - return EncoderSession_finish_error(&encoder_session); + /* fmt chunk size */ + if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename)) + return false; data_bytes = xx; - if(data_bytes < 16) { - flac__utils_printf(stderr, 1, "%s: ERROR: found non-standard 'fmt ' sub-chunk which has length = %u\n", encoder_session.inbasefilename, data_bytes); - return EncoderSession_finish_error(&encoder_session); + 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); } - /* format code */ - if(!read_little_endian_uint16(infile, &format, false, encoder_session.inbasefilename)) - return EncoderSession_finish_error(&encoder_session); - if(format != 1 /*WAVE_FORMAT_PCM*/ && format != 65534 /*WAVE_FORMAT_EXTENSIBLE*/) { - flac__utils_printf(stderr, 1, "%s: ERROR: unsupported format type %u\n", encoder_session.inbasefilename, (unsigned)format); - return EncoderSession_finish_error(&encoder_session); + 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; } - /* number of channels */ - if(!read_little_endian_uint16(infile, &x, false, encoder_session.inbasefilename)) - return EncoderSession_finish_error(&encoder_session); - channels = (unsigned)x; - if(channels == 0 || channels > FLAC__MAX_CHANNELS) { - flac__utils_printf(stderr, 1, "%s: ERROR: unsupported number of channels %u\n", encoder_session.inbasefilename, channels); - return EncoderSession_finish_error(&encoder_session); + if(e->format != FORMAT_WAVE64) { + if(data_bytes & 1) /* should never happen, but enforce WAVE alignment rules */ + data_bytes++; } - else if(options.common.sector_align && channels != 2) { - flac__utils_printf(stderr, 1, "%s: ERROR: file has %u channels, must be 2 for --sector-align\n", encoder_session.inbasefilename, channels); - return EncoderSession_finish_error(&encoder_session); + 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_little_endian_uint32(infile, &xx, false, encoder_session.inbasefilename)) - return EncoderSession_finish_error(&encoder_session); + if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename)) + return false; sample_rate = xx; - if(!FLAC__format_sample_rate_is_valid(sample_rate)) { - flac__utils_printf(stderr, 1, "%s: ERROR: unsupported sample rate %u\n", encoder_session.inbasefilename, sample_rate); - return EncoderSession_finish_error(&encoder_session); - } - else if(options.common.sector_align && sample_rate != 44100) { - flac__utils_printf(stderr, 1, "%s: ERROR: file's sample rate is %u, must be 44100 for --sector-align\n", encoder_session.inbasefilename, sample_rate); - return EncoderSession_finish_error(&encoder_session); - } + /* avg bytes per second (ignored) */ - if(!read_little_endian_uint32(infile, &xx, false, encoder_session.inbasefilename)) - return EncoderSession_finish_error(&encoder_session); + if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename)) + return false; /* block align */ - if(!read_little_endian_uint16(infile, &x, false, encoder_session.inbasefilename)) - return EncoderSession_finish_error(&encoder_session); - block_align = (unsigned)x; + if(!read_uint16(e->fin, /*big_endian=*/false, &x, e->inbasefilename)) + return false; + block_align = x; /* bits per sample */ - if(!read_little_endian_uint16(infile, &x, false, encoder_session.inbasefilename)) - return EncoderSession_finish_error(&encoder_session); - bps = (unsigned)x; - is_unsigned_samples = (bps <= 8); - if(format == 1) { + if(!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", encoder_session.inbasefilename, (unsigned)format, bps); - if(encoder_session.treat_warnings_as_errors) - return EncoderSession_finish_error(&encoder_session); + 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", encoder_session.inbasefilename, (unsigned)format, bps); - return EncoderSession_finish_error(&encoder_session); - } - } -#if 0 /* @@@ reinstate once we can get an answer about whether the samples are left- or right-justified */ - if((bps+7)/8 * channels == block_align) { - if(bps % 8) { - /* assume legacy file is byte aligned with some LSBs zero; this is double-checked in format_input() */ - flac__utils_printf(stderr, 1, "%s: WARNING: legacy WAVE file (format type %d) has block alignment=%u, bits-per-sample=%u, channels=%u\n", encoder_session.inbasefilename, (unsigned)format, block_align, bps, channels); - if(encoder_session.treat_warnings_as_errors) - return EncoderSession_finish_error(&encoder_session); - shift = 8 - (bps % 8); - bps += shift; + 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; } - else - shift = 0; } - else { - flac__utils_printf(stderr, 1, "%s: ERROR: illegal WAVE file (format type %d) has block alignment=%u, bits-per-sample=%u, channels=%u\n", encoder_session.inbasefilename, (unsigned)format, block_align, bps, channels); - return EncoderSession_finish_error(&encoder_session); + 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; } -#else - shift = 0; -#endif - if(channels > 2 && !options.common.channel_map_none) { - flac__utils_printf(stderr, 1, "%s: ERROR: WAVE has >2 channels but is not WAVE_FORMAT_EXTENSIBLE; cannot assign channels\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); + 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", encoder_session.inbasefilename, data_bytes); - return EncoderSession_finish_error(&encoder_session); + 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_little_endian_uint16(infile, &x, false, encoder_session.inbasefilename)) - return EncoderSession_finish_error(&encoder_session); + 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", encoder_session.inbasefilename, (unsigned)x); - return EncoderSession_finish_error(&encoder_session); + 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_little_endian_uint16(infile, &x, false, encoder_session.inbasefilename)) - return EncoderSession_finish_error(&encoder_session); - if((unsigned)x > bps) { - flac__utils_printf(stderr, 1, "%s: ERROR: invalid WAVEFORMATEXTENSIBLE chunk with wValidBitsPerSample (%u) > wBitsPerSample (%u)\n", encoder_session.inbasefilename, (unsigned)x, bps); - return EncoderSession_finish_error(&encoder_session); + 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 - (unsigned)x; + shift = bps - (uint32_t)x; /* channel mask */ - if(!read_little_endian_uint32(infile, &channel_mask, false, encoder_session.inbasefilename)) - return EncoderSession_finish_error(&encoder_session); - /* for mono/stereo and unassigned channels, we fake the mask */ - if(channel_mask == 0) { - if(channels == 1) - channel_mask = 0x0001; - else if(channels == 2) - channel_mask = 0x0003; - } - /* set channel mapping */ - /* FLAC order follows SMPTE and WAVEFORMATEXTENSIBLE but with fewer channels, which are: */ - /* front left, front right, center, LFE, back left, back right, surround left, surround right */ - /* the default mapping is sufficient for 1-6 channels and 7-8 are currently unspecified anyway */ -#if 0 - /* @@@ example for dolby/vorbis order, for reference later in case it becomes important */ - if( - options.common.channel_map_none || - channel_mask == 0x0001 || /* 1 channel: (mono) */ - channel_mask == 0x0003 || /* 2 channels: front left, front right */ - channel_mask == 0x0033 || /* 4 channels: front left, front right, back left, back right */ - channel_mask == 0x0603 /* 4 channels: front left, front right, side left, side right */ - ) { - /* keep default channel order */ - } - else if( - channel_mask == 0x0007 || /* 3 channels: front left, front right, front center */ - channel_mask == 0x0037 || /* 5 channels: front left, front right, front center, back left, back right */ - channel_mask == 0x0607 /* 5 channels: front left, front right, front center, side left, side right */ - ) { - /* to dolby order: front left, center, front right [, surround left, surround right ] */ - channel_map[1] = 2; - channel_map[2] = 1; - } - else if( - channel_mask == 0x003f || /* 6 channels: front left, front right, front center, LFE, back left, back right */ - channel_mask == 0x060f /* 6 channels: front left, front right, front center, LFE, side left, side right */ - ) { - /* to dolby order: front left, center, front right, surround left, surround right, LFE */ - channel_map[1] = 2; - channel_map[2] = 1; - channel_map[3] = 5; - channel_map[4] = 3; - channel_map[5] = 4; - } -#else - if( - options.common.channel_map_none || - channel_mask == 0x0001 || /* 1 channel: (mono) */ - channel_mask == 0x0003 || /* 2 channels: front left, front right */ - channel_mask == 0x0007 || /* 3 channels: front left, front right, front center */ - channel_mask == 0x0033 || /* 4 channels: front left, front right, back left, back right */ - channel_mask == 0x0603 || /* 4 channels: front left, front right, side left, side right */ - channel_mask == 0x0037 || /* 5 channels: front left, front right, front center, back left, back right */ - channel_mask == 0x0607 || /* 5 channels: front left, front right, front center, side left, side right */ - channel_mask == 0x003f || /* 6 channels: front left, front right, front center, LFE, back left, back right */ - channel_mask == 0x060f /* 6 channels: front left, front right, front center, LFE, side left, side right */ - ) { - /* keep default channel order */ - } -#endif - else { - flac__utils_printf(stderr, 1, "%s: ERROR: WAVEFORMATEXTENSIBLE chunk with unsupported channel mask=0x%04X\n", encoder_session.inbasefilename, (unsigned)channel_mask); - return EncoderSession_finish_error(&encoder_session); - } - if(!options.common.channel_map_none) { - if(count_channel_mask_bits(channel_mask) < channels) { - flac__utils_printf(stderr, 1, "%s: ERROR: WAVEFORMATEXTENSIBLE chunk: channel mask 0x%04X has unassigned channels (#channels=%u)\n", encoder_session.inbasefilename, (unsigned)channel_mask, channels); - return EncoderSession_finish_error(&encoder_session); - } -#if 0 - /* supporting this is too difficult with channel mapping; e.g. what if mask is 0x003f but #channels=4? - * there would be holes in the order that would have to be filled in, or the mask would have to be - * limited and the logic above rerun to see if it still fits into the FLAC mapping. - */ - else if(count_channel_mask_bits(channel_mask) > channels) - channel_mask = limit_channel_mask(channel_mask, channels); -#else - else if(count_channel_mask_bits(channel_mask) > channels) { - flac__utils_printf(stderr, 1, "%s: ERROR: WAVEFORMATEXTENSIBLE chunk: channel mask 0x%04X has extra bits for non-existant channels (#channels=%u)\n", encoder_session.inbasefilename, (unsigned)channel_mask, channels); - return EncoderSession_finish_error(&encoder_session); - } -#endif + 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_little_endian_uint16(infile, &x, false, encoder_session.inbasefilename)) - return EncoderSession_finish_error(&encoder_session); + 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", encoder_session.inbasefilename, (unsigned)x); - return EncoderSession_finish_error(&encoder_session); + 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; } - if(bps-shift < 4 || bps-shift > 24) { - flac__utils_printf(stderr, 1, "%s: ERROR: unsupported bits-per-sample %u\n", encoder_session.inbasefilename, bps-shift); - return EncoderSession_finish_error(&encoder_session); - } - else if(options.common.sector_align && bps-shift != 16) { - flac__utils_printf(stderr, 1, "%s: ERROR: file has %u bits-per-sample, must be 16 for --sector-align\n", encoder_session.inbasefilename, bps-shift); - return EncoderSession_finish_error(&encoder_session); - } + e->info.bytes_per_wide_sample = channels * (bps / 8); - /* skip any extra data in the fmt sub-chunk */ - if(!fskip_ahead(infile, data_bytes)) { - flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping over extra 'fmt' data\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); + /* 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; } - /* - * now that we know the sample rate, canonicalize the - * --skip string to a number of samples: - */ - flac__utils_canonicalize_skip_until_specification(&options.common.skip_specification, sample_rate); - FLAC__ASSERT(options.common.skip_specification.value.samples >= 0); - encoder_session.skip = (FLAC__uint64)options.common.skip_specification.value.samples; - FLAC__ASSERT(!options.common.sector_align || encoder_session.skip == 0); - got_fmt_chunk = true; } - else if(xx == 0x61746164 && !got_data_chunk && got_fmt_chunk) { /* "data" */ - FLAC__uint64 total_samples_in_input, trim = 0; - FLAC__bool pad = false; - const size_t bytes_per_wide_sample = channels * (bps >> 3); - unsigned data_bytes; + 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(!read_little_endian_uint32(infile, &xx, false, encoder_session.inbasefilename)) - return EncoderSession_finish_error(&encoder_session); - if(options.common.ignore_chunk_sizes) { - FLAC__ASSERT(!options.common.sector_align); - data_bytes = (unsigned)(-(int)bytes_per_wide_sample); /* max out data_bytes; we'll use EOF as signal to stop reading */ - } - else { + if(e->format != FORMAT_WAVE64) { + if(!read_uint32(e->fin, /*big_endian=*/false, &xx, e->inbasefilename)) + return false; data_bytes = xx; - if(0 == data_bytes) { - flac__utils_printf(stderr, 1, "%s: ERROR: 'data' subchunk has size of 0\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); - } - } - pad = (data_bytes & 1U) ? true : false; - - /* *options.common.align_reservoir_samples will be 0 unless --sector-align is used */ - FLAC__ASSERT(options.common.sector_align || *options.common.align_reservoir_samples == 0); - total_samples_in_input = data_bytes / bytes_per_wide_sample + *options.common.align_reservoir_samples; - - /* - * now that we know the input size, canonicalize the - * --until string to an absolute sample number: - */ - if(!canonicalize_until_specification(&options.common.until_specification, encoder_session.inbasefilename, sample_rate, encoder_session.skip, total_samples_in_input)) - return EncoderSession_finish_error(&encoder_session); - encoder_session.until = (FLAC__uint64)options.common.until_specification.value.samples; - FLAC__ASSERT(!options.common.sector_align || encoder_session.until == 0); - - if(encoder_session.skip > 0) { - if(!fskip_ahead(infile, encoder_session.skip * bytes_per_wide_sample)) { - flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping samples\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); - } - } - - data_bytes -= (unsigned)encoder_session.skip * bytes_per_wide_sample; /*@@@ WATCHOUT: 4GB limit */ - if(options.common.ignore_chunk_sizes) { - encoder_session.total_samples_to_encode = 0; - flac__utils_printf(stderr, 2, "(No runtime statistics possible; please wait for encoding to finish...)\n"); - FLAC__ASSERT(0 == encoder_session.until); - } - else { - encoder_session.total_samples_to_encode = total_samples_in_input - encoder_session.skip; - } - if(encoder_session.until > 0) { - trim = total_samples_in_input - encoder_session.until; - FLAC__ASSERT(total_samples_in_input > 0); - FLAC__ASSERT(!options.common.sector_align); - data_bytes -= (unsigned int)trim * bytes_per_wide_sample; - encoder_session.total_samples_to_encode -= trim; - } - if(options.common.sector_align) { - align_remainder = (unsigned)(encoder_session.total_samples_to_encode % 588); - if(options.common.is_last_file) - encoder_session.total_samples_to_encode += (588-align_remainder); /* will pad with zeroes */ - else - encoder_session.total_samples_to_encode -= align_remainder; /* will stop short and carry over to next file */ - } - - /* +44 for the size of the WAV headers; this is just an estimate for the progress indicator and doesn't need to be exact */ - encoder_session.unencoded_size = encoder_session.total_samples_to_encode * bytes_per_wide_sample + 44; - - if(!EncoderSession_init_encoder(&encoder_session, options.common, channel_mask, channels, bps-shift, sample_rate, options.foreign_metadata, /*flac_decoder_data=*/0)) - return EncoderSession_finish_error(&encoder_session); - - /* - * first do any samples in the reservoir - */ - if(options.common.sector_align && *options.common.align_reservoir_samples > 0) { - if(!EncoderSession_process(&encoder_session, (const FLAC__int32 * const *)options.common.align_reservoir, *options.common.align_reservoir_samples)) { - print_error_with_state(&encoder_session, "ERROR during encoding"); - return EncoderSession_finish_error(&encoder_session); - } } - - /* - * decrement the data_bytes counter if we need to align the file - */ - if(options.common.sector_align) { - if(options.common.is_last_file) { - *options.common.align_reservoir_samples = 0; - } - else { - *options.common.align_reservoir_samples = align_remainder; - data_bytes -= (*options.common.align_reservoir_samples) * bytes_per_wide_sample; + 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); } - - /* - * now do from the file - */ - while(data_bytes > 0) { - bytes_read = fread(ucbuffer_, sizeof(unsigned char), min(data_bytes, CHUNK_OF_SAMPLES * bytes_per_wide_sample), infile); - if(bytes_read == 0) { - if(ferror(infile)) { - flac__utils_printf(stderr, 1, "%s: ERROR during read\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); - } - else if(feof(infile)) { - if(options.common.ignore_chunk_sizes) { - flac__utils_printf(stderr, 1, "%s: INFO: hit EOF with --ignore-chunk-sizes, got %u samples\n", encoder_session.inbasefilename, (unsigned)encoder_session.samples_written); - } - else { - flac__utils_printf(stderr, 1, "%s: WARNING: unexpected EOF; expected %u samples, got %u samples\n", encoder_session.inbasefilename, (unsigned)encoder_session.total_samples_to_encode, (unsigned)encoder_session.samples_written); - if(encoder_session.treat_warnings_as_errors) - return EncoderSession_finish_error(&encoder_session); - } - data_bytes = 0; - } - } - else { - if(bytes_read % bytes_per_wide_sample != 0) { - flac__utils_printf(stderr, 1, "%s: ERROR: got partial sample\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); - } - else { - unsigned wide_samples = bytes_read / bytes_per_wide_sample; - if(!format_input(input_, wide_samples, /*is_big_endian=*/false, is_unsigned_samples, channels, bps, shift, channel_map)) - return EncoderSession_finish_error(&encoder_session); - - if(!EncoderSession_process(&encoder_session, (const FLAC__int32 * const *)input_, wide_samples)) { - print_error_with_state(&encoder_session, "ERROR during encoding"); - return EncoderSession_finish_error(&encoder_session); - } - data_bytes -= bytes_read; - } + if(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(trim > 0) { - FLAC__ASSERT(!options.common.sector_align); - if(!fskip_ahead(infile, trim * bytes_per_wide_sample)) { - flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping samples\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); + 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 */ } - - /* - * now read unaligned samples into reservoir or pad with zeroes if necessary - */ - if(options.common.sector_align) { - if(options.common.is_last_file) { - unsigned wide_samples = 588 - align_remainder; - if(wide_samples < 588) { - unsigned channel; - - info_align_zero = wide_samples; - for(channel = 0; channel < channels; channel++) - memset(input_[channel], 0, sizeof(input_[0][0]) * wide_samples); - - if(!EncoderSession_process(&encoder_session, (const FLAC__int32 * const *)input_, wide_samples)) { - print_error_with_state(&encoder_session, "ERROR during encoding"); - return EncoderSession_finish_error(&encoder_session); - } - } - } - else { - if(*options.common.align_reservoir_samples > 0) { - FLAC__ASSERT(CHUNK_OF_SAMPLES >= 588); - bytes_read = fread(ucbuffer_, sizeof(unsigned char), (*options.common.align_reservoir_samples) * bytes_per_wide_sample, infile); - if(bytes_read == 0 && ferror(infile)) { - flac__utils_printf(stderr, 1, "%s: ERROR during read\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); - } - else if(bytes_read != (*options.common.align_reservoir_samples) * bytes_per_wide_sample) { - flac__utils_printf(stderr, 1, "%s: WARNING: unexpected EOF; read %u bytes; expected %u samples, got %u samples\n", encoder_session.inbasefilename, (unsigned)bytes_read, (unsigned)encoder_session.total_samples_to_encode, (unsigned)encoder_session.samples_written); - if(encoder_session.treat_warnings_as_errors) - return EncoderSession_finish_error(&encoder_session); - } - else { - info_align_carry = *options.common.align_reservoir_samples; - if(!format_input(options.common.align_reservoir, *options.common.align_reservoir_samples, /*is_big_endian=*/false, is_unsigned_samples, channels, bps, shift, channel_map)) - return EncoderSession_finish_error(&encoder_session); - } - } - } + else if(0 == data_bytes) { + flac__utils_printf(stderr, 1, "%s: ERROR: 'data' chunk has size of 0\n", e->inbasefilename); + return false; } - if(pad == true) { - unsigned char tmp; - - if(fread(&tmp, 1U, 1U, infile) < 1U) { - flac__utils_printf(stderr, 1, "%s: ERROR during read of data pad byte\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); - } - } + e->fmt.iff.data_bytes = data_bytes; got_data_chunk = true; + break; } else { - if(xx == 0x61746164 && !got_fmt_chunk) { /* "data" */ - flac__utils_printf(stderr, 1, "%s: ERROR: got 'data' sub-chunk before 'fmt' sub-chunk\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); - } - - if(!options.foreign_metadata) { - if(xx == 0x20746d66 && got_fmt_chunk) /* "fmt " */ - flac__utils_printf(stderr, 1, "%s: WARNING: skipping extra 'fmt ' sub-chunk (use --keep-foreign-metadata to keep)\n", encoder_session.inbasefilename); - else if(xx == 0x61746164) /* "data" */ - flac__utils_printf(stderr, 1, "%s: WARNING: skipping extra 'data' sub-chunk (use --keep-foreign-metadata to keep)\n", encoder_session.inbasefilename); + 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 sub-chunk '%c%c%c%c' (use --keep-foreign-metadata to keep)\n", encoder_session.inbasefilename, (char)(xx&255), (char)((xx>>8)&255), (char)((xx>>16)&255), (char)(xx>>24)); - if(encoder_session.treat_warnings_as_errors) - return EncoderSession_finish_error(&encoder_session); + 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; } - /* sub-chunk size */ - if(!read_little_endian_uint32(infile, &xx, false, encoder_session.inbasefilename)) - return EncoderSession_finish_error(&encoder_session); - else { - unsigned long skip = xx+(xx & 1U); - - FLAC__ASSERT(skip<=LONG_MAX); - if(!fskip_ahead(infile, skip)) { - flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping over unsupported sub-chunk\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); + /* 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; } } } } - return EncoderSession_finish_ok(&encoder_session, info_align_carry, info_align_zero, options.foreign_metadata); + 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; } -int flac__encode_raw(FILE *infile, off_t infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, unsigned lookahead_length, raw_encode_options_t options) +static FLAC__bool get_sample_info_aiff(EncoderSession *e, encode_options_t options) { - EncoderSession encoder_session; - size_t bytes_read; - const size_t bytes_per_wide_sample = options.channels * (options.bps >> 3); - unsigned align_remainder = 0; - int info_align_carry = -1, info_align_zero = -1; - FLAC__uint64 total_samples_in_input = 0; - - FLAC__ASSERT(!options.common.sector_align || options.channels == 2); - FLAC__ASSERT(!options.common.sector_align || options.bps == 16); - FLAC__ASSERT(!options.common.sector_align || options.sample_rate == 44100); - FLAC__ASSERT(!options.common.sector_align || infilesize >= 0); - FLAC__ASSERT(!options.common.replay_gain || options.channels <= 2); - FLAC__ASSERT(!options.common.replay_gain || grabbag__replaygain_is_valid_sample_frequency(options.sample_rate)); - - if(! - EncoderSession_construct( - &encoder_session, -#if FLAC__HAS_OGG - options.common.use_ogg, -#else - /*use_ogg=*/false, -#endif - options.common.verify, - options.common.treat_warnings_as_errors, - options.common.continue_through_decode_errors, - infile, - infilename, - outfilename - ) - ) - return 1; + 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; /* - * now that we know the sample rate, canonicalize the - * --skip string to a number of samples: + * lookahead[] already has "FORMxxxxAIFF", do chunks */ - flac__utils_canonicalize_skip_until_specification(&options.common.skip_specification, options.sample_rate); - FLAC__ASSERT(options.common.skip_specification.value.samples >= 0); - encoder_session.skip = (FLAC__uint64)options.common.skip_specification.value.samples; - FLAC__ASSERT(!options.common.sector_align || encoder_session.skip == 0); + 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(infilesize < 0) - total_samples_in_input = 0; - else { - /* *options.common.align_reservoir_samples will be 0 unless --sector-align is used */ - FLAC__ASSERT(options.common.sector_align || *options.common.align_reservoir_samples == 0); - total_samples_in_input = (FLAC__uint64)infilesize / bytes_per_wide_sample + *options.common.align_reservoir_samples; - } + 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); - /* - * now that we know the input size, canonicalize the - * --until strings to a number of samples: - */ - if(!canonicalize_until_specification(&options.common.until_specification, encoder_session.inbasefilename, options.sample_rate, encoder_session.skip, total_samples_in_input)) - return EncoderSession_finish_error(&encoder_session); - encoder_session.until = (FLAC__uint64)options.common.until_specification.value.samples; - FLAC__ASSERT(!options.common.sector_align || encoder_session.until == 0); - - infilesize -= (off_t)encoder_session.skip * bytes_per_wide_sample; - encoder_session.total_samples_to_encode = total_samples_in_input - encoder_session.skip; - if(encoder_session.until > 0) { - const FLAC__uint64 trim = total_samples_in_input - encoder_session.until; - FLAC__ASSERT(total_samples_in_input > 0); - FLAC__ASSERT(!options.common.sector_align); - infilesize -= (off_t)trim * bytes_per_wide_sample; - encoder_session.total_samples_to_encode -= trim; - } - if(infilesize >= 0 && options.common.sector_align) { - FLAC__ASSERT(encoder_session.skip == 0); - align_remainder = (unsigned)(encoder_session.total_samples_to_encode % 588); - if(options.common.is_last_file) - encoder_session.total_samples_to_encode += (588-align_remainder); /* will pad with zeroes */ - else - encoder_session.total_samples_to_encode -= align_remainder; /* will stop short and carry over to next file */ - } - encoder_session.unencoded_size = encoder_session.total_samples_to_encode * bytes_per_wide_sample; + if(got_comm_chunk) { + flac__utils_printf(stderr, 1, "%s: ERROR: file has multiple 'COMM' chunks\n", e->inbasefilename); + return false; + } - if(encoder_session.total_samples_to_encode <= 0) - flac__utils_printf(stderr, 2, "(No runtime statistics possible; please wait for encoding to finish...)\n"); + /* 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); - if(encoder_session.skip > 0) { - unsigned skip_bytes = bytes_per_wide_sample * (unsigned)encoder_session.skip; - if(skip_bytes > lookahead_length) { - skip_bytes -= lookahead_length; - lookahead_length = 0; - if(!fskip_ahead(infile, skip_bytes)) { - flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping samples\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); + /* 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; } - } - else { - lookahead += skip_bytes; - lookahead_length -= skip_bytes; - } - } - if(!EncoderSession_init_encoder(&encoder_session, options.common, /*channel_mask=*/0, options.channels, options.bps, options.sample_rate, /*foreign_metadata=*/0, /*flac_decoder_data=*/0)) - return EncoderSession_finish_error(&encoder_session); + /* number of sample frames */ + if(!read_uint32(e->fin, /*big_endian=*/true, &xx, e->inbasefilename)) + return false; + sample_frames = xx; - /* - * first do any samples in the reservoir - */ - if(options.common.sector_align && *options.common.align_reservoir_samples > 0) { - if(!EncoderSession_process(&encoder_session, (const FLAC__int32 * const *)options.common.align_reservoir, *options.common.align_reservoir_samples)) { - print_error_with_state(&encoder_session, "ERROR during encoding"); - return EncoderSession_finish_error(&encoder_session); - } - } + /* 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; - /* - * decrement infilesize if we need to align the file - */ - if(options.common.sector_align) { - FLAC__ASSERT(infilesize >= 0); - if(options.common.is_last_file) { - *options.common.align_reservoir_samples = 0; - } - else { - *options.common.align_reservoir_samples = align_remainder; - infilesize -= (off_t)((*options.common.align_reservoir_samples) * bytes_per_wide_sample); - FLAC__ASSERT(infilesize >= 0); - } - } + /* sample rate */ + if(!read_sane_extended(e->fin, &xx, e->inbasefilename)) + return false; + sample_rate = xx; - /* - * now do from the file - */ - if(infilesize < 0) { - while(!feof(infile)) { - if(lookahead_length > 0) { - FLAC__ASSERT(lookahead_length < CHUNK_OF_SAMPLES * bytes_per_wide_sample); - memcpy(ucbuffer_, lookahead, lookahead_length); - bytes_read = fread(ucbuffer_+lookahead_length, sizeof(unsigned char), CHUNK_OF_SAMPLES * bytes_per_wide_sample - lookahead_length, infile) + lookahead_length; - if(ferror(infile)) { - flac__utils_printf(stderr, 1, "%s: ERROR during read\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); + /* 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; } - lookahead_length = 0; } - else - bytes_read = fread(ucbuffer_, sizeof(unsigned char), CHUNK_OF_SAMPLES * bytes_per_wide_sample, infile); - if(bytes_read == 0) { - if(ferror(infile)) { - flac__utils_printf(stderr, 1, "%s: ERROR during read\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); - } - } - else if(bytes_read % bytes_per_wide_sample != 0) { - flac__utils_printf(stderr, 1, "%s: ERROR: got partial sample\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); + /* 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 { - unsigned wide_samples = bytes_read / bytes_per_wide_sample; - if(!format_input(input_, wide_samples, options.is_big_endian, options.is_unsigned_samples, options.channels, options.bps, /*shift=*/0, /*channel_map=*/0)) - return EncoderSession_finish_error(&encoder_session); + flac__utils_printf(stderr, 1, "%s: ERROR: unsupported number of channels %u for AIFF\n", e->inbasefilename, channels); + return false; + } - 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); - } + 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 { - const FLAC__uint64 max_input_bytes = infilesize; - FLAC__uint64 total_input_bytes_read = 0; - while(total_input_bytes_read < max_input_bytes) { - { - size_t wanted = (CHUNK_OF_SAMPLES * bytes_per_wide_sample); - wanted = (size_t) min((FLAC__uint64)wanted, max_input_bytes - total_input_bytes_read); - - if(lookahead_length > 0) { - FLAC__ASSERT(lookahead_length <= wanted); - memcpy(ucbuffer_, lookahead, lookahead_length); - wanted -= lookahead_length; - bytes_read = lookahead_length; - if(wanted > 0) { - bytes_read += fread(ucbuffer_+lookahead_length, sizeof(unsigned char), wanted, infile); - if(ferror(infile)) { - flac__utils_printf(stderr, 1, "%s: ERROR during read\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); - } - } - lookahead_length = 0; - } - else - bytes_read = fread(ucbuffer_, sizeof(unsigned char), wanted, infile); + 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; } - if(bytes_read == 0) { - if(ferror(infile)) { - flac__utils_printf(stderr, 1, "%s: ERROR during read\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); - } - else if(feof(infile)) { - flac__utils_printf(stderr, 1, "%s: WARNING: unexpected EOF; expected %u samples, got %u samples\n", encoder_session.inbasefilename, (unsigned)encoder_session.total_samples_to_encode, (unsigned)encoder_session.samples_written); - if(encoder_session.treat_warnings_as_errors) - return EncoderSession_finish_error(&encoder_session); - total_input_bytes_read = max_input_bytes; + /* 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 { - if(bytes_read % bytes_per_wide_sample != 0) { - flac__utils_printf(stderr, 1, "%s: ERROR: got partial sample\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); - } - else { - unsigned wide_samples = bytes_read / bytes_per_wide_sample; - if(!format_input(input_, wide_samples, options.is_big_endian, options.is_unsigned_samples, options.channels, options.bps, /*shift=*/0, /*channel_map=*/0)) - return EncoderSession_finish_error(&encoder_session); + data_bytes -= 8; /* discount the offset and block size fields */ + } - 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; + /* 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; } } - } - } - /* - * now read unaligned samples into reservoir or pad with zeroes if necessary - */ - if(options.common.sector_align) { - if(options.common.is_last_file) { - unsigned wide_samples = 588 - align_remainder; - if(wide_samples < 588) { - unsigned channel; - - info_align_zero = wide_samples; - for(channel = 0; channel < options.channels; channel++) - memset(input_[channel], 0, sizeof(input_[0][0]) * wide_samples); - - if(!EncoderSession_process(&encoder_session, (const FLAC__int32 * const *)input_, wide_samples)) { - print_error_with_state(&encoder_session, "ERROR during encoding"); - return EncoderSession_finish_error(&encoder_session); - } + /* 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 { - if(*options.common.align_reservoir_samples > 0) { - FLAC__ASSERT(CHUNK_OF_SAMPLES >= 588); - bytes_read = fread(ucbuffer_, sizeof(unsigned char), (*options.common.align_reservoir_samples) * bytes_per_wide_sample, infile); - if(bytes_read == 0 && ferror(infile)) { - flac__utils_printf(stderr, 1, "%s: ERROR during read\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); - } - else if(bytes_read != (*options.common.align_reservoir_samples) * bytes_per_wide_sample) { - flac__utils_printf(stderr, 1, "%s: WARNING: unexpected EOF; read %u bytes; expected %u samples, got %u samples\n", encoder_session.inbasefilename, (unsigned)bytes_read, (unsigned)encoder_session.total_samples_to_encode, (unsigned)encoder_session.samples_written); - if(encoder_session.treat_warnings_as_errors) - return EncoderSession_finish_error(&encoder_session); - } - else { - info_align_carry = *options.common.align_reservoir_samples; - if(!format_input(options.common.align_reservoir, *options.common.align_reservoir_samples, options.is_big_endian, options.is_unsigned_samples, options.channels, options.bps, /*shift=*/0, /*channel_map=*/0)) - return EncoderSession_finish_error(&encoder_session); + 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; } } } } - return EncoderSession_finish_ok(&encoder_session, info_align_carry, info_align_zero, /*foreign_metadata=*/0); -} + 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; + } -int flac__encode_flac(FILE *infile, off_t infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, unsigned lookahead_length, flac_encode_options_t options, FLAC__bool input_is_ogg) -{ - EncoderSession encoder_session; - FLAC__StreamDecoder *decoder = 0; - FLACDecoderData decoder_data; - size_t i; - int retval; - - if(! - EncoderSession_construct( - &encoder_session, -#if FLAC__HAS_OGG - options.common.use_ogg, -#else - /*use_ogg=*/false, -#endif - options.common.verify, - options.common.treat_warnings_as_errors, - options.common.continue_through_decode_errors, - infile, - infilename, - outfilename - ) - ) - return 1; + 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; - decoder_data.encoder_session = &encoder_session; - decoder_data.filesize = (infilesize == (off_t)(-1)? 0 : infilesize); - decoder_data.lookahead = lookahead; - decoder_data.lookahead_length = lookahead_length; - decoder_data.num_metadata_blocks = 0; - decoder_data.samples_left_to_process = 0; - decoder_data.fatal_error = false; + return true; +} - /* - * set up FLAC decoder for the input - */ - if (0 == (decoder = FLAC__stream_decoder_new())) { - flac__utils_printf(stderr, 1, "%s: ERROR: creating decoder for FLAC input\n", encoder_session.inbasefilename); - return EncoderSession_finish_error(&encoder_session); - } +static FLAC__bool get_sample_info_flac(EncoderSession *e) +{ if (!( - FLAC__stream_decoder_set_md5_checking(decoder, false) && - FLAC__stream_decoder_set_metadata_respond_all(decoder) + 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", encoder_session.inbasefilename); - goto fubar1; /*@@@ yuck */ + flac__utils_printf(stderr, 1, "%s: ERROR: setting up decoder for FLAC input\n", e->inbasefilename); + return false; } - if (input_is_ogg) { - if (FLAC__stream_decoder_init_ogg_stream(decoder, flac_decoder_read_callback, flac_decoder_seek_callback, flac_decoder_tell_callback, flac_decoder_length_callback, flac_decoder_eof_callback, flac_decoder_write_callback, flac_decoder_metadata_callback, flac_decoder_error_callback, /*client_data=*/&decoder_data) != FLAC__STREAM_DECODER_INIT_STATUS_OK) { - flac__utils_printf(stderr, 1, "%s: ERROR: initializing decoder for Ogg FLAC input, state = %s\n", encoder_session.inbasefilename, FLAC__stream_decoder_get_resolved_state_string(decoder)); - goto fubar1; /*@@@ yuck */ + 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(decoder, flac_decoder_read_callback, flac_decoder_seek_callback, flac_decoder_tell_callback, flac_decoder_length_callback, flac_decoder_eof_callback, flac_decoder_write_callback, flac_decoder_metadata_callback, flac_decoder_error_callback, /*client_data=*/&decoder_data) != FLAC__STREAM_DECODER_INIT_STATUS_OK) { - flac__utils_printf(stderr, 1, "%s: ERROR: initializing decoder for FLAC input, state = %s\n", encoder_session.inbasefilename, FLAC__stream_decoder_get_resolved_state_string(decoder)); - goto fubar1; /*@@@ yuck */ + 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(decoder) || decoder_data.fatal_error) { - if (decoder_data.fatal_error) - flac__utils_printf(stderr, 1, "%s: ERROR: out of memory or too many metadata blocks while reading metadata in FLAC input\n", encoder_session.inbasefilename); + 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", encoder_session.inbasefilename, FLAC__stream_decoder_get_resolved_state_string(decoder)); - goto fubar1; /*@@@ yuck */ + 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 (decoder_data.num_metadata_blocks == 0) { - flac__utils_printf(stderr, 1, "%s: ERROR: reading metadata in FLAC input, got no metadata blocks\n", encoder_session.inbasefilename); - goto fubar2; /*@@@ yuck */ + 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 (decoder_data.metadata_blocks[0]->type != FLAC__METADATA_TYPE_STREAMINFO) { - flac__utils_printf(stderr, 1, "%s: ERROR: reading metadata in FLAC input, first metadata block is not STREAMINFO\n", encoder_session.inbasefilename); - goto fubar2; /*@@@ yuck */ + else if (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 (decoder_data.metadata_blocks[0]->data.stream_info.total_samples == 0) { - flac__utils_printf(stderr, 1, "%s: ERROR: FLAC input has STREAMINFO with unknown total samples which is not supported\n", encoder_session.inbasefilename); - goto fubar2; /*@@@ yuck */ + 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; } - /* - * now that we have the STREAMINFO and know the sample rate, - * canonicalize the --skip string to a number of samples: - */ - flac__utils_canonicalize_skip_until_specification(&options.common.skip_specification, decoder_data.metadata_blocks[0]->data.stream_info.sample_rate); - FLAC__ASSERT(options.common.skip_specification.value.samples >= 0); - encoder_session.skip = (FLAC__uint64)options.common.skip_specification.value.samples; - FLAC__ASSERT(!options.common.sector_align); /* --sector-align with FLAC input is not supported */ + 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, trim = 0; + 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); + } - total_samples_in_input = decoder_data.metadata_blocks[0]->data.stream_info.total_samples; + /* + * 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 know the input size, canonicalize the + * now that we possibly know the input size, canonicalize the * --until string to an absolute sample number: */ - if(!canonicalize_until_specification(&options.common.until_specification, encoder_session.inbasefilename, decoder_data.metadata_blocks[0]->data.stream_info.sample_rate, encoder_session.skip, total_samples_in_input)) - goto fubar2; /*@@@ yuck */ - encoder_session.until = (FLAC__uint64)options.common.until_specification.value.samples; - - encoder_session.total_samples_to_encode = total_samples_in_input - encoder_session.skip; - if(encoder_session.until > 0) { - trim = total_samples_in_input - encoder_session.until; + 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"); + } - encoder_session.unencoded_size = decoder_data.filesize; + 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; - /* (channel mask will get copied over from the source VORBIS_COMMENT if it exists) */ - if(!EncoderSession_init_encoder(&encoder_session, options.common, /*channel_mask=*/0, decoder_data.metadata_blocks[0]->data.stream_info.channels, decoder_data.metadata_blocks[0]->data.stream_info.bits_per_sample, decoder_data.metadata_blocks[0]->data.stream_info.sample_rate, /*foreign_metadata=*/0, &decoder_data)) - goto fubar2; /*@@@ yuck */ + stats_new_file(); + /* init the encoder */ + if(!EncoderSession_init_encoder(&encoder_session, options)) + return EncoderSession_finish_error(&encoder_session); - /* - * have to wait until the FLAC encoder is set up for writing - * before any seeking in the input FLAC file, because the seek - * itself will usually call the decoder's write callback, and - * our decoder's write callback passes samples to our FLAC - * encoder - */ - decoder_data.samples_left_to_process = encoder_session.total_samples_to_encode; - if(encoder_session.skip > 0) { - if(!FLAC__stream_decoder_seek_absolute(decoder, encoder_session.skip)) { - flac__utils_printf(stderr, 1, "%s: ERROR while skipping samples, FLAC decoder state = %s\n", encoder_session.inbasefilename, FLAC__stream_decoder_get_resolved_state_string(decoder)); - goto fubar2; /*@@@ yuck */ + /* 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 */ - while(!decoder_data.fatal_error && decoder_data.samples_left_to_process > 0) { - /* We can also hit the end of stream without samples_left_to_process - * going to 0 if there are errors and continue_through_decode_errors - * is on, so we want to break in that case too: - */ - if(encoder_session.continue_through_decode_errors && FLAC__stream_decoder_get_state(decoder) == FLAC__STREAM_DECODER_END_OF_STREAM) + 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; - if(!FLAC__stream_decoder_process_single(decoder)) { - flac__utils_printf(stderr, 1, "%s: ERROR: while decoding FLAC input, state = %s\n", encoder_session.inbasefilename, FLAC__stream_decoder_get_resolved_state_string(decoder)); - goto fubar2; /*@@@ yuck */ - } - } - if(decoder_data.fatal_error) { - flac__utils_printf(stderr, 1, "%s: ERROR: while decoding FLAC input, state = %s\n", encoder_session.inbasefilename, FLAC__stream_decoder_get_resolved_state_string(decoder)); - goto fubar2; /*@@@ yuck */ + 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); } - } - FLAC__stream_decoder_delete(decoder); - retval = EncoderSession_finish_ok(&encoder_session, -1, -1, /*foreign_metadata=*/0); - /* have to wail until encoder is completely finished before deleting because of the final step of writing the seekpoint offsets */ - for(i = 0; i < decoder_data.num_metadata_blocks; i++) - FLAC__metadata_object_delete(decoder_data.metadata_blocks[i]); - return retval; + } -fubar2: - for(i = 0; i < decoder_data.num_metadata_blocks; i++) - FLAC__metadata_object_delete(decoder_data.metadata_blocks[i]); -fubar1: - FLAC__stream_decoder_delete(decoder); - return EncoderSession_finish_error(&encoder_session); + 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, FLAC__bool use_ogg, FLAC__bool verify, FLAC__bool treat_warnings_as_errors, FLAC__bool continue_through_decode_errors, FILE *infile, const char *infilename, const char *outfilename) +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) { - unsigned i; + uint32_t i; FLAC__uint32 test = 1; /* @@ -1616,13 +1386,11 @@ FLAC__bool EncoderSession_construct(EncoderSession *e, FLAC__bool use_ogg, FLAC_ */ #if FLAC__HAS_OGG - e->use_ogg = use_ogg; -#else - (void)use_ogg; + e->use_ogg = options.use_ogg; #endif - e->verify = verify; - e->treat_warnings_as_errors = treat_warnings_as_errors; - e->continue_through_decode_errors = continue_through_decode_errors; + e->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; @@ -1631,12 +1399,49 @@ FLAC__bool EncoderSession_construct(EncoderSession *e, FLAC__bool use_ogg, FLAC_ e->infilename = infilename; e->outfilename = outfilename; - e->skip = 0; /* filled in later after the sample_rate is known */ - e->unencoded_size = 0; e->total_samples_to_encode = 0; + e->unencoded_size = 0; e->bytes_written = 0; e->samples_written = 0; - e->stats_mask = 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; @@ -1660,6 +1465,16 @@ FLAC__bool EncoderSession_construct(EncoderSession *e, FLAC__bool use_ogg, FLAC_ 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); @@ -1674,7 +1489,7 @@ void EncoderSession_destroy(EncoderSession *e) } } -int EncoderSession_finish_ok(EncoderSession *e, int info_align_carry, int info_align_zero, foreign_metadata_t *foreign_metadata) +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; @@ -1700,14 +1515,6 @@ int EncoderSession_finish_ok(EncoderSession *e, int info_align_carry, int info_a print_verify_error(e); ret = 1; } - else { - if(info_align_carry >= 0) { - flac__utils_printf(stderr, 1, "%s: INFO: sector alignment causing %d samples to be carried over\n", e->inbasefilename, info_align_carry); - } - if(info_align_zero >= 0) { - flac__utils_printf(stderr, 1, "%s: INFO: sector alignment causing %d zero samples to be appended\n", e->inbasefilename, info_align_zero); - } - } /*@@@@@@ should this go here or somewhere else? */ if(ret == 0 && foreign_metadata) { @@ -1718,6 +1525,22 @@ int EncoderSession_finish_ok(EncoderSession *e, int info_align_carry, int info_a } } + 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; @@ -1730,19 +1553,24 @@ int EncoderSession_finish_error(EncoderSession *e) 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) + if(FLAC__stream_encoder_get_state(e->encoder) == FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA) { print_verify_error(e); - else if(e->outputfile_opened) + 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 */ - unlink(e->outfilename); - - EncoderSession_destroy(e); + /* 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 { - unsigned num_metadata; + uint32_t num_metadata; FLAC__bool *needs_delete; FLAC__StreamMetadata **metadata; FLAC__StreamMetadata *cuesheet; /* always needs to be deleted */ @@ -1758,7 +1586,7 @@ static void static_metadata_init(static_metadata_t *m) static void static_metadata_clear(static_metadata_t *m) { - unsigned i; + uint32_t i; for(i = 0; i < m->num_metadata; i++) if(m->needs_delete[i]) FLAC__metadata_object_delete(m->metadata[i]); @@ -1774,10 +1602,10 @@ static void static_metadata_clear(static_metadata_t *m) static FLAC__bool static_metadata_append(static_metadata_t *m, FLAC__StreamMetadata *d, FLAC__bool needs_delete) { void *x; - if(0 == (x = safe_realloc_muladd2_(m->metadata, sizeof(*m->metadata), /*times (*/m->num_metadata, /*+*/1/*)*/))) + 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_muladd2_(m->needs_delete, sizeof(*m->needs_delete), /*times (*/m->num_metadata, /*+*/1/*)*/))) + 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; @@ -1786,12 +1614,16 @@ static FLAC__bool static_metadata_append(static_metadata_t *m, FLAC__StreamMetad return true; } -FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t options, FLAC__uint32 channel_mask, unsigned channels, unsigned bps, unsigned sample_rate, const foreign_metadata_t *foreign_metadata, FLACDecoderData *flac_decoder_data) +FLAC__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; - unsigned num_metadata = 0, i; + 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]; @@ -1801,9 +1633,6 @@ FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t optio static_metadata_init(&static_metadata); e->replay_gain = options.replay_gain; - e->channels = channels; - e->bits_per_sample = bps; - e->sample_rate = sample_rate; apodizations[0] = '\0'; @@ -1824,7 +1653,7 @@ FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t optio } } - if(!parse_cuesheet(&static_metadata.cuesheet, options.cuesheet_filename, e->inbasefilename, is_cdda, e->total_samples_to_encode, e->treat_warnings_as_errors)) + 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)) { @@ -1840,6 +1669,7 @@ FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t optio * metadata as the basis for the encoded file */ { + uint32_t i; /* * first handle pictures: simple append any --pictures * specified. @@ -1869,7 +1699,7 @@ FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t optio if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) vc_found = true; if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_VORBIS_COMMENT && options.vorbis_comment->data.vorbis_comment.num_comments > 0) { - (void) flac__utils_get_channel_mask_tag(flac_decoder_data->metadata_blocks[i], &channel_mask); + (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); @@ -1885,7 +1715,7 @@ FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t optio if((!vc_found || options.vorbis_comment->data.vorbis_comment.num_comments > 0) && flac_decoder_data->num_metadata_blocks < sizeof(flac_decoder_data->metadata_blocks)/sizeof(flac_decoder_data->metadata_blocks[0])) { /* prepend ours */ FLAC__StreamMetadata *vc = FLAC__metadata_object_clone(options.vorbis_comment); - if(0 == vc || (channel_mask && !flac__utils_set_channel_mask_tag(vc, channel_mask))) { + 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; @@ -1916,7 +1746,7 @@ FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t optio } existing_cuesheet_is_bad = true; } - else if(e->total_samples_to_encode != cs->tracks[cs->num_tracks-1].offset) { + 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); @@ -2036,8 +1866,15 @@ FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t optio flac_decoder_data->num_metadata_blocks = j; if(options.padding > 0) p = options.padding; - if(p < 0) - p = e->total_samples_to_encode / e->sample_rate < 20*60? FLAC_ENCODE__DEFAULT_PADDING : FLAC_ENCODE__DEFAULT_PADDING*8; + if(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); @@ -2060,20 +1897,26 @@ FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t optio * 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(channel_mask) { - if(!flac__utils_set_channel_mask_tag(options.vorbis_comment, channel_mask)) { + 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); } - static_metadata_append(&static_metadata, options.vorbis_comment, /*needs_delete=*/false); + 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) { @@ -2086,13 +1929,16 @@ FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t optio } static_metadata_append(&static_metadata, p, /*needs_delete=*/true); static_metadata.metadata[static_metadata.num_metadata-1]->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8 + foreign_metadata->blocks[i].size; -/*fprintf(stderr,"@@@@@@ add PADDING=%u\n",static_metadata.metadata[static_metadata.num_metadata-1]->length);*/ } } if(options.padding != 0) { padding.is_last = false; /* the encoder will set this for us */ padding.type = FLAC__METADATA_TYPE_PADDING; - padding.length = (unsigned)(options.padding>0? options.padding : (e->total_samples_to_encode / e->sample_rate < 20*60? FLAC_ENCODE__DEFAULT_PADDING : FLAC_ENCODE__DEFAULT_PADDING*8)); + 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; @@ -2114,62 +1960,71 @@ FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t optio FLAC__stream_encoder_set_channels(e->encoder, channels); FLAC__stream_encoder_set_bits_per_sample(e->encoder, bps); FLAC__stream_encoder_set_sample_rate(e->encoder, sample_rate); - for(i = 0; i < options.num_compression_settings; i++) { - switch(options.compression_settings[i].type) { + 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[i].value.t_unsigned); + 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[i].value.t_unsigned); + 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[i].value.t_bool); + 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[i].value.t_bool); + 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[i].value.t_string)+2 >= sizeof(apodizations)) { + 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 { - strcat(apodizations, options.compression_settings[i].value.t_string); - strcat(apodizations, ";"); + safe_strncat(apodizations, options.compression_settings[ic].value.t_string, sizeof(apodizations)); + safe_strncat(apodizations, ";", sizeof(apodizations)); } break; case CST_MAX_LPC_ORDER: - FLAC__stream_encoder_set_max_lpc_order(e->encoder, options.compression_settings[i].value.t_unsigned); +#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[i].value.t_unsigned); + FLAC__stream_encoder_set_qlp_coeff_precision(e->encoder, options.compression_settings[ic].value.t_unsigned); break; case CST_DO_QLP_COEFF_PREC_SEARCH: - FLAC__stream_encoder_set_do_qlp_coeff_prec_search(e->encoder, options.compression_settings[i].value.t_bool); +#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[i].value.t_bool); + FLAC__stream_encoder_set_do_escape_coding(e->encoder, options.compression_settings[ic].value.t_bool); break; case CST_DO_EXHAUSTIVE_MODEL_SEARCH: - FLAC__stream_encoder_set_do_exhaustive_model_search(e->encoder, options.compression_settings[i].value.t_bool); +#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[i].value.t_unsigned); + 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[i].value.t_unsigned); + 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[i].value.t_unsigned); + 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); @@ -2182,6 +2037,13 @@ FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t optio } 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) { @@ -2205,20 +2067,22 @@ FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t optio else e->outputfile_opened = true; - e->stats_mask = - (FLAC__stream_encoder_get_do_exhaustive_model_search(e->encoder) && FLAC__stream_encoder_get_do_qlp_coeff_prec_search(e->encoder))? 0x07 : - (FLAC__stream_encoder_get_do_exhaustive_model_search(e->encoder) || FLAC__stream_encoder_get_do_qlp_coeff_prec_search(e->encoder))? 0x0f : - 0x3f; +#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[], unsigned samples) +FLAC__bool EncoderSession_process(EncoderSession *e, const FLAC__int32 * const buffer[], uint32_t samples) { if(e->replay_gain) { - if(!grabbag__replaygain_analyze(buffer, e->channels==2, e->bits_per_sample, samples)) { + 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; @@ -2228,6 +2092,16 @@ FLAC__bool EncoderSession_process(EncoderSession *e, const FLAC__int32 * const b 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; @@ -2236,24 +2110,23 @@ FLAC__bool convert_to_seek_table_template(const char *requested_seek_points, int if(num_requested_seek_points == 0 && 0 == cuesheet) return true; - if(num_requested_seek_points < 0) { #if FLAC__HAS_OGG - /*@@@@@@ workaround ogg bug: too many seekpoints makes table not fit in one page */ - if(e->use_ogg && e->total_samples_to_encode > 0 && e->total_samples_to_encode / e->sample_rate / 10 > 230) - requested_seek_points = "230x;"; - else + if(e->use_ogg) + return true; #endif - requested_seek_points = "10s;"; + + 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->sample_rate, e->seek_table_template, &has_real_points)) + 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) { - unsigned i, j; + 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; @@ -2279,10 +2152,13 @@ FLAC__bool convert_to_seek_table_template(const char *requested_seek_points, int return true; } -FLAC__bool canonicalize_until_specification(utils__SkipUntilSpecification *spec, const char *inbasefilename, unsigned sample_rate, FLAC__uint64 skip, FLAC__uint64 total_samples_in_input) +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 */ - flac__utils_canonicalize_skip_until_specification(spec, sample_rate); + 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) { @@ -2324,11 +2200,11 @@ FLAC__bool canonicalize_until_specification(utils__SkipUntilSpecification *spec, return true; } -FLAC__bool verify_metadata(const EncoderSession *e, FLAC__StreamMetadata **metadata, unsigned num_metadata) +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; - unsigned i; + uint32_t i; FLAC__ASSERT(0 != metadata); for(i = 0; i < num_metadata; i++) { @@ -2371,9 +2247,9 @@ FLAC__bool verify_metadata(const EncoderSession *e, FLAC__StreamMetadata **metad return true; } -FLAC__bool format_input(FLAC__int32 *dest[], unsigned wide_samples, FLAC__bool is_big_endian, FLAC__bool is_unsigned_samples, unsigned channels, unsigned bps, unsigned shift, size_t *channel_map) +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) { - unsigned wide_sample, sample, channel, byte; + uint32_t wide_sample, sample, channel; FLAC__int32 *out[FLAC__MAX_CHANNELS]; if(0 == channel_map) { @@ -2387,67 +2263,130 @@ FLAC__bool format_input(FLAC__int32 *dest[], unsigned wide_samples, FLAC__bool i if(bps == 8) { if(is_unsigned_samples) { - for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) - for(channel = 0; channel < channels; channel++, sample++) - out[channel][wide_sample] = (FLAC__int32)ucbuffer_[sample] - 0x80; + 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(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) - for(channel = 0; channel < channels; channel++, sample++) - out[channel][wide_sample] = (FLAC__int32)scbuffer_[sample]; + 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_big_endian != is_big_endian_host_) { - unsigned char tmp; - const unsigned bytes = wide_samples * channels * (bps >> 3); - for(byte = 0; byte < bytes; byte += 2) { - tmp = ucbuffer_[byte]; - ucbuffer_[byte] = ucbuffer_[byte+1]; - ucbuffer_[byte+1] = tmp; - } - } if(is_unsigned_samples) { - for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) - for(channel = 0; channel < channels; channel++, sample++) - out[channel][wide_sample] = (FLAC__int32)usbuffer_[sample] - 0x8000; + 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 { - for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) - for(channel = 0; channel < channels; channel++, sample++) - out[channel][wide_sample] = (FLAC__int32)ssbuffer_[sample]; + 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) { - unsigned char tmp; - const unsigned bytes = wide_samples * channels * (bps >> 3); - for(byte = 0; byte < bytes; byte += 3) { - tmp = ucbuffer_[byte]; - ucbuffer_[byte] = ucbuffer_[byte+2]; - ucbuffer_[byte+2] = tmp; + if(is_unsigned_samples) { + for(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; + } + } } - } - if(is_unsigned_samples) { - for(byte = sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) - for(channel = 0; channel < channels; channel++, sample++) { - out[channel][wide_sample] = ucbuffer_[byte++]; out[channel][wide_sample] <<= 8; - out[channel][wide_sample] |= ucbuffer_[byte++]; out[channel][wide_sample] <<= 8; - out[channel][wide_sample] |= ucbuffer_[byte++]; - out[channel][wide_sample] -= 0x800000; + else { + for(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 { - for(byte = sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) - for(channel = 0; channel < channels; channel++, sample++) { - out[channel][wide_sample] = scbuffer_[byte++]; out[channel][wide_sample] <<= 8; - out[channel][wide_sample] |= ucbuffer_[byte++]; out[channel][wide_sample] <<= 8; - out[channel][wide_sample] |= ucbuffer_[byte++]; + 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__ASSERT(0); + flac__utils_printf(stderr, 1, "ERROR: unsupported input format\n"); + return false; } if(shift > 0) { FLAC__int32 mask = (1<<shift)-1; @@ -2463,23 +2402,40 @@ FLAC__bool format_input(FLAC__int32 *dest[], unsigned wide_samples, FLAC__bool i return true; } -void encoder_progress_callback(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data) +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 *encoder_session = (EncoderSession*)client_data; + EncoderSession *e = (EncoderSession*)client_data; + + const FLAC__uint64 uesize = e->unencoded_size; - (void)encoder, (void)total_frames_estimate; + (void)encoder, (void)total_frames_estimate, (void) frames_written; - encoder_session->bytes_written = bytes_written; - encoder_session->samples_written = samples_written; + e->bytes_written = bytes_written; + e->samples_written = samples_written; - if(encoder_session->total_samples_to_encode > 0 && !((frames_written-1) & encoder_session->stats_mask)) - print_stats(encoder_session); + 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; - FLACDecoderData *data = (FLACDecoderData*)client_data; + EncoderSession *e = (EncoderSession*)client_data; + FLACDecoderData *data = &e->fmt.flac.client_data; + (void)decoder; if (data->fatal_error) @@ -2496,8 +2452,8 @@ FLAC__StreamDecoderReadStatus flac_decoder_read_callback(const FLAC__StreamDecod /* get the rest from file */ if (*bytes > n) { - *bytes = n + fread(buffer, 1, *bytes-n, data->encoder_session->fin); - if(ferror(data->encoder_session->fin)) + *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; @@ -2510,10 +2466,10 @@ FLAC__StreamDecoderReadStatus flac_decoder_read_callback(const FLAC__StreamDecod FLAC__StreamDecoderSeekStatus flac_decoder_seek_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data) { - FLACDecoderData *data = (FLACDecoderData*)client_data; + EncoderSession *e = (EncoderSession*)client_data; (void)decoder; - if(fseeko(data->encoder_session->fin, (off_t)absolute_byte_offset, SEEK_SET) < 0) + 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; @@ -2521,11 +2477,11 @@ FLAC__StreamDecoderSeekStatus flac_decoder_seek_callback(const FLAC__StreamDecod FLAC__StreamDecoderTellStatus flac_decoder_tell_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) { - FLACDecoderData *data = (FLACDecoderData*)client_data; - off_t pos; + EncoderSession *e = (EncoderSession*)client_data; + FLAC__off_t pos; (void)decoder; - if((pos = ftello(data->encoder_session->fin)) < 0) + if((pos = ftello(e->fin)) < 0) return FLAC__STREAM_DECODER_TELL_STATUS_ERROR; else { *absolute_byte_offset = (FLAC__uint64)pos; @@ -2535,10 +2491,11 @@ FLAC__StreamDecoderTellStatus flac_decoder_tell_callback(const FLAC__StreamDecod FLAC__StreamDecoderLengthStatus flac_decoder_length_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data) { - FLACDecoderData *data = (FLACDecoderData*)client_data; + const EncoderSession *e = (EncoderSession*)client_data; + const FLACDecoderData *data = &e->fmt.flac.client_data; (void)decoder; - if(0 == data->filesize) + if(data->filesize < 0) return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR; else { *stream_length = (FLAC__uint64)data->filesize; @@ -2548,20 +2505,33 @@ FLAC__StreamDecoderLengthStatus flac_decoder_length_callback(const FLAC__StreamD FLAC__bool flac_decoder_eof_callback(const FLAC__StreamDecoder *decoder, void *client_data) { - FLACDecoderData *data = (FLACDecoderData*)client_data; + EncoderSession *e = (EncoderSession*)client_data; (void)decoder; - return feof(data->encoder_session->fin)? true : false; + 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) { - FLACDecoderData *data = (FLACDecoderData*)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; - if(!EncoderSession_process(data->encoder_session, buffer, (unsigned)n)) { - print_error_with_state(data->encoder_session, "ERROR during encoding"); + /* 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; } @@ -2572,7 +2542,8 @@ FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(const FLAC__StreamDec void flac_decoder_metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) { - FLACDecoderData *data = (FLACDecoderData*)client_data; + EncoderSession *e = (EncoderSession*)client_data; + FLACDecoderData *data = &e->fmt.flac.client_data; (void)decoder; if (data->fatal_error) @@ -2589,18 +2560,20 @@ void flac_decoder_metadata_callback(const FLAC__StreamDecoder *decoder, const FL void flac_decoder_error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) { - FLACDecoderData *data = (FLACDecoderData*)client_data; + EncoderSession *e = (EncoderSession*)client_data; + FLACDecoderData *data = &e->fmt.flac.client_data; (void)decoder; - flac__utils_printf(stderr, 1, "%s: ERROR got %s while decoding FLAC input\n", data->encoder_session->inbasefilename, FLAC__StreamDecoderErrorStatusString[status]); - if(!data->encoder_session->continue_through_decode_errors) + 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, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset, FLAC__bool treat_warnings_as_errors) +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; - unsigned last_line_read; + uint32_t last_line_read; const char *error_message; if(0 == cuesheet_filename) @@ -2611,12 +2584,12 @@ FLAC__bool parse_cuesheet(FLAC__StreamMetadata **cuesheet, const char *cuesheet_ return false; } - if(0 == (f = fopen(cuesheet_filename, "r"))) { + 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, is_cdda, lead_out_offset); + *cuesheet = grabbag__cuesheet_parse(f, &error_message, &last_line_read, sample_rate, is_cdda, lead_out_offset); fclose(f); @@ -2641,30 +2614,30 @@ FLAC__bool parse_cuesheet(FLAC__StreamMetadata **cuesheet, const char *cuesheet_ return true; } -void print_stats(const EncoderSession *encoder_session) +static void print_stats(const EncoderSession *encoder_session) { - const FLAC__uint64 samples_written = min(encoder_session->total_samples_to_encode, encoder_session->samples_written); -#if defined _MSC_VER || defined __MINGW32__ - /* with MSVC you have to spoon feed it the casting */ - const double progress = (double)(FLAC__int64)samples_written / (double)(FLAC__int64)encoder_session->total_samples_to_encode; - const double ratio = (double)(FLAC__int64)encoder_session->bytes_written / ((double)(FLAC__int64)encoder_session->unencoded_size * min(1.0, progress)); -#else - const double progress = (double)samples_written / (double)encoder_session->total_samples_to_encode; - const double ratio = (double)encoder_session->bytes_written / ((double)encoder_session->unencoded_size * min(1.0, progress)); -#endif + if(flac__utils_verbosity_ >= 2) { + char ratiostr[16]; - FLAC__ASSERT(encoder_session->total_samples_to_encode > 0); + FLAC__ASSERT(encoder_session->total_samples_to_encode > 0); - if(samples_written == encoder_session->total_samples_to_encode) { - flac__utils_printf(stderr, 2, "\r%s:%s wrote %u bytes, ratio=%0.3f", - encoder_session->inbasefilename, - encoder_session->verify? " Verify OK," : "", - (unsigned)encoder_session->bytes_written, - ratio - ); - } - else { - flac__utils_printf(stderr, 2, "\r%s: %u%% complete, ratio=%0.3f", encoder_session->inbasefilename, (unsigned)floor(progress * 100.0 + 0.5), ratio); + 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); + } } } @@ -2694,7 +2667,12 @@ void print_error_with_init_status(const EncoderSession *e, const char *message, "\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 ); } } @@ -2704,7 +2682,7 @@ void print_error_with_init_status(const EncoderSession *e, const char *message, "The encoding parameters specified do not conform to the FLAC Subset and may not\n" "be streamable or playable in hardware devices. If you really understand the\n" "consequences, you can add --lax to the command-line options to encode with\n" - "these parameters anyway. See http://flac.sourceforge.net/format.html#subset\n" + "these parameters anyway. See http://xiph.org/flac/format.html#subset\n" ); } } @@ -2732,33 +2710,33 @@ void print_error_with_state(const EncoderSession *e, const char *message) void print_verify_error(EncoderSession *e) { FLAC__uint64 absolute_sample; - unsigned frame_number; - unsigned channel; - unsigned 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=%u, frame=%u, channel=%u, sample=%u, expected %d, got %d\n", (unsigned)absolute_sample, frame_number, channel, sample, expected, got); + flac__utils_printf(stderr, 1, " 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://flac.sourceforge.net/faq.html#tools__hardware_prob\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://sourceforge.net/bugs/?func=addbug&group_id=13478\n"); + 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_little_endian_uint16(FILE *f, FLAC__uint16 *val, FLAC__bool eof_ok, const char *fn) +FLAC__bool read_bytes(FILE *f, FLAC__byte *buf, size_t n, FLAC__bool eof_ok, const char *fn) { - size_t bytes_read = fread(val, 1, 2, f); + size_t bytes_read = fread(buf, 1, n, f); if(bytes_read == 0) { if(!eof_ok) { @@ -2768,148 +2746,102 @@ FLAC__bool read_little_endian_uint16(FILE *f, FLAC__uint16 *val, FLAC__bool eof_ else return true; } - else if(bytes_read < 2) { + if(bytes_read < n) { flac__utils_printf(stderr, 1, "%s: ERROR: unexpected EOF\n", fn); return false; } - else { - if(is_big_endian_host_) { - FLAC__byte tmp, *b = (FLAC__byte*)val; - tmp = b[1]; b[1] = b[0]; b[0] = tmp; - } - return true; - } + return true; } -FLAC__bool read_little_endian_uint32(FILE *f, FLAC__uint32 *val, FLAC__bool eof_ok, const char *fn) +FLAC__bool read_uint16(FILE *f, FLAC__bool big_endian, FLAC__uint16 *val, const char *fn) { - size_t bytes_read = fread(val, 1, 4, f); - - if(bytes_read == 0) { - if(!eof_ok) { - flac__utils_printf(stderr, 1, "%s: ERROR: unexpected EOF\n", fn); - return false; - } - else - return true; - } - else if(bytes_read < 4) { - flac__utils_printf(stderr, 1, "%s: ERROR: unexpected EOF\n", fn); + 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; } - else { - if(is_big_endian_host_) { - FLAC__byte tmp, *b = (FLAC__byte*)val; - tmp = b[3]; b[3] = b[0]; b[0] = tmp; - tmp = b[2]; b[2] = b[1]; b[1] = tmp; - } - return true; - } + return true; } -FLAC__bool read_big_endian_uint16(FILE *f, FLAC__uint16 *val, FLAC__bool eof_ok, const char *fn) +FLAC__bool read_uint32(FILE *f, FLAC__bool big_endian, FLAC__uint32 *val, const char *fn) { - unsigned char buf[4]; - size_t bytes_read= fread(buf, 1, 2, f); - - if(bytes_read==0U && eof_ok) - return true; - else if(bytes_read<2U) { - flac__utils_printf(stderr, 1, "%s: ERROR: unexpected EOF\n", fn); + 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; } - - /* this is independent of host endianness */ - *val= (FLAC__uint16)(buf[0])<<8 | buf[1]; - return true; } -FLAC__bool read_big_endian_uint32(FILE *f, FLAC__uint32 *val, FLAC__bool eof_ok, const char *fn) +FLAC__bool read_uint64(FILE *f, FLAC__bool big_endian, FLAC__uint64 *val, const char *fn) { - unsigned char buf[4]; - size_t bytes_read= fread(buf, 1, 4, f); - - if(bytes_read==0U && eof_ok) - return true; - else if(bytes_read<4U) { - flac__utils_printf(stderr, 1, "%s: ERROR: unexpected EOF\n", fn); + 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; } - - /* this is independent of host endianness */ - *val= (FLAC__uint32)(buf[0])<<24 | (FLAC__uint32)(buf[1])<<16 | - (FLAC__uint32)(buf[2])<<8 | buf[3]; - return true; } -FLAC__bool read_sane_extended(FILE *f, FLAC__uint32 *val, FLAC__bool eof_ok, const char *fn) +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' and 'eof_ok' is - * false, or if the value is negative, between zero and one, or too large to be - * represented by 'val'; return true otherwise. + * 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. */ { - unsigned int i; - unsigned char buf[10]; - size_t bytes_read= fread(buf, 1U, 10U, f); - FLAC__int16 e= ((FLAC__uint16)(buf[0])<<8 | (FLAC__uint16)(buf[1]))-0x3FFF; - FLAC__int16 shift= 63-e; - FLAC__uint64 p= 0U; - - if(bytes_read==0U && eof_ok) - return true; - else if(bytes_read<10U) { - flac__utils_printf(stderr, 1, "%s: ERROR: unexpected EOF\n", fn); + 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; - } - else if((buf[0]>>7)==1U || e<0 || e>63) { + 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= 0U; i<8U; ++i) - p|= (FLAC__uint64)(buf[i+2])<<(56U-i*8); - *val= (FLAC__uint32)((p>>shift)+(p>>(shift-1) & 0x1)); + 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 unsigned char dump[8192]; - -#ifdef _MSC_VER - if(f == stdin) { - /* MS' stdio impl can't even seek forward on stdin, have to use pure non-fseek() version: */ - while(offset > 0) { - const long need = (long)min(offset, sizeof(dump)); - if((long)fread(dump, 1, need, f) < need) - return false; - offset -= need; - } - } - else -#endif + static uint8_t dump[8192]; + struct flac_stat_s stb; + + if(flac_fstat(fileno(f), &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFREG) { - while(offset > 0) { - long need = (long)min(offset, LONG_MAX); - if(fseeko(f, need, SEEK_CUR) < 0) { - need = (long)min(offset, sizeof(dump)); - if((long)fread(dump, 1, need, f) < need) - return false; - } - offset -= need; - } + 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; } -unsigned count_channel_mask_bits(FLAC__uint32 mask) +uint32_t count_channel_mask_bits(FLAC__uint32 mask) { - unsigned count = 0; + uint32_t count = 0; while(mask) { if(mask & 1) count++; @@ -2918,19 +2850,3 @@ unsigned count_channel_mask_bits(FLAC__uint32 mask) return count; } -#if 0 -FLAC__uint32 limit_channel_mask(FLAC__uint32 mask, unsigned channels) -{ - FLAC__uint32 x = 0x80000000; - unsigned count = count_channel_mask_bits(mask); - while(x && count > channels) { - if(mask & x) { - mask &= ~x; - count--; - } - x >>= 1; - } - FLAC__ASSERT(count_channel_mask_bits(mask) == channels); - return mask; -} -#endif diff --git a/3rdparty/libflac/src/flac/encode.h b/3rdparty/libflac/src/flac/encode.h index 13ee7d39a02..2d65c506899 100644 --- a/3rdparty/libflac/src/flac/encode.h +++ b/3rdparty/libflac/src/flac/encode.h @@ -1,5 +1,6 @@ /* flac - Command-line FLAC encoder/decoder - * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson + * 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 @@ -11,21 +12,22 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * You 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 -#if HAVE_CONFIG_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; @@ -74,19 +76,33 @@ typedef struct { FLAC__bool cued_seekpoints; FLAC__bool channel_map_none; /* --channel-map=none specified, eventually will expand to take actual channel map */ - /* options related to --replay-gain and --sector-align */ FLAC__bool is_first_file; FLAC__bool is_last_file; - FLAC__int32 **align_reservoir; - unsigned *align_reservoir_samples; FLAC__bool replay_gain; FLAC__bool ignore_chunk_sizes; - FLAC__bool sector_align; + FLAC__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; @@ -95,28 +111,6 @@ typedef struct { } debug; } encode_options_t; -typedef struct { - encode_options_t common; - foreign_metadata_t *foreign_metadata; /* NULL unless --keep-foreign-metadata requested */ -} wav_encode_options_t; - -typedef struct { - encode_options_t common; - - FLAC__bool is_big_endian; - FLAC__bool is_unsigned_samples; - unsigned channels; - unsigned bps; - unsigned sample_rate; -} raw_encode_options_t; - -typedef struct { - encode_options_t common; -} flac_encode_options_t; - -int flac__encode_aif(FILE *infile, off_t infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, unsigned lookahead_length, wav_encode_options_t options, FLAC__bool is_aifc); -int flac__encode_wav(FILE *infile, off_t infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, unsigned lookahead_length, wav_encode_options_t options); -int flac__encode_raw(FILE *infile, off_t infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, unsigned lookahead_length, raw_encode_options_t options); -int flac__encode_flac(FILE *infile, off_t infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, unsigned lookahead_length, flac_encode_options_t options, FLAC__bool input_is_ogg); +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/3rdparty/libflac/src/flac/flac.dsp b/3rdparty/libflac/src/flac/flac.dsp deleted file mode 100644 index ae2ad597d00..00000000000 --- a/3rdparty/libflac/src/flac/flac.dsp +++ /dev/null @@ -1,156 +0,0 @@ -# Microsoft Developer Studio Project File - Name="flac" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=flac - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "flac.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "flac.mak" CFG="flac - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "flac - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "flac - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "flac - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "..\..\obj\release\bin" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c -# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "..\..\include" /D "NDEBUG" /D "FLAC__NO_DLL" /D "FLAC__HAS_OGG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /c -# SUBTRACT CPP /YX /Yc /Yu -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 ..\..\obj\release\lib\grabbag_static.lib ..\..\obj\release\lib\libFLAC_static.lib ..\..\obj\release\lib\replaygain_analysis_static.lib ..\..\obj\release\lib\replaygain_synthesis_static.lib ..\..\obj\release\lib\getopt_static.lib ..\..\obj\release\lib\utf8_static.lib ..\..\obj\release\lib\ogg_static.lib /nologo /subsystem:console /machine:I386 - -!ELSEIF "$(CFG)" == "flac - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "..\..\obj\debug\bin" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "." /I "..\..\include" /D "_DEBUG" /D "DEBUG" /D "FLAC__NO_DLL" /D "FLAC__HAS_OGG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c -# SUBTRACT CPP /YX /Yc /Yu -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 ..\..\obj\debug\lib\grabbag_static.lib ..\..\obj\debug\lib\libFLAC_static.lib ..\..\obj\debug\lib\replaygain_analysis_static.lib ..\..\obj\debug\lib\replaygain_synthesis_static.lib ..\..\obj\debug\lib\getopt_static.lib ..\..\obj\debug\lib\utf8_static.lib ..\..\obj\release\lib\ogg_static.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "flac - Win32 Release" -# Name "flac - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=.\analyze.c -# End Source File -# Begin Source File - -SOURCE=.\decode.c -# End Source File -# Begin Source File - -SOURCE=.\encode.c -# End Source File -# Begin Source File - -SOURCE=.\foreign_metadata.c -# End Source File -# Begin Source File - -SOURCE=.\main.c -# End Source File -# Begin Source File - -SOURCE=.\local_string_utils.c -# End Source File -# Begin Source File - -SOURCE=.\utils.c -# End Source File -# Begin Source File - -SOURCE=.\vorbiscomment.c -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# Begin Source File - -SOURCE=.\analyze.h -# End Source File -# Begin Source File - -SOURCE=.\decode.h -# End Source File -# Begin Source File - -SOURCE=.\encode.h -# End Source File -# Begin Source File - -SOURCE=.\foreign_metadata.h -# End Source File -# Begin Source File - -SOURCE=.\local_string_utils.h -# End Source File -# Begin Source File - -SOURCE=.\utils.h -# End Source File -# Begin Source File - -SOURCE=.\vorbiscomment.h -# End Source File -# End Group -# End Target -# End Project diff --git a/3rdparty/libflac/src/flac/flac.vcproj b/3rdparty/libflac/src/flac/flac.vcproj deleted file mode 100644 index 0680364335e..00000000000 --- a/3rdparty/libflac/src/flac/flac.vcproj +++ /dev/null @@ -1,260 +0,0 @@ -<?xml version="1.0" encoding="Windows-1252"?> -<VisualStudioProject - ProjectType="Visual C++" - Version="8.00" - Name="flac" - ProjectGUID="{4cefbc7d-c215-11db-8314-0800200c9a66}" - RootNamespace="flac" - Keyword="Win32Proj" - > - <Platforms> - <Platform - Name="Win32" - /> - </Platforms> - <ToolFiles> - </ToolFiles> - <Configurations> - <Configuration - Name="Debug|Win32" - OutputDirectory="..\..\obj\debug\bin" - IntermediateDirectory="Debug" - ConfigurationType="1" - > - <Tool - Name="VCPreBuildEventTool" - /> - <Tool - Name="VCCustomBuildTool" - /> - <Tool - Name="VCXMLDataGeneratorTool" - /> - <Tool - Name="VCWebServiceProxyGeneratorTool" - /> - <Tool - Name="VCMIDLTool" - /> - <Tool - Name="VCCLCompilerTool" - Optimization="0" - AdditionalIncludeDirectories=".;..\..\include" - PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL;DEBUG" - MinimalRebuild="true" - BasicRuntimeChecks="3" - RuntimeLibrary="1" - UsePrecompiledHeader="0" - WarningLevel="3" - Detect64BitPortabilityProblems="true" - DebugInformationFormat="4" - CompileAs="0" - DisableSpecificWarnings="4267;4996" - /> - <Tool - Name="VCManagedResourceCompilerTool" - /> - <Tool - Name="VCResourceCompilerTool" - /> - <Tool - Name="VCPreLinkEventTool" - /> - <Tool - Name="VCLinkerTool" - AdditionalDependencies="..\..\obj\release\lib\ogg_static.lib" - LinkIncremental="2" - IgnoreDefaultLibraryNames="uuid.lib" - GenerateDebugInformation="true" - SubSystem="1" - TargetMachine="1" - /> - <Tool - Name="VCALinkTool" - /> - <Tool - Name="VCManifestTool" - /> - <Tool - Name="VCXDCMakeTool" - /> - <Tool - Name="VCBscMakeTool" - /> - <Tool - Name="VCFxCopTool" - /> - <Tool - Name="VCAppVerifierTool" - /> - <Tool - Name="VCWebDeploymentTool" - /> - <Tool - Name="VCPostBuildEventTool" - /> - </Configuration> - <Configuration - Name="Release|Win32" - OutputDirectory="..\..\obj\release\bin" - IntermediateDirectory="Release" - ConfigurationType="1" - > - <Tool - Name="VCPreBuildEventTool" - /> - <Tool - Name="VCCustomBuildTool" - /> - <Tool - Name="VCXMLDataGeneratorTool" - /> - <Tool - Name="VCWebServiceProxyGeneratorTool" - /> - <Tool - Name="VCMIDLTool" - /> - <Tool - Name="VCCLCompilerTool" - EnableIntrinsicFunctions="true" - FavorSizeOrSpeed="1" - OmitFramePointers="true" - WholeProgramOptimization="true" - AdditionalIncludeDirectories=".;..\..\include" - PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL" - RuntimeLibrary="0" - BufferSecurityCheck="false" - UsePrecompiledHeader="0" - WarningLevel="3" - Detect64BitPortabilityProblems="true" - DebugInformationFormat="3" - CompileAs="0" - DisableSpecificWarnings="4267;4996" - /> - <Tool - Name="VCManagedResourceCompilerTool" - /> - <Tool - Name="VCResourceCompilerTool" - /> - <Tool - Name="VCPreLinkEventTool" - /> - <Tool - Name="VCLinkerTool" - AdditionalDependencies="..\..\obj\release\lib\ogg_static.lib" - LinkIncremental="1" - IgnoreDefaultLibraryNames="uuid.lib" - GenerateDebugInformation="true" - SubSystem="1" - OptimizeReferences="2" - EnableCOMDATFolding="2" - LinkTimeCodeGeneration="1" - TargetMachine="1" - /> - <Tool - Name="VCALinkTool" - /> - <Tool - Name="VCManifestTool" - /> - <Tool - Name="VCXDCMakeTool" - /> - <Tool - Name="VCBscMakeTool" - /> - <Tool - Name="VCFxCopTool" - /> - <Tool - Name="VCAppVerifierTool" - /> - <Tool - Name="VCWebDeploymentTool" - /> - <Tool - Name="VCPostBuildEventTool" - /> - </Configuration> - </Configurations> - <References> - </References> - <Files> - <Filter - Name="Header Files" - Filter="h;hpp;hxx;hm;inl;inc;xsd" - UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" - > - <File - RelativePath=".\analyze.h" - > - </File> - <File - RelativePath=".\decode.h" - > - </File> - <File - RelativePath=".\encode.h" - > - </File> - <File - RelativePath=".\foreign_metadata.h" - > - </File> - <File - RelativePath=".\local_string_utils.h" - > - </File> - <File - RelativePath=".\utils.h" - > - </File> - <File - RelativePath=".\vorbiscomment.h" - > - </File> - </Filter> - <Filter - Name="Source Files" - Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" - UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" - > - <File - RelativePath=".\analyze.c" - > - </File> - <File - RelativePath=".\decode.c" - > - </File> - <File - RelativePath=".\encode.c" - > - </File> - <File - RelativePath=".\foreign_metadata.c" - > - </File> - <File - RelativePath=".\local_string_utils.c" - > - </File> - <File - RelativePath=".\main.c" - > - </File> - <File - RelativePath=".\utils.c" - > - </File> - <File - RelativePath=".\vorbiscomment.c" - > - </File> - </Filter> - </Files> - <Globals> - </Globals> -</VisualStudioProject> diff --git a/3rdparty/libflac/src/flac/foreign_metadata.c b/3rdparty/libflac/src/flac/foreign_metadata.c index 3fc5310bbf4..f63fc3e60a5 100644 --- a/3rdparty/libflac/src/flac/foreign_metadata.c +++ b/3rdparty/libflac/src/flac/foreign_metadata.c @@ -1,5 +1,6 @@ /* flac - Command-line FLAC encoder/decoder - * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson + * 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 @@ -11,28 +12,22 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * You 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 HAVE_CONFIG_H +#ifdef HAVE_CONFIG_H # include <config.h> #endif -#if defined _MSC_VER || defined __MINGW32__ -#include <sys/types.h> /* for off_t */ -#if _MSC_VER <= 1600 /* @@@ [2G limit] */ -#define fseeko fseek -#define ftello ftell -#endif -#endif #include <stdio.h> /* for FILE etc. */ #include <stdlib.h> /* for calloc() etc. */ #include <string.h> /* for memcmp() etc. */ #include "FLAC/assert.h" #include "FLAC/metadata.h" #include "share/alloc.h" +#include "share/compat.h" #include "foreign_metadata.h" #ifdef min @@ -40,8 +35,7 @@ #endif #define min(x,y) ((x)<(y)?(x):(y)) - -static const char *FLAC__FOREIGN_METADATA_APPLICATION_ID[2] = { "aiff" , "riff" }; +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) { @@ -53,9 +47,15 @@ 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) { - static FLAC__byte buffer[4096]; + FLAC__byte buffer[4096]; size_t left; for(left = size; left > 0; ) { size_t need = min(sizeof(buffer), left); @@ -72,9 +72,39 @@ static FLAC__bool copy_data_(FILE *fin, FILE *fout, size_t size, const char **er return true; } -static FLAC__bool append_block_(foreign_metadata_t *fm, off_t offset, FLAC__uint32 size, const char **error) +/* 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) { - foreign_block_t *fb = safe_realloc_muladd2_(fm->blocks, sizeof(foreign_block_t), /*times (*/fm->num_blocks, /*+*/1/*)*/); + 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; @@ -89,7 +119,7 @@ static FLAC__bool append_block_(foreign_metadata_t *fm, off_t offset, FLAC__uint static FLAC__bool read_from_aiff_(foreign_metadata_t *fm, FILE *f, const char **error) { FLAC__byte buffer[12]; - off_t offset, eof_offset; + FLAC__off_t offset, eof_offset; if((offset = ftello(f)) < 0) { if(error) *error = "ftello() error (001)"; return false; @@ -100,7 +130,7 @@ static FLAC__bool read_from_aiff_(foreign_metadata_t *fm, FILE *f, const char ** } if(!append_block_(fm, offset, 12, error)) return false; - eof_offset = 8 + unpack32be_(buffer+4); + eof_offset = (FLAC__off_t)8 + (FLAC__off_t)unpack32be_(buffer+4); while(!feof(f)) { FLAC__uint32 size; if((offset = ftello(f)) < 0) { @@ -148,9 +178,15 @@ static FLAC__bool read_from_aiff_(foreign_metadata_t *fm, FILE *f, const char ** 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; @@ -174,20 +210,30 @@ static FLAC__bool read_from_aiff_(foreign_metadata_t *fm, FILE *f, const char ** static FLAC__bool read_from_wave_(foreign_metadata_t *fm, FILE *f, const char **error) { FLAC__byte buffer[12]; - off_t offset, eof_offset; + 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+8, "WAVE", 4)) { + 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; - eof_offset = 8 + unpack32le_(buffer+4); + 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__uint32 size; + FLAC__off_t size; if((offset = ftello(f)) < 0) { if(error) *error = "ftello() error (003)"; return false; @@ -223,14 +269,77 @@ static FLAC__bool read_from_wave_(foreign_metadata_t *fm, FILE *f, const char ** 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; - if(fseeko(f, size, SEEK_CUR) < 0) { - if(error) *error = "invalid WAVE file: seek error (009)"; - 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; @@ -246,10 +355,98 @@ static FLAC__bool read_from_wave_(foreign_metadata_t *fm, FILE *f, const char ** 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 unsigned ID_LEN = FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8; + 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) { @@ -304,9 +501,10 @@ static FLAC__bool write_to_flac_(foreign_metadata_t *fm, FILE *fin, FILE *fout, static FLAC__bool read_from_flac_(foreign_metadata_t *fm, FILE *f, FLAC__Metadata_SimpleIterator *it, const char **error) { - FLAC__byte id[4], buffer[12]; - off_t offset; - FLAC__bool type_found = false; + FLAC__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); @@ -314,29 +512,54 @@ static FLAC__bool read_from_flac_(foreign_metadata_t *fm, FILE *f, FLAC__Metadat if(FLAC__metadata_simple_iterator_get_block_type(it) != FLAC__METADATA_TYPE_APPLICATION) continue; if(!FLAC__metadata_simple_iterator_get_application_id(it, id)) { - if(error) *error = "FLAC__metadata_simple_iterator_get_application_id() error (003)"; + if(error) *error = "FLAC__metadata_simple_iterator_get_application_id() error (002)"; return false; } - if(memcmp(id, FLAC__FOREIGN_METADATA_APPLICATION_ID[fm->type], sizeof(id))) + 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(fseek(f, offset, SEEK_SET) < 0) { - if(error) *error = "seek error (004)"; + 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 (005)"; + if(error) *error = "read error (004)"; return false; } - if(fm->num_blocks == 0) { - if(fm->type == FOREIGN_BLOCK_TYPE__RIFF && 0 == memcmp(buffer, "RIFF", 4)) + 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)) + 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; @@ -359,6 +582,11 @@ static FLAC__bool read_from_flac_(foreign_metadata_t *fm, FILE *f, FLAC__Metadat 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) { @@ -371,32 +599,71 @@ static FLAC__bool read_from_flac_(foreign_metadata_t *fm, FILE *f, FLAC__Metadat } 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 (011)"; + 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 (012)"; + 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 (013)"; + 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 (014)"; + 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 (015)"; + if(error) *error = "read error (020)"; return false; } fm->ssnd_offset_size = unpack32be_(buffer+8); @@ -405,64 +672,126 @@ static FLAC__bool read_from_flac_(foreign_metadata_t *fm, FILE *f, FLAC__Metadat else { FLAC__ASSERT(0); /* double protection: */ - if(error) *error = "unsupported foreign metadata found, may need newer FLAC decoder (016)"; + 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(!type_found) { - if(error) *error = "no foreign metadata found (017)"; + 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 (018)" : "invalid AIFF file: missing \"COMM\" chunk (018)"; + 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 (019)" : "invalid AIFF file: missing \"SSND\" chunk (019)"; + 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, off_t offset1, off_t offset2, off_t offset3, const char **error) +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 (002)"; + if(error) *error = "seek failed in WAVE/AIFF file"; return false; } - for(i = 1; i < fm->format_block; i++) { + + /* 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 (003)"; + if(error) *error = "seek failed in FLAC file"; return false; } - if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in WAVE/AIFF file (004)", "write failed in FLAC file (005)")) + 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 (007)"; + if(error) *error = "seek failed in FLAC file"; return false; } - if(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in WAVE/AIFF file (008)", "write failed in FLAC file (009)")) + 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 (010)"; + 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 (011)"; + 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(!copy_data_(fin, fout, fm->blocks[i].size, error, "read failed in WAVE/AIFF file (012)", "write failed in FLAC file (013)")) + 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; @@ -470,9 +799,12 @@ static FLAC__bool write_to_iff_(foreign_metadata_t *fm, FILE *fin, FILE *fout, o foreign_metadata_t *flac__foreign_metadata_new(foreign_block_type_t type) { - foreign_metadata_t *x = (foreign_metadata_t*)calloc(sizeof(foreign_metadata_t), 1); - if(x) + /* 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; } @@ -488,7 +820,7 @@ 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 ok; - FILE *f = fopen(filename, "rb"); + FILE *f = flac_fopen(filename, "rb"); if(!f) { if(error) *error = "can't open AIFF file for reading (000)"; return false; @@ -501,7 +833,7 @@ FLAC__bool flac__foreign_metadata_read_from_aiff(foreign_metadata_t *fm, const c FLAC__bool flac__foreign_metadata_read_from_wave(foreign_metadata_t *fm, const char *filename, const char **error) { FLAC__bool ok; - FILE *f = fopen(filename, "rb"); + FILE *f = flac_fopen(filename, "rb"); if(!f) { if(error) *error = "can't open WAVE file for reading (000)"; return false; @@ -511,6 +843,19 @@ FLAC__bool flac__foreign_metadata_read_from_wave(foreign_metadata_t *fm, const c 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; @@ -525,12 +870,12 @@ FLAC__bool flac__foreign_metadata_write_to_flac(foreign_metadata_t *fm, const ch FLAC__metadata_simple_iterator_delete(it); return false; } - if(0 == (fin = fopen(infilename, "rb"))) { + 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 = fopen(outfilename, "r+b"))) { + 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); @@ -557,7 +902,7 @@ FLAC__bool flac__foreign_metadata_read_from_flac(foreign_metadata_t *fm, const c FLAC__metadata_simple_iterator_delete(it); return false; } - if(0 == (f = fopen(filename, "rb"))) { + 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; @@ -568,15 +913,15 @@ FLAC__bool flac__foreign_metadata_read_from_flac(foreign_metadata_t *fm, const c return ok; } -FLAC__bool flac__foreign_metadata_write_to_iff(foreign_metadata_t *fm, const char *infilename, const char *outfilename, off_t offset1, off_t offset2, off_t offset3, const char **error) +FLAC__bool 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 = fopen(infilename, "rb"))) { + if(0 == (fin = flac_fopen(infilename, "rb"))) { if(error) *error = "can't open FLAC file for reading (000)"; return false; } - if(0 == (fout = fopen(outfilename, "r+b"))) { + if(0 == (fout = flac_fopen(outfilename, "r+b"))) { if(error) *error = "can't open WAVE/AIFF file for updating (001)"; fclose(fin); return false; @@ -586,3 +931,22 @@ FLAC__bool flac__foreign_metadata_write_to_iff(foreign_metadata_t *fm, const cha 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/3rdparty/libflac/src/flac/foreign_metadata.h b/3rdparty/libflac/src/flac/foreign_metadata.h index baeda20e9cd..fa68d46f5d9 100644 --- a/3rdparty/libflac/src/flac/foreign_metadata.h +++ b/3rdparty/libflac/src/flac/foreign_metadata.h @@ -1,5 +1,6 @@ /* flac - Command-line FLAC encoder/decoder - * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson + * 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 @@ -11,37 +12,58 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * You 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 -#if HAVE_CONFIG_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, FOREIGN_BLOCK_TYPE__RIFF = 1 } foreign_block_type_t; +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 */ - off_t offset; + 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 (an maybe never will) */ + 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; @@ -51,9 +73,11 @@ 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, off_t offset1, off_t offset2, off_t offset3, 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/3rdparty/libflac/src/flac/iffscan.c b/3rdparty/libflac/src/flac/iffscan.c index d03b65bc8b9..a5472e0c0cf 100644 --- a/3rdparty/libflac/src/flac/iffscan.c +++ b/3rdparty/libflac/src/flac/iffscan.c @@ -1,5 +1,6 @@ /* iffscan - Simple AIFF/RIFF chunk scanner - * Copyright (C) 2007 Josh Coalson + * 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 @@ -11,25 +12,19 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * You 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 HAVE_CONFIG_H +#ifdef HAVE_CONFIG_H # include <config.h> #endif #include <stdio.h> #include <stdlib.h> #include <string.h> -#if defined _MSC_VER || defined __MINGW32__ -#include <sys/types.h> /* for off_t */ -#if _MSC_VER <= 1600 /* @@@ [2G limit] */ -#define fseeko fseek -#define ftello ftell -#endif -#endif +#include "share/compat.h" #include "foreign_metadata.h" static FLAC__uint32 unpack32be_(const FLAC__byte *b) @@ -42,6 +37,11 @@ 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) @@ -53,57 +53,74 @@ static FLAC__uint32 unpack32_(const FLAC__byte *b, foreign_block_type_t type) int main(int argc, char *argv[]) { FILE *f; - char buf[12]; + 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) { - fprintf(stderr, "usage: %s { file.wav | file.aif }\n", argv[0]); + flac_fprintf(stderr, "usage: %s { file.wav | file.aif }\n", argv[0]); return 1; } fn = argv[1]; - if(0 == (f = fopen(fn, "rb")) || fread(buf, 1, 4, f) != 4) { - fprintf(stderr, "ERROR opening %s for reading\n", fn); + 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)? FOREIGN_BLOCK_TYPE__AIFF : FOREIGN_BLOCK_TYPE__RIFF))) { - fprintf(stderr, "ERROR: out of memory\n"); + 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)) { - fprintf(stderr, "ERROR reading chunks from %s: %s\n", 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)) { - fprintf(stderr, "ERROR reading chunks from %s: %s\n", fn, error); + flac_fprintf(stderr, "ERROR reading chunks from %s: %s\n", fn, error); return 1; } } - if(0 == (f = fopen(fn, "rb"))) { - fprintf(stderr, "ERROR opening %s for reading\n", fn); + 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) { - fprintf(stderr, "ERROR seeking in %s\n", fn); + flac_fprintf(stderr, "ERROR seeking in %s\n", fn); return 1; } - if(fread(buf, 1, 12, f) != 12) { - fprintf(stderr, "ERROR reading %s\n", fn); + 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_((const FLAC__byte*)buf+4, fm->type); + 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); diff --git a/3rdparty/libflac/src/flac/iffscan.dsp b/3rdparty/libflac/src/flac/iffscan.dsp deleted file mode 100644 index f3d0e4120f0..00000000000 --- a/3rdparty/libflac/src/flac/iffscan.dsp +++ /dev/null @@ -1,108 +0,0 @@ -# Microsoft Developer Studio Project File - Name="iffscan" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=iffscan - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "iffscan.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "iffscan.mak" CFG="iffscan - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "iffscan - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "iffscan - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "iffscan - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "..\..\obj\release\bin" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c -# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "..\..\include" /D "NDEBUG" /D "FLAC__NO_DLL" /D "FLAC__HAS_OGG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /c -# SUBTRACT CPP /YX /Yc /Yu -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 ..\..\obj\release\lib\libFLAC_static.lib ..\..\obj\release\lib\ogg_static.lib /nologo /subsystem:console /machine:I386 - -!ELSEIF "$(CFG)" == "iffscan - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "..\..\obj\debug\bin" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "." /I "..\..\include" /D "_DEBUG" /D "DEBUG" /D "FLAC__NO_DLL" /D "FLAC__HAS_OGG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c -# SUBTRACT CPP /YX /Yc /Yu -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 ..\..\obj\debug\lib\libFLAC_static.lib ..\..\obj\release\lib\ogg_static.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "iffscan - Win32 Release" -# Name "iffscan - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=.\iffscan.c -# End Source File -# Begin Source File - -SOURCE=.\foreign_metadata.c -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# Begin Source File - -SOURCE=.\foreign_metadata.h -# End Source File -# End Group -# End Target -# End Project diff --git a/3rdparty/libflac/src/flac/iffscan.vcproj b/3rdparty/libflac/src/flac/iffscan.vcproj deleted file mode 100644 index 0651666b1db..00000000000 --- a/3rdparty/libflac/src/flac/iffscan.vcproj +++ /dev/null @@ -1,212 +0,0 @@ -<?xml version="1.0" encoding="Windows-1252"?> -<VisualStudioProject - ProjectType="Visual C++" - Version="8.00" - Name="iffscan" - ProjectGUID="{4cefbc94-c215-11db-8314-0800200c9a66}" - RootNamespace="iffscan" - Keyword="Win32Proj" - > - <Platforms> - <Platform - Name="Win32" - /> - </Platforms> - <ToolFiles> - </ToolFiles> - <Configurations> - <Configuration - Name="Debug|Win32" - OutputDirectory="..\..\obj\debug\bin" - IntermediateDirectory="Debug" - ConfigurationType="1" - > - <Tool - Name="VCPreBuildEventTool" - /> - <Tool - Name="VCCustomBuildTool" - /> - <Tool - Name="VCXMLDataGeneratorTool" - /> - <Tool - Name="VCWebServiceProxyGeneratorTool" - /> - <Tool - Name="VCMIDLTool" - /> - <Tool - Name="VCCLCompilerTool" - Optimization="0" - AdditionalIncludeDirectories=".;..\..\include" - PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL;DEBUG" - MinimalRebuild="true" - BasicRuntimeChecks="3" - RuntimeLibrary="1" - UsePrecompiledHeader="0" - WarningLevel="3" - Detect64BitPortabilityProblems="true" - DebugInformationFormat="4" - CompileAs="0" - DisableSpecificWarnings="4267;4996" - /> - <Tool - Name="VCManagedResourceCompilerTool" - /> - <Tool - Name="VCResourceCompilerTool" - /> - <Tool - Name="VCPreLinkEventTool" - /> - <Tool - Name="VCLinkerTool" - AdditionalDependencies="..\..\obj\release\lib\ogg_static.lib" - LinkIncremental="2" - IgnoreDefaultLibraryNames="uuid.lib" - GenerateDebugInformation="true" - SubSystem="1" - TargetMachine="1" - /> - <Tool - Name="VCALinkTool" - /> - <Tool - Name="VCManifestTool" - /> - <Tool - Name="VCXDCMakeTool" - /> - <Tool - Name="VCBscMakeTool" - /> - <Tool - Name="VCFxCopTool" - /> - <Tool - Name="VCAppVerifierTool" - /> - <Tool - Name="VCWebDeploymentTool" - /> - <Tool - Name="VCPostBuildEventTool" - /> - </Configuration> - <Configuration - Name="Release|Win32" - OutputDirectory="..\..\obj\release\bin" - IntermediateDirectory="Release" - ConfigurationType="1" - > - <Tool - Name="VCPreBuildEventTool" - /> - <Tool - Name="VCCustomBuildTool" - /> - <Tool - Name="VCXMLDataGeneratorTool" - /> - <Tool - Name="VCWebServiceProxyGeneratorTool" - /> - <Tool - Name="VCMIDLTool" - /> - <Tool - Name="VCCLCompilerTool" - EnableIntrinsicFunctions="true" - FavorSizeOrSpeed="1" - OmitFramePointers="true" - WholeProgramOptimization="true" - AdditionalIncludeDirectories=".;..\..\include" - PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;FLAC__HAS_OGG;FLAC__NO_DLL" - RuntimeLibrary="0" - BufferSecurityCheck="false" - UsePrecompiledHeader="0" - WarningLevel="3" - Detect64BitPortabilityProblems="true" - DebugInformationFormat="3" - CompileAs="0" - DisableSpecificWarnings="4267;4996" - /> - <Tool - Name="VCManagedResourceCompilerTool" - /> - <Tool - Name="VCResourceCompilerTool" - /> - <Tool - Name="VCPreLinkEventTool" - /> - <Tool - Name="VCLinkerTool" - AdditionalDependencies="..\..\obj\release\lib\ogg_static.lib" - LinkIncremental="1" - IgnoreDefaultLibraryNames="uuid.lib" - GenerateDebugInformation="true" - SubSystem="1" - OptimizeReferences="2" - EnableCOMDATFolding="2" - LinkTimeCodeGeneration="1" - TargetMachine="1" - /> - <Tool - Name="VCALinkTool" - /> - <Tool - Name="VCManifestTool" - /> - <Tool - Name="VCXDCMakeTool" - /> - <Tool - Name="VCBscMakeTool" - /> - <Tool - Name="VCFxCopTool" - /> - <Tool - Name="VCAppVerifierTool" - /> - <Tool - Name="VCWebDeploymentTool" - /> - <Tool - Name="VCPostBuildEventTool" - /> - </Configuration> - </Configurations> - <References> - </References> - <Files> - <Filter - Name="Header Files" - Filter="h;hpp;hxx;hm;inl;inc;xsd" - UniqueIdentifier="{93995380-89BD-4b04-88EB-6E5FBE522BFB}" - > - <File - RelativePath=".\foreign_metadata.h" - > - </File> - </Filter> - <Filter - Name="Source Files" - Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" - UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2D32A752A2FF}" - > - <File - RelativePath=".\foreign_metadata.c" - > - </File> - <File - RelativePath=".\iffscan.c" - > - </File> - </Filter> - </Files> - <Globals> - </Globals> -</VisualStudioProject> diff --git a/3rdparty/libflac/src/flac/local_string_utils.c b/3rdparty/libflac/src/flac/local_string_utils.c index d0f8ed3499d..7e252334a72 100644 --- a/3rdparty/libflac/src/flac/local_string_utils.c +++ b/3rdparty/libflac/src/flac/local_string_utils.c @@ -1,7 +1,7 @@ /* flac - Command-line FLAC encoder/decoder */ -#if HAVE_CONFIG_H +#ifdef HAVE_CONFIG_H # include <config.h> #endif diff --git a/3rdparty/libflac/src/flac/local_string_utils.h b/3rdparty/libflac/src/flac/local_string_utils.h index e43041bad28..01f891f7967 100644 --- a/3rdparty/libflac/src/flac/local_string_utils.h +++ b/3rdparty/libflac/src/flac/local_string_utils.h @@ -1,5 +1,6 @@ /* flac - Command-line FLAC encoder/decoder - * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson + * 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 @@ -11,9 +12,9 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * You 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 diff --git a/3rdparty/libflac/src/flac/main.c b/3rdparty/libflac/src/flac/main.c index f3716a8097f..c22e602c1e9 100644 --- a/3rdparty/libflac/src/flac/main.c +++ b/3rdparty/libflac/src/flac/main.c @@ -1,5 +1,6 @@ /* flac - Command-line FLAC encoder/decoder - * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson + * 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 @@ -11,12 +12,12 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * You 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 HAVE_CONFIG_H +#ifdef HAVE_CONFIG_H # include <config.h> #endif @@ -36,6 +37,9 @@ #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" @@ -43,12 +47,6 @@ #include "utils.h" #include "vorbiscomment.h" -#if defined _MSC_VER || defined __MINGW32__ || defined __EMX__ -#define FLAC__STRCASECMP stricmp -#else -#define FLAC__STRCASECMP strcasecmp -#endif - #if 0 /*[JEC] was:#if HAVE_GETOPT_LONG*/ /*[JEC] see flac/include/share/getopt.h as to why the change */ @@ -57,8 +55,6 @@ # include "share/getopt.h" #endif -typedef enum { RAW, WAV, AIF, FLAC, OGGFLAC } FileFormat; - static int do_it(void); static FLAC__bool init_options(void); @@ -67,7 +63,7 @@ static int parse_option(int short_option, const char *long_option, const char *o static void free_options(void); static void add_compression_setting_bool(compression_setting_type_t type, FLAC__bool value); static void add_compression_setting_string(compression_setting_type_t type, const char *value); -static void add_compression_setting_unsigned(compression_setting_type_t type, unsigned value); +static 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); @@ -80,17 +76,12 @@ static int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__b static int decode_file(const char *infilename); static const char *get_encoded_outfilename(const char *infilename); -static const char *get_decoded_outfilename(const char *infilename); +static const char *get_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); -#ifdef _MSC_VER -/* There's no strtoll() in MSVC6 so we just write a specialized one */ -static FLAC__int64 local__strtoll(const char *src, char **endptr); -#endif - /* * share__getopt format struct; note that for long options with no @@ -100,24 +91,26 @@ static struct share__option long_options_[] = { /* * general options */ - { "help" , share__no_argument, 0, 'h' }, - { "explain" , share__no_argument, 0, 'H' }, - { "version" , share__no_argument, 0, 'v' }, - { "decode" , share__no_argument, 0, 'd' }, - { "analyze" , share__no_argument, 0, 'a' }, - { "test" , share__no_argument, 0, 't' }, - { "stdout" , share__no_argument, 0, 'c' }, - { "silent" , share__no_argument, 0, 's' }, - { "totally-silent" , share__no_argument, 0, 0 }, - { "warnings-as-errors" , share__no_argument, 0, 'w' }, - { "force" , share__no_argument, 0, 'f' }, - { "delete-input-file" , share__no_argument, 0, 0 }, - { "keep-foreign-metadata" , share__no_argument, 0, 0 }, - { "output-prefix" , share__required_argument, 0, 0 }, - { "output-name" , share__required_argument, 0, 'o' }, - { "skip" , share__required_argument, 0, 0 }, - { "until" , share__required_argument, 0, 0 }, - { "channel-map" , share__required_argument, 0, 0 }, /* undocumented */ + { "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 @@ -147,12 +140,17 @@ static struct share__option long_options_[] = { { "best" , share__no_argument, 0, '8' }, { "fast" , share__no_argument, 0, '0' }, { "verify" , share__no_argument, 0, 'V' }, - { "force-aiff-format" , share__no_argument, 0, 0 }, { "force-raw-format" , share__no_argument, 0, 0 }, + { "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 }, - { "sector-align" , share__no_argument, 0, 0 }, { "seekpoint" , share__required_argument, 0, 'S' }, { "padding" , share__required_argument, 0, 'P' }, #if FLAC__HAS_OGG @@ -174,6 +172,8 @@ static struct share__option long_options_[] = { { "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 @@ -184,6 +184,7 @@ static struct share__option long_options_[] = { /* * 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 }, @@ -192,7 +193,6 @@ static struct share__option long_options_[] = { { "no-keep-foreign-metadata" , share__no_argument, 0, 0 }, { "no-replay-gain" , share__no_argument, 0, 0 }, { "no-ignore-chunk-sizes" , share__no_argument, 0, 0 }, - { "no-sector-align" , share__no_argument, 0, 0 }, { "no-utf8-convert" , share__no_argument, 0, 0 }, { "no-lax" , share__no_argument, 0, 0 }, #if FLAC__HAS_OGG @@ -207,6 +207,7 @@ static struct share__option long_options_[] = { { "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 */ @@ -240,13 +241,20 @@ static struct { FLAC__bool has_serial_number; /* true iff --serial-number was used */ long serial_number; /* this is the Ogg serial number and is unused for native FLAC */ FLAC__bool force_to_stdout; - FLAC__bool force_aiff_format; FLAC__bool force_raw_format; + FLAC__bool 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 sector_align; FLAC__bool utf8_convert; /* true by default, to convert tag strings from locale to utf-8, false if --no-utf8-convert used */ const char *cmdline_forced_outfilename; const char *output_prefix; @@ -262,19 +270,21 @@ static struct { int format_channels; int format_bps; int format_sample_rate; - off_t format_input_size; + 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; - unsigned num_files; + uint32_t num_files; char **filenames; FLAC__StreamMetadata *vorbis_comment; FLAC__StreamMetadata *pictures[64]; - unsigned num_pictures; + uint32_t num_pictures; struct { FLAC__bool disable_constant_subframes; @@ -289,12 +299,12 @@ static struct { * miscellaneous globals */ -static FLAC__int32 align_reservoir_0[588], align_reservoir_1[588]; /* for carrying over samples from --sector-align */ -static FLAC__int32 *align_reservoir[2] = { align_reservoir_0, align_reservoir_1 }; -static unsigned align_reservoir_samples = 0; /* 0 .. 587 */ - +#ifndef FUZZ_TOOL_FLAC int main(int argc, char *argv[]) +#else +static int main_to_fuzz(int argc, char *argv[]) +#endif { int retval = 0; @@ -302,9 +312,28 @@ int main(int argc, char *argv[]) _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((unsigned)time(0)); + 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; @@ -366,19 +395,27 @@ int do_it(void) return usage_error("ERROR: --cue may not be combined with --skip or --until\n"); if(option_values.format_channels >= 0) { - if(option_values.format_channels == 0 || (unsigned)option_values.format_channels > FLAC__MAX_CHANNELS) + 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) - return usage_error("ERROR: invalid bits per sample '%u' (must be 8/16/24)\n", option_values.format_bps); + 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 && option_values.force_aiff_format) - return usage_error("ERROR: only one of --force-raw-format and --force-aiff-format allowed\n"); + 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) @@ -397,8 +434,6 @@ int do_it(void) if(option_values.ignore_chunk_sizes) { if(option_values.mode_decode) return usage_error("ERROR: --ignore-chunk-sizes only allowed for encoding\n"); - if(0 != option_values.sector_align) - return usage_error("ERROR: --ignore-chunk-sizes not allowed with --sector-align\n"); if(0 != option_values.until_specification) return usage_error("ERROR: --ignore-chunk-sizes not allowed with --until\n"); if(0 != option_values.cue_specification) @@ -406,22 +441,6 @@ int do_it(void) if(0 != option_values.cuesheet_filename) return usage_error("ERROR: --ignore-chunk-sizes not allowed with --cuesheet\n"); } - if(option_values.sector_align) { - if(option_values.mode_decode) - return usage_error("ERROR: --sector-align only allowed for encoding\n"); - if(0 != option_values.skip_specification) - return usage_error("ERROR: --sector-align not allowed with --skip\n"); - if(0 != option_values.until_specification) - return usage_error("ERROR: --sector-align not allowed with --until\n"); - if(0 != option_values.cue_specification) - return usage_error("ERROR: --sector-align not allowed with --cue\n"); - if(option_values.format_channels >= 0 && option_values.format_channels != 2) - return usage_error("ERROR: --sector-align can only be done with stereo input\n"); - if(option_values.format_bps >= 0 && option_values.format_bps != 16) - return usage_error("ERROR: --sector-align can only be done with 16-bit samples\n"); - if(option_values.format_sample_rate >= 0 && option_values.format_sample_rate != 44100) - return usage_error("ERROR: --sector-align can only be done with a sample rate of 44100\n"); - } if(option_values.replay_gain) { if(option_values.force_to_stdout) return usage_error("ERROR: --replay-gain not allowed with -c/--stdout\n"); @@ -431,20 +450,11 @@ int do_it(void) return usage_error("ERROR: --replay-gain can only be done with mono/stereo input\n"); if(option_values.format_sample_rate >= 0 && !grabbag__replaygain_is_valid_sample_frequency(option_values.format_sample_rate)) return usage_error("ERROR: invalid sample rate used with --replay-gain\n"); - /* - * We want to reserve padding space for the ReplayGain - * tags that we will set later, to avoid rewriting the - * whole file. - */ if( (option_values.padding >= 0 && option_values.padding < (int)GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED) || (option_values.padding < 0 && FLAC_ENCODE__DEFAULT_PADDING < (int)GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED) ) { flac__utils_printf(stderr, 1, "NOTE: --replay-gain may leave a small PADDING block even with --no-padding\n"); - option_values.padding = GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED; - } - else { - option_values.padding += GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED; } } if(option_values.num_files > 1 && option_values.cmdline_forced_outfilename) { @@ -456,7 +466,7 @@ int do_it(void) 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) { + 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"); @@ -464,15 +474,13 @@ int do_it(void) return usage_error("ERROR: --keep-foreign-metadata is not allowed in test mode\n"); if(option_values.analyze) return usage_error("ERROR: --keep-foreign-metadata is not allowed in analyis mode\n"); - /*@@@@@@*/ - if(option_values.delete_input) - return usage_error("ERROR: using --delete-input-file with --keep-foreign-metadata has been disabled until more testing has been done.\n"); flac__utils_printf(stderr, 1, "NOTE: --keep-foreign-metadata is a new feature; make sure to test the output file before deleting the original.\n"); } } flac__utils_printf(stderr, 2, "\n"); - flac__utils_printf(stderr, 2, "flac %s, Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson\n", FLAC__VERSION_STRING); + flac__utils_printf(stderr, 2, "flac %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"); @@ -483,7 +491,7 @@ int do_it(void) retval = decode_file("-"); } else { - unsigned i; + 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++) { @@ -504,14 +512,16 @@ int do_it(void) retval = encode_file("-", first, true); } else { - unsigned i; + 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 |= encode_file(option_values.filenames[i], first, i == (option_values.num_files-1)); - first = false; + 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; @@ -522,13 +532,7 @@ int do_it(void) flac__utils_printf(stderr, 1, "ERROR: filename too long: %s", option_values.filenames[i]); return 1; } - if(0 == strcmp(option_values.filenames[i], "-")) { - FLAC__ASSERT(0); - /* double protection */ - flac__utils_printf(stderr, 1, "internal error\n"); - return 2; - } - if(0 != (error = grabbag__replaygain_store_to_file_album(outfilename, album_gain, album_peak, /*preserve_modtime=*/true))) { + 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; } @@ -544,6 +548,7 @@ 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; @@ -561,13 +566,20 @@ FLAC__bool init_options(void) option_values.has_serial_number = false; option_values.serial_number = 0; option_values.force_to_stdout = false; - option_values.force_aiff_format = false; option_values.force_raw_format = false; + option_values.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.sector_align = false; option_values.utf8_convert = true; option_values.cmdline_forced_outfilename = 0; option_values.output_prefix = 0; @@ -585,12 +597,14 @@ FLAC__bool init_options(void) option_values.format_channels = -1; option_values.format_bps = -1; option_values.format_sample_rate = -1; - option_values.format_input_size = (off_t)(-1); + option_values.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; @@ -638,8 +652,8 @@ int parse_options(int argc, char *argv[]) option_values.num_files = argc - share__optind; if(option_values.num_files > 0) { - unsigned i = 0; - if(0 == (option_values.filenames = (char**)malloc(sizeof(char*) * option_values.num_files))) + 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++]); @@ -651,8 +665,6 @@ int parse_options(int argc, char *argv[]) int parse_option(int short_option, const char *long_option, const char *option_argument) { const char *violation; - char *p; - int i; if(short_option == 0) { FLAC__ASSERT(0 != long_option); @@ -662,9 +674,15 @@ int parse_option(int short_option, const char *long_option, const char *option_a 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; @@ -681,17 +699,12 @@ int parse_option(int short_option, const char *long_option, const char *option_a FLAC__ASSERT(0 != option_argument); { char *end; -#ifdef _MSC_VER - FLAC__int64 i; - i = local__strtoll(option_argument, &end); -#else - long long i; - i = strtoll(option_argument, &end, 10); -#endif + 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 = (off_t)i; - if(option_values.format_input_size != i) /* check if off_t is smaller than long long */ + 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); @@ -736,7 +749,7 @@ int parse_option(int short_option, const char *long_option, const char *option_a option_values.cuesheet_filename = option_argument; } else if(0 == strcmp(long_option, "picture")) { - const unsigned max_pictures = sizeof(option_values.pictures)/sizeof(option_values.pictures[0]); + 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); @@ -752,11 +765,29 @@ int parse_option(int short_option, const char *long_option, const char *option_a 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-raw-format")) { - option_values.force_raw_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; @@ -767,9 +798,6 @@ int parse_option(int short_option, const char *long_option, const char *option_a else if(0 == strcmp(long_option, "ignore-chunk-sizes")) { option_values.ignore_chunk_sizes = true; } - else if(0 == strcmp(long_option, "sector-align")) { - option_values.sector_align = true; - } #if FLAC__HAS_OGG else if(0 == strcmp(long_option, "ogg")) { option_values.use_ogg = true; @@ -815,14 +843,22 @@ int parse_option(int short_option, const char *long_option, const char *option_a 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; @@ -836,6 +872,7 @@ int parse_option(int short_option, const char *long_option, const char *option_a } 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; @@ -843,9 +880,6 @@ int parse_option(int short_option, const char *long_option, const char *option_a else if(0 == strcmp(long_option, "no-ignore-chunk-sizes")) { option_values.ignore_chunk_sizes = false; } - else if(0 == strcmp(long_option, "no-sector-align")) { - option_values.sector_align = false; - } else if(0 == strcmp(long_option, "no-utf8-convert")) { option_values.utf8_convert = false; } @@ -898,6 +932,12 @@ int parse_option(int short_option, const char *long_option, const char *option_a 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) { @@ -925,7 +965,9 @@ int parse_option(int short_option, const char *long_option, const char *option_a 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; @@ -951,7 +993,7 @@ int parse_option(int short_option, const char *long_option, const char *option_a case '6': case '7': case '8': - add_compression_setting_unsigned(CST_COMPRESSION_LEVEL, short_option-'0'); + add_compression_setting_uint32_t(CST_COMPRESSION_LEVEL, short_option-'0'); break; case '9': return usage_error("ERROR: compression level '9' is reserved\n"); @@ -975,8 +1017,8 @@ int parse_option(int short_option, const char *long_option, const char *option_a return usage_error("ERROR: too many seekpoints requested\n"); } else { - strcat(option_values.requested_seek_points, option_argument); - strcat(option_values.requested_seek_points, ";"); + 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; @@ -987,11 +1029,14 @@ int parse_option(int short_option, const char *long_option, const char *option_a return usage_error("ERROR: argument to -%c must be >= 0; for no padding use -%c-\n", short_option, short_option); break; case 'b': - FLAC__ASSERT(0 != option_argument); - i = atoi(option_argument); - if((i < (int)FLAC__MIN_BLOCK_SIZE || i > (int)FLAC__MAX_BLOCK_SIZE)) - return usage_error("ERROR: invalid blocksize (-%c) '%d', must be >= %u and <= %u\n", short_option, i, FLAC__MIN_BLOCK_SIZE, FLAC__MAX_BLOCK_SIZE); - add_compression_setting_unsigned(CST_BLOCKSIZE, (unsigned)i); + { + 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); @@ -1000,11 +1045,14 @@ int parse_option(int short_option, const char *long_option, const char *option_a add_compression_setting_bool(CST_DO_ESCAPE_CODING, true); break; case 'l': - FLAC__ASSERT(0 != option_argument); - i = atoi(option_argument); - if((i < 0 || i > (int)FLAC__MAX_LPC_ORDER)) - return usage_error("ERROR: invalid LPC order (-%c) '%d', must be >= %u and <= %u\n", short_option, i, 0, FLAC__MAX_LPC_ORDER); - add_compression_setting_unsigned(CST_MAX_LPC_ORDER, (unsigned)i); + { + 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); @@ -1022,38 +1070,46 @@ int parse_option(int short_option, const char *long_option, const char *option_a add_compression_setting_bool(CST_DO_QLP_COEFF_PREC_SEARCH, true); break; case 'q': - FLAC__ASSERT(0 != option_argument); - i = atoi(option_argument); - if(i < 0 || (i > 0 && (i < (int)FLAC__MIN_QLP_COEFF_PRECISION || i > (int)FLAC__MAX_QLP_COEFF_PRECISION))) - return usage_error("ERROR: invalid value '%d' for qlp coeff precision (-%c), must be 0 or between %u and %u, inclusive\n", i, short_option, FLAC__MIN_QLP_COEFF_PRECISION, FLAC__MAX_QLP_COEFF_PRECISION); - add_compression_setting_unsigned(CST_QLP_COEFF_PRECISION, (unsigned)i); - break; - case 'r': - FLAC__ASSERT(0 != option_argument); - p = strchr(option_argument, ','); - if(0 == p) { - add_compression_setting_unsigned(CST_MIN_RESIDUAL_PARTITION_ORDER, 0); + { + uint32_t i ; + FLAC__ASSERT(0 != option_argument); i = atoi(option_argument); - if(i < 0) - return usage_error("ERROR: invalid value '%d' for residual partition order (-%c), must be between 0 and %u, inclusive\n", i, short_option, FLAC__MAX_RICE_PARTITION_ORDER); - add_compression_setting_unsigned(CST_MAX_RESIDUAL_PARTITION_ORDER, (unsigned)i); + 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); } - else { - i = atoi(option_argument); - if(i < 0) - return usage_error("ERROR: invalid value '%d' for min residual partition order (-%c), must be between 0 and %u, inclusive\n", i, short_option, FLAC__MAX_RICE_PARTITION_ORDER); - add_compression_setting_unsigned(CST_MIN_RESIDUAL_PARTITION_ORDER, (unsigned)i); - i = atoi(++p); - if(i < 0) - return usage_error("ERROR: invalid value '%d' for max residual partition order (-%c), must be between 0 and %u, inclusive\n", i, short_option, FLAC__MAX_RICE_PARTITION_ORDER); - add_compression_setting_unsigned(CST_MAX_RESIDUAL_PARTITION_ORDER, (unsigned)i); + break; + case 'r': + { + 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': - i = atoi(option_argument); - if(i < 0) - return usage_error("ERROR: invalid value '%d' for Rice parameter search distance (-%c), must be >= 0\n", i, short_option); - add_compression_setting_unsigned(CST_RICE_PARAMETER_SEARCH_DIST, (unsigned)i); + { + uint32_t i; + i = atoi(option_argument); + add_compression_setting_uint32_t(CST_RICE_PARAMETER_SEARCH_DIST, i); + } break; default: FLAC__ASSERT(0); @@ -1065,7 +1121,7 @@ int parse_option(int short_option, const char *long_option, const char *option_a void free_options(void) { - unsigned i; + uint32_t i; if(0 != option_values.filenames) { for(i = 0; i < option_values.num_files; i++) { if(0 != option_values.filenames[i]) @@ -1082,7 +1138,11 @@ void free_options(void) 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++; @@ -1091,19 +1151,34 @@ void add_compression_setting_bool(compression_setting_type_t type, FLAC__bool va 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_unsigned(compression_setting_type_t type, unsigned value) +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"); - 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++; +#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, ...) @@ -1115,7 +1190,9 @@ int usage_error(const char *message, ...) va_start(args, message); +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION (void) vfprintf(stderr, message, args); +#endif va_end(args); @@ -1134,7 +1211,8 @@ static void usage_header(void) { printf("===============================================================================\n"); printf("flac - Command-line FLAC encoder/decoder version %s\n", FLAC__VERSION_STRING); - printf("Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson\n"); + printf("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"); @@ -1146,9 +1224,9 @@ static void usage_header(void) printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"); printf("GNU General Public License for more details.\n"); printf("\n"); - printf("You should have received a copy of the GNU General Public License\n"); - printf("along with this program; if not, write to the Free Software\n"); - printf("Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n"); + printf("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"); } @@ -1156,10 +1234,13 @@ static void usage_summary(void) { printf("Usage:\n"); printf("\n"); - printf(" Encoding: flac [<general-options>] [<encoding/format-options>] [INPUTFILE [...]]\n"); - printf(" Decoding: flac -d [<general-options>] [<format-options>] [FLACFILE [...]]\n"); - printf(" Testing: flac -t [<general-options>] [FLACFILE [...]]\n"); - printf("Analyzing: flac -a [<general-options>] [<analysis-options>] [FLACFILE [...]]\n"); + printf(" 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"); } @@ -1170,6 +1251,9 @@ void short_usage(void) 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"); @@ -1202,7 +1286,10 @@ void show_help(void) 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 @@ -1218,10 +1305,7 @@ void show_help(void) printf("encoding options:\n"); printf(" -V, --verify Verify a correct encoding\n"); printf(" --lax Allow encoder to generate non-Subset files\n"); -#if 0 /*@@@ currently undocumented */ printf(" --ignore-chunk-sizes Ignore data chunk sizes in WAVE/AIFF files\n"); -#endif - printf(" --sector-align Align multiple files on sector boundaries\n"); printf(" --replay-gain Calculate ReplayGain & store in FLAC tags\n"); printf(" --cuesheet=FILENAME Import cuesheet and store in CUESHEET block\n"); printf(" --picture=SPECIFICATION Import picture and store in PICTURE block\n"); @@ -1236,8 +1320,11 @@ void show_help(void) printf(" -4, --compression-level-4 Synonymous with -l 8 -b 4096 -M -r 4\n"); printf(" -5, --compression-level-5 Synonymous with -l 8 -b 4096 -m -r 5\n"); printf(" -6, --compression-level-6 Synonymous with -l 8 -b 4096 -m -r 6\n"); - printf(" -7, --compression-level-7 Synonymous with -l 8 -b 4096 -m -e -r 6\n"); - printf(" -8, --compression-level-8, --best Synonymous with -l 12 -b 4096 -m -e -r 6\n"); + printf(" -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"); @@ -1247,19 +1334,30 @@ void show_help(void) 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(" --force-aiff-format Force decoding to AIFF format\n"); - printf(" --force-raw-format Treat input or output as raw samples\n"); printf("negative options:\n"); printf(" --no-adaptive-mid-side\n"); + printf(" --no-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"); @@ -1272,10 +1370,7 @@ void show_help(void) printf(" --no-replay-gain\n"); printf(" --no-residual-gnuplot\n"); printf(" --no-residual-text\n"); -#if 0 /*@@@ currently undocumented */ printf(" --no-ignore-chunk-sizes\n"); -#endif - printf(" --no-sector-align\n"); printf(" --no-seektable\n"); printf(" --no-silent\n"); printf(" --no-force\n"); @@ -1288,9 +1383,9 @@ void show_explain(void) usage_header(); usage_summary(); printf("For encoding:\n"); - printf(" The input file(s) may be a PCM WAVE file, AIFF (or uncompressed AIFF-C)\n"); - printf(" file, or raw samples.\n"); - printf(" The output file(s) will be in native FLAC or Ogg FLAC format\n"); + printf(" 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"); @@ -1301,12 +1396,6 @@ void show_explain(void) printf("since the former allows flac to seek backwards to write the STREAMINFO or\n"); printf("WAVE/AIFF header contents when necessary.\n"); printf("\n"); - printf("flac checks for the presence of a AIFF/WAVE header to decide whether or not to\n"); - printf("treat an input file as AIFF/WAVE format or raw samples. If any input file is\n"); - printf("raw you must specify the format options {-fb|fl} -fc -fp and -fs, which will\n"); - printf("apply to all raw files. You can force AIFF/WAVE files to be treated as raw\n"); - printf("files using -fr.\n"); - printf("\n"); printf("general options:\n"); printf(" -v, --version Show the flac version number\n"); printf(" -h, --help Show basic usage a list of all options\n"); @@ -1338,6 +1427,11 @@ void show_explain(void) 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"); @@ -1345,6 +1439,14 @@ void show_explain(void) 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"); @@ -1408,22 +1510,22 @@ void show_explain(void) printf(" output in parallel and comparing to the\n"); printf(" original\n"); printf(" --lax Allow encoder to generate non-Subset files\n"); -#if 0 /*@@@ currently undocumented */ printf(" --ignore-chunk-sizes Ignore data chunk sizes in WAVE/AIFF files;\n"); printf(" useful when piping data from programs which\n"); printf(" generate bogus data chunk sizes.\n"); -#endif - printf(" --sector-align Align encoding of multiple CD format WAVE files\n"); - printf(" on sector boundaries.\n"); printf(" --replay-gain Calculate ReplayGain values and store them as\n"); printf(" FLAC tags. Title gains/peaks will be computed\n"); printf(" for each file, and an album gain/peak will be\n"); printf(" computed for all files. All input files must\n"); printf(" have the same resolution, sample rate, and\n"); - printf(" number of channels. The sample rate must be\n"); - printf(" one of 8, 11.025, 12, 16, 22.05, 24, 32, 44.1,\n"); - printf(" or 48 kHz. NOTE: this option may also leave a\n"); - printf(" few extra bytes in the PADDING block.\n"); + printf(" 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"); @@ -1469,7 +1571,7 @@ void show_explain(void) printf(" mean that FILE is actually a URL to an image, though this use is\n"); printf(" discouraged.\n"); printf(" DESCRIPTION is optional; the default is an empty string\n"); - printf(" The next part specfies the resolution and color information. If\n"); + printf(" The 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"); @@ -1518,20 +1620,25 @@ void show_explain(void) printf(" block of 8192 bytes by default, or 65536 bytes\n"); printf(" if the input audio is more than 20 minutes long.\n"); printf(" -b, --blocksize=# Specify the blocksize in samples; the default is\n"); - printf(" 1152 for -l 0, else 4096; must be one of 192,\n"); - printf(" 576, 1152, 2304, 4608, 256, 512, 1024, 2048,\n"); - printf(" 4096 (and 8192 or 16384 if the sample rate is\n"); - printf(" >48kHz) for Subset streams.\n"); + printf(" 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(" -7, --compression-level-7 Synonymous with -l 8 -b 4096 -m -e -r 6\n"); - printf(" -8, --compression-level-8, --best Synonymous with -l 12 -b 4096 -m -e -r 6\n"); + printf(" -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"); @@ -1542,12 +1649,13 @@ void show_explain(void) printf(" blackman, blackman_harris_4term_92db,\n"); printf(" connes, flattop, gauss(STDDEV), hamming,\n"); printf(" hann, kaiser_bessel, nuttall, rectangle,\n"); - printf(" triangle, tukey(P), welch. More than one\n"); - printf(" may be specified but encoding time is a\n"); - printf(" multiple of the number of functions since\n"); - printf(" they are each tried in turn. The encoder\n"); - printf(" chooses suitable defaults in the absence\n"); - printf(" of any -A options.\n"); + printf(" 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"); @@ -1556,38 +1664,63 @@ void show_explain(void) printf(" does nothing if using -l 0\n"); printf(" -q, --qlp-coeff-precision=# Specify precision in bits of quantized\n"); printf(" linear-predictor coefficients; 0 => let\n"); - printf(" encoder decide (the minimun is %u, the\n", FLAC__MIN_QLP_COEFF_PRECISION); + printf(" 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..16; min defaults to 0; the\n"); - printf(" default is -r 0; above 4 doesn't usually\n"); - printf(" help much)\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 (the default is signed)\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, --cue-sheet, or other options that need\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(" --force-aiff-format Force the decoder to output AIFF format. This\n"); - printf(" option is not needed if the output filename (as\n"); - printf(" set by -o) ends with .aif or .aiff; this option\n"); - printf(" has no effect when encoding since input AIFF is\n"); - printf(" auto-detected.\n"); - printf(" --force-raw-format Force input (when encoding) or output (when\n"); - printf(" decoding) to be treated as raw samples\n"); printf("negative options:\n"); printf(" --no-adaptive-mid-side\n"); + printf(" --no-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"); @@ -1599,10 +1732,7 @@ void show_explain(void) printf(" --no-qlp-coeff-prec-search\n"); printf(" --no-residual-gnuplot\n"); printf(" --no-residual-text\n"); -#if 0 /*@@@ currently undocumented */ printf(" --no-ignore-chunk-sizes\n"); -#endif - printf(" --no-sector-align\n"); printf(" --no-seektable\n"); printf(" --no-silent\n"); printf(" --no-force\n"); @@ -1613,23 +1743,22 @@ void show_explain(void) void format_mistake(const char *infilename, FileFormat wrong, FileFormat right) { /* WATCHOUT: indexed by FileFormat */ - static const char * const ff[] = { "raw", "WAVE", "AIFF", "FLAC", "Ogg FLAC" }; - flac__utils_printf(stderr, 1, "WARNING: %s is not a %s file; treating as a %s file\n", infilename, ff[wrong], ff[right]); + 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]; - unsigned lookahead_length = 0; - FileFormat input_format = RAW; - FLAC__bool is_aifc = false; + uint32_t lookahead_length = 0, master_chunk_size = 0; + FileFormat input_format = FORMAT_RAW; int retval; - off_t infilesize; - encode_options_t common_options; + 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); @@ -1637,12 +1766,13 @@ int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_ } if(0 == strcmp(infilename, "-")) { - infilesize = (off_t)(-1); + infilesize = (FLAC__off_t)(-1); encode_infile = grabbag__file_get_binary_stdin(); } - else { + else + { infilesize = grabbag__file_get_filesize(infilename); - if(0 == (encode_infile = fopen(infilename, "rb"))) { + 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; } @@ -1650,69 +1780,102 @@ int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_ if(!option_values.force_raw_format) { /* first set format based on name */ - if(strlen(infilename) >= 4 && 0 == FLAC__STRCASECMP(infilename+(strlen(infilename)-4), ".wav")) - input_format = WAV; - else if(strlen(infilename) >= 4 && 0 == FLAC__STRCASECMP(infilename+(strlen(infilename)-4), ".aif")) - input_format = AIF; - else if(strlen(infilename) >= 5 && 0 == FLAC__STRCASECMP(infilename+(strlen(infilename)-5), ".aiff")) - input_format = AIF; - else if(strlen(infilename) >= 5 && 0 == FLAC__STRCASECMP(infilename+(strlen(infilename)-5), ".flac")) - input_format = FLAC; - else if(strlen(infilename) >= 4 && 0 == FLAC__STRCASECMP(infilename+(strlen(infilename)-4), ".oga")) - input_format = OGGFLAC; - else if(strlen(infilename) >= 4 && 0 == FLAC__STRCASECMP(infilename+(strlen(infilename)-4), ".ogg")) - input_format = OGGFLAC; + 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) { - if(input_format != RAW) { - format_mistake(infilename, input_format, RAW); + /* 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; } } - input_format = RAW; + /* force to raw */ + input_format = FORMAT_RAW; } else { - if(!strncmp((const char *)lookahead, "ID3", 3)) { + 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(!strncmp((const char *)lookahead, "RIFF", 4) && !strncmp((const char *)lookahead+8, "WAVE", 4)) - input_format = WAV; - else if(!strncmp((const char *)lookahead, "FORM", 4) && !strncmp((const char *)lookahead+8, "AIFF", 4)) - input_format = AIF; - else if(!strncmp((const char *)lookahead, "FORM", 4) && !strncmp((const char *)lookahead+8, "AIFC", 4)) { - input_format = AIF; - is_aifc = true; - } + else if(!memcmp(lookahead, "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 = FLAC; - /* this could be made more accurate by looking at the first packet */ + 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 = OGGFLAC; + input_format = FORMAT_OGGFLAC; else { - if(input_format != RAW) { - format_mistake(infilename, input_format, RAW); + /* 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; } } - input_format = RAW; + /* force to raw */ + input_format = FORMAT_RAW; } } } - if(option_values.keep_foreign_metadata) { + 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 != WAV && input_format != AIF) { + 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 or AIFF input\n"); + return usage_error("ERROR: --keep-foreign-metadata can only be used with WAVE, Wave64, RF64, or AIFF input\n"); } } @@ -1720,8 +1883,8 @@ int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_ * Error if output file already exists (and -f not used). * Use grabbag__file_get_filesize() as a cheap way to check. */ - if(!option_values.test_only && !option_values.force_file_overwrite && strcmp(outfilename, "-") && grabbag__file_get_filesize(outfilename) != (off_t)(-1)) { - if(input_format == FLAC) { + 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" @@ -1732,7 +1895,7 @@ int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_ outfilename ); } - else if(input_format == OGGFLAC) { + 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" @@ -1750,7 +1913,7 @@ int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_ } if(option_values.format_input_size >= 0) { - if (input_format != RAW || infilesize >= 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; @@ -1760,25 +1923,20 @@ int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_ } } - if(option_values.sector_align && (input_format == FLAC || input_format == OGGFLAC)) { - flac__utils_printf(stderr, 1, "ERROR: can't use --sector-align when the input file is FLAC or Ogg FLAC\n"); - conditional_fclose(encode_infile); - return 1; - } - if(option_values.sector_align && input_format == RAW && infilesize < 0) { - flac__utils_printf(stderr, 1, "ERROR: can't use --sector-align when the input size is unknown\n"); - conditional_fclose(encode_infile); - return 1; - } - - if(input_format == RAW) { + if(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(/*@@@@@@why no stdin?*/encode_infile == stdin || option_values.force_to_stdout) { + 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"); @@ -1789,111 +1947,113 @@ int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_ return usage_error("ERROR: --replay-gain cannot be used when encoding to Ogg FLAC yet\n"); } - if(!flac__utils_parse_skip_until_specification(option_values.skip_specification, &common_options.skip_specification) || common_options.skip_specification.is_relative) { + 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, &common_options.until_specification)) { /*@@@@ more checks: no + without --skip, no - unless known total_samples_to_{en,de}code */ + 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) - common_options.until_specification.is_relative = true; + encode_options.until_specification.is_relative = true; - common_options.verify = option_values.verify; - common_options.treat_warnings_as_errors = option_values.treat_warnings_as_errors; + encode_options.verify = option_values.verify; + encode_options.treat_warnings_as_errors = option_values.treat_warnings_as_errors; #if FLAC__HAS_OGG - common_options.use_ogg = option_values.use_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; } - common_options.serial_number = option_values.serial_number++; + encode_options.serial_number = option_values.serial_number++; #endif - common_options.lax = option_values.lax; - common_options.padding = option_values.padding; - common_options.num_compression_settings = option_values.num_compression_settings; - FLAC__ASSERT(sizeof(common_options.compression_settings) >= sizeof(option_values.compression_settings)); - memcpy(common_options.compression_settings, option_values.compression_settings, sizeof(option_values.compression_settings)); - common_options.requested_seek_points = option_values.requested_seek_points; - common_options.num_requested_seek_points = option_values.num_requested_seek_points; - common_options.cuesheet_filename = option_values.cuesheet_filename; - common_options.continue_through_decode_errors = option_values.continue_through_decode_errors; - common_options.cued_seekpoints = option_values.cued_seekpoints; - common_options.channel_map_none = option_values.channel_map_none; - common_options.is_first_file = is_first_file; - common_options.is_last_file = is_last_file; - common_options.align_reservoir = align_reservoir; - common_options.align_reservoir_samples = &align_reservoir_samples; - common_options.replay_gain = option_values.replay_gain; - common_options.ignore_chunk_sizes = option_values.ignore_chunk_sizes; - common_options.sector_align = option_values.sector_align; - common_options.vorbis_comment = option_values.vorbis_comment; - FLAC__ASSERT(sizeof(common_options.pictures) >= sizeof(option_values.pictures)); - memcpy(common_options.pictures, option_values.pictures, sizeof(option_values.pictures)); - common_options.num_pictures = option_values.num_pictures; - common_options.debug.disable_constant_subframes = option_values.debug.disable_constant_subframes; - common_options.debug.disable_fixed_subframes = option_values.debug.disable_fixed_subframes; - common_options.debug.disable_verbatim_subframes = option_values.debug.disable_verbatim_subframes; - common_options.debug.do_md5 = option_values.debug.do_md5; + 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(0 == (internal_outfilename = (char *)safe_malloc_add_3op_(strlen(outfilename), /*+*/strlen(tmp_suffix), /*+*/1))) { + 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; } - strcpy(internal_outfilename, outfilename); - strcat(internal_outfilename, tmp_suffix); + flac_snprintf(internal_outfilename, dest_len, "%s%s", outfilename, tmp_suffix); } - if(input_format == RAW) { - raw_encode_options_t options; - - options.common = common_options; - options.is_big_endian = option_values.format_is_big_endian; - options.is_unsigned_samples = option_values.format_is_unsigned_samples; - options.channels = option_values.format_channels; - options.bps = option_values.format_bps; - options.sample_rate = option_values.format_sample_rate; + 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_raw(encode_infile, infilesize, infilename, internal_outfilename? internal_outfilename : outfilename, lookahead, lookahead_length, options); + retval = flac__encode_file(encode_infile, infilesize, infilename, internal_outfilename? internal_outfilename : outfilename, lookahead, lookahead_length, encode_options); } - else if(input_format == FLAC || input_format == OGGFLAC) { - flac_encode_options_t options; - - options.common = common_options; - - retval = flac__encode_flac(encode_infile, infilesize, infilename, internal_outfilename? internal_outfilename : outfilename, lookahead, lookahead_length, options, input_format==OGGFLAC); + else 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 { - wav_encode_options_t options; - - options.common = common_options; - options.foreign_metadata = 0; - - /* read foreign metadata if requested */ - if(option_values.keep_foreign_metadata) { - if(0 == (options.foreign_metadata = flac__foreign_metadata_new(input_format==AIF? FOREIGN_BLOCK_TYPE__AIFF : FOREIGN_BLOCK_TYPE__RIFF))) { + 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; } } - if(input_format == AIF) - retval = flac__encode_aif(encode_infile, infilesize, infilename, internal_outfilename? internal_outfilename : outfilename, lookahead, lookahead_length, options, is_aifc); - else - retval = flac__encode_wav(encode_infile, infilesize, infilename, internal_outfilename? internal_outfilename : outfilename, lookahead, lookahead_length, options); + retval = flac__encode_file(encode_infile, infilesize, infilename, internal_outfilename? internal_outfilename : outfilename, lookahead, lookahead_length, encode_options); - if(options.foreign_metadata) - flac__foreign_metadata_delete(options.foreign_metadata); + 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) { @@ -1903,28 +2063,28 @@ int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_ const char *error; grabbag__replaygain_get_title(&title_gain, &title_peak); if( - 0 != (error = grabbag__replaygain_store_to_file_reference(internal_outfilename? internal_outfilename : outfilename, /*preserve_modtime=*/true)) || - 0 != (error = grabbag__replaygain_store_to_file_title(internal_outfilename? internal_outfilename : outfilename, title_gain, title_peak, /*preserve_modtime=*/true)) + 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(strcmp(infilename, "-")) + 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(rename(internal_outfilename, outfilename) < 0) { + if(flac_rename(internal_outfilename, outfilename) < 0) { #if defined _MSC_VER || defined __MINGW32__ || defined __EMX__ - /* on some flavors of windows, rename() will fail if the destination already exists, so we unlink and try again */ - if(unlink(outfilename) < 0) { + /* 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(rename(internal_outfilename, outfilename) < 0) { + 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; } @@ -1937,7 +2097,7 @@ int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_ /* handle --delete-input-file, but don't want to delete if piping from stdin, or if input filename and output filename are the same */ if(retval == 0 && option_values.delete_input && strcmp(infilename, "-") && internal_outfilename == 0) - unlink(infilename); + flac_unlink(infilename); if(internal_outfilename != 0) free(internal_outfilename); @@ -1949,52 +2109,157 @@ int decode_file(const char *infilename) { int retval; FLAC__bool treat_as_ogg = false; - FileFormat output_format = WAV; - decode_options_t common_options; - const char *outfilename = get_decoded_outfilename(infilename); + 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; } - /* - * Error if output file already exists (and -f not used). - * Use grabbag__file_get_filesize() as a cheap way to check. - */ - if(!option_values.test_only && !option_values.force_file_overwrite && strcmp(outfilename, "-") && grabbag__file_get_filesize(outfilename) != (off_t)(-1)) { - flac__utils_printf(stderr, 1, "ERROR: output file %s already exists, use -f to override\n", outfilename); - return 1; + if(!option_values.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 = RAW; + 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 = AIF; + 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 = WAV; + 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; + } + } - if(!option_values.test_only && !option_values.analyze) { - if(output_format == RAW && (option_values.format_is_big_endian < 0 || option_values.format_is_unsigned_samples < 0)) - return usage_error("ERROR: for decoding to a raw file you must specify a value for --endian and --sign\n"); + + /* 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]); + } } - if(option_values.keep_foreign_metadata) { - if(0 == strcmp(infilename, "-") || 0 == strcmp(outfilename, "-")) - return usage_error("ERROR: --keep-foreign-metadata cannot be used when decoding from stdin or to stdout\n"); - if(output_format != WAV && output_format != AIF) - return usage_error("ERROR: --keep-foreign-metadata can only be used with WAVE or AIFF output\n"); + /* 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(strlen(infilename) >= 4 && 0 == FLAC__STRCASECMP(infilename+(strlen(infilename)-4), ".oga")) + else if(infilename_length >= 4 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-4), ".oga")) treat_as_ogg = true; - else if(strlen(infilename) >= 4 && 0 == FLAC__STRCASECMP(infilename+(strlen(infilename)-4), ".ogg")) + else if(infilename_length >= 4 && 0 == FLAC__STRCASECMP(infilename+(infilename_length-4), ".ogg")) treat_as_ogg = true; else treat_as_ogg = false; @@ -2002,74 +2267,68 @@ int decode_file(const char *infilename) #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, &common_options.skip_specification) || common_options.skip_specification.is_relative) + 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, &common_options.until_specification)) /*@@@ more checks: no + without --skip, no - unless known total_samples_to_{en,de}code */ + 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) - common_options.until_specification.is_relative = true; + decode_options.until_specification.is_relative = true; if(option_values.cue_specification) { - if(!flac__utils_parse_cue_specification(option_values.cue_specification, &common_options.cue_specification)) + 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"); - common_options.has_cue_specification = true; + } + decode_options.has_cue_specification = true; } else - common_options.has_cue_specification = false; + decode_options.has_cue_specification = false; - common_options.treat_warnings_as_errors = option_values.treat_warnings_as_errors; - common_options.continue_through_decode_errors = option_values.continue_through_decode_errors; - common_options.replaygain_synthesis_spec = option_values.replaygain_synthesis_spec; + 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 - common_options.is_ogg = treat_as_ogg; - common_options.use_first_serial_number = !option_values.has_serial_number; - common_options.serial_number = option_values.serial_number; + 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 - common_options.channel_map_none = option_values.channel_map_none; - - if(output_format == RAW) { - raw_decode_options_t options; + decode_options.channel_map_none = option_values.channel_map_none; + decode_options.format = output_format; - options.common = common_options; - options.is_big_endian = option_values.format_is_big_endian; - options.is_unsigned_samples = option_values.format_is_unsigned_samples; + 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_raw(infilename, option_values.test_only? 0 : outfilename, option_values.analyze, option_values.aopts, options); + retval = flac__decode_file(infilename, option_values.test_only? 0 : outfilename, option_values.analyze, option_values.aopts, decode_options); } else { - wav_decode_options_t options; + decode_options.format_options.iff.foreign_metadata = foreign_metadata; - options.common = common_options; - options.foreign_metadata = 0; + retval = flac__decode_file(infilename, option_values.test_only? 0 : outfilename, option_values.analyze, option_values.aopts, decode_options); - /* read foreign metadata if requested */ - if(option_values.keep_foreign_metadata) { - if(0 == (options.foreign_metadata = flac__foreign_metadata_new(output_format==AIF? FOREIGN_BLOCK_TYPE__AIFF : FOREIGN_BLOCK_TYPE__RIFF))) { - flac__utils_printf(stderr, 1, "ERROR: creating foreign metadata object\n"); - return 1; - } - } - - if(output_format == AIF) - retval = flac__decode_aiff(infilename, option_values.test_only? 0 : outfilename, option_values.analyze, option_values.aopts, options); - else - retval = flac__decode_wav(infilename, option_values.test_only? 0 : outfilename, option_values.analyze, option_values.aopts, options); - - if(options.foreign_metadata) - flac__foreign_metadata_delete(options.foreign_metadata); } + if(foreign_metadata) + flac__foreign_metadata_delete(foreign_metadata); + if(retval == 0 && strcmp(infilename, "-")) { - if(strcmp(outfilename, "-")) + 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) - unlink(infilename); + flac_unlink(infilename); } return retval; @@ -2078,34 +2337,62 @@ int decode_file(const char *infilename) const char *get_encoded_outfilename(const char *infilename) { const char *suffix = (option_values.use_ogg? ".oga" : ".flac"); - return get_outfilename(infilename, suffix); + 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 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(option_values.force_raw_format) { + else if(format == FORMAT_RAW) { suffix = ".raw"; } - else if(option_values.force_aiff_format) { + 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(infilename, suffix); + 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]; /* @@@ bad MAGIC NUMBER */ + static char buffer[4096]; if(0 == strcmp(infilename, "-") || option_values.force_to_stdout) { - strcpy(buffer, "-"); + buffer [0] = '-'; + buffer [1] = 0; } else { char *p; @@ -2153,29 +2440,3 @@ char *local_strdup(const char *source) die("out of memory during strdup()"); return ret; } - -#ifdef _MSC_VER -/* There's no strtoll() in MSVC6 so we just write a specialized one */ -FLAC__int64 local__strtoll(const char *src, char **endptr) -{ - FLAC__bool neg = false; - FLAC__int64 ret = 0; - int c; - FLAC__ASSERT(0 != src); - if(*src == '-') { - neg = true; - src++; - } - while(0 != (c = *src)) { - c -= '0'; - if(c >= 0 && c <= 9) - ret = (ret * 10) + c; - else - break; - src++; - } - if(endptr) - *endptr = (char*)src; - return neg? -ret : ret; -} -#endif diff --git a/3rdparty/libflac/src/flac/utils.c b/3rdparty/libflac/src/flac/utils.c index bca8af761cc..446150d41de 100644 --- a/3rdparty/libflac/src/flac/utils.c +++ b/3rdparty/libflac/src/flac/utils.c @@ -1,5 +1,6 @@ /* flac - Command-line FLAC encoder/decoder - * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson + * 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 @@ -11,23 +12,36 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * You 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 HAVE_CONFIG_H +#ifdef HAVE_CONFIG_H # include <config.h> #endif -#include "utils.h" -#include "FLAC/assert.h" -#include "FLAC/metadata.h" #include <math.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#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"; @@ -42,8 +56,18 @@ static FLAC__bool local__parse_uint64_(const char *s, FLAC__uint64 *value) return false; while('\0' != (c = *s++)) - if(c >= '0' && c <= '9') - ret = ret * 10 + (c - '0'); + 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; @@ -54,8 +78,8 @@ static FLAC__bool local__parse_uint64_(const char *s, FLAC__uint64 *value) static FLAC__bool local__parse_timecode_(const char *s, double *value) { double ret; - unsigned i; - char c; + uint32_t i; + char c, *endptr; /* parse [0-9][0-9]*: */ c = *s++; @@ -74,21 +98,18 @@ static FLAC__bool local__parse_timecode_(const char *s, double *value) /* parse [0-9]*[.,]?[0-9]* i.e. a sign-less rational number (. or , OK for fractional seconds, to support different locales) */ if(strspn(s, "1234567890.,") != strlen(s)) return false; - { - const char *p = strpbrk(s, ".,"); - if(p && 0 != strpbrk(++p, ".,")) - return false; - } - ret += atof(s); + 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, unsigned *track, unsigned *index) +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; - unsigned t = 0, i = 0; + uint32_t t = 0, i = 0; char c; while(end? s < end : *s != '\0') { @@ -112,7 +133,7 @@ static FLAC__bool local__parse_cue_(const char *s, const char *end, unsigned *tr return false; } *track = t; - *index = i; + *indx = i; return got_track && got_index; } @@ -121,20 +142,20 @@ static FLAC__bool local__parse_cue_(const char *s, const char *end, unsigned *tr * does not require sorted cuesheets). but if it's not sorted, picking a * nearest cue point has no significance. */ -static FLAC__uint64 local__find_closest_cue_(const FLAC__StreamMetadata_CueSheet *cuesheet, unsigned track, unsigned index, FLAC__uint64 total_samples, FLAC__bool look_forward) +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 >= index)) + 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 <= index)) + 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; } @@ -149,9 +170,109 @@ void flac__utils_printf(FILE *stream, int level, const char *format, ...) va_start(args, format); - (void) vfprintf(stream, format, args); + (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); } } @@ -189,6 +310,8 @@ FLAC__bool flac__utils_parse_skip_until_specification(const char *s, utils__Skip 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); @@ -207,13 +330,17 @@ FLAC__bool flac__utils_parse_skip_until_specification(const char *s, utils__Skip return true; } -void flac__utils_canonicalize_skip_until_specification(utils__SkipUntilSpecification *spec, unsigned sample_rate) +FLAC__bool flac__utils_canonicalize_skip_until_specification(utils__SkipUntilSpecification *spec, uint32_t sample_rate) { FLAC__ASSERT(0 != spec); if(!spec->value_is_samples) { - spec->value.samples = (FLAC__int64)(spec->value.seconds * (double)sample_rate); + 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) @@ -281,13 +408,9 @@ FLAC__bool flac__utils_set_channel_mask_tag(FLAC__StreamMetadata *object, FLAC__ 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 */ + FLAC__ASSERT(strlen(CHANNEL_MASK_TAG)+1+2+16+1 <= sizeof(tag)); /* +1 for =, +2 for 0x, +16 for digits, +1 for NUL */ entry.entry = (FLAC__byte*)tag; -#if defined _MSC_VER || defined __MINGW32__ - if((entry.length = _snprintf(tag, sizeof(tag), "%s=0x%04X", CHANNEL_MASK_TAG, (unsigned)channel_mask)) >= sizeof(tag)) -#else - if((entry.length = snprintf(tag, sizeof(tag), "%s=0x%04X", CHANNEL_MASK_TAG, (unsigned)channel_mask)) >= sizeof(tag)) -#endif + 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; @@ -297,7 +420,7 @@ FLAC__bool flac__utils_set_channel_mask_tag(FLAC__StreamMetadata *object, FLAC__ FLAC__bool flac__utils_get_channel_mask_tag(const FLAC__StreamMetadata *object, FLAC__uint32 *channel_mask) { int offset; - unsigned val; + uint32_t val; char *p; FLAC__ASSERT(object); FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); @@ -307,7 +430,7 @@ FLAC__bool flac__utils_get_channel_mask_tag(const FLAC__StreamMetadata *object, return false; if(0 == (p = strchr((const char *)object->data.vorbis_comment.comments[offset].entry, '='))) /* should never happen, but just in case */ return false; - if(strncmp(p, "=0x", 3)) + if(FLAC__STRNCASECMP(p, "=0x", 3)) return false; if(sscanf(p+3, "%x", &val) != 1) return false; diff --git a/3rdparty/libflac/src/flac/utils.h b/3rdparty/libflac/src/flac/utils.h index 74ab29e3e3e..931b4a6e5df 100644 --- a/3rdparty/libflac/src/flac/utils.h +++ b/3rdparty/libflac/src/flac/utils.h @@ -1,5 +1,6 @@ /* flac - Command-line FLAC encoder/decoder - * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson + * 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 @@ -11,15 +12,15 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * You 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 -#if HAVE_CONFIG_H +#ifdef HAVE_CONFIG_H # include <config.h> #endif @@ -27,6 +28,12 @@ #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; @@ -51,8 +58,15 @@ size_t flac__utils_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stre 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); -void flac__utils_canonicalize_skip_until_specification(utils__SkipUntilSpecification *spec, unsigned sample_rate); +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); diff --git a/3rdparty/libflac/src/flac/version.rc b/3rdparty/libflac/src/flac/version.rc new file mode 100644 index 00000000000..00842b924c5 --- /dev/null +++ b/3rdparty/libflac/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/3rdparty/libflac/src/flac/vorbiscomment.c b/3rdparty/libflac/src/flac/vorbiscomment.c index 6b35a1e6359..3941ec24080 100644 --- a/3rdparty/libflac/src/flac/vorbiscomment.c +++ b/3rdparty/libflac/src/flac/vorbiscomment.c @@ -1,5 +1,6 @@ /* flac - Command-line FLAC encoder/decoder - * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson + * 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 @@ -11,12 +12,12 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * You 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 HAVE_CONFIG_H +#ifdef HAVE_CONFIG_H # include <config.h> #endif @@ -29,6 +30,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include "share/compat.h" /* @@ -40,7 +42,7 @@ 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; + 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; @@ -61,7 +63,7 @@ static char *local_strdup(const char *source) return ret; } -static FLAC__bool parse_vorbis_comment_field(const char *field_ref, char **field, char **name, char **value, unsigned *length, const char **violation) +static 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", @@ -102,7 +104,7 @@ static FLAC__bool parse_vorbis_comment_field(const char *field_ref, char **field 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; + char *converted = NULL; FLAC__ASSERT(0 != block); FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); @@ -113,7 +115,7 @@ static FLAC__bool set_vc_field(FLAC__StreamMetadata *block, const Argument_VcFie /* read the file into 'data' */ FILE *f = 0; char *data = 0; - const off_t size = grabbag__file_get_filesize(field->field_value); + 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; @@ -125,7 +127,7 @@ static FLAC__bool set_vc_field(FLAC__StreamMetadata *block, const Argument_VcFie if(0 == (data = malloc(size+1))) die("out of memory allocating tag value"); data[size] = '\0'; - if(0 == (f = fopen(field->field_value, "rb")) || fread(data, 1, size, f) != (size_t)size) { + if(0 == (f = flac_fopen(field->field_value, "rb")) || fread(data, 1, size, f) != (size_t)size) { free(data); if(f) fclose(f); @@ -169,6 +171,9 @@ static FLAC__bool set_vc_field(FLAC__StreamMetadata *block, const Argument_VcFie } 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; } @@ -180,6 +185,7 @@ static FLAC__bool set_vc_field(FLAC__StreamMetadata *block, const Argument_VcFie *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) @@ -188,7 +194,7 @@ static FLAC__bool set_vc_field(FLAC__StreamMetadata *block, const Argument_VcFie * our previous parsing has already established that the field * name is OK, so it must be the field value */ - *violation = "tag value for is not valid UTF-8"; + *violation = "tag value is not valid UTF-8"; return false; } @@ -237,7 +243,7 @@ FLAC__bool flac__vorbiscomment_add(FLAC__StreamMetadata *block, const char *comm return false; } - if(!set_vc_field(block, &parsed, &dummy, raw, violation)) { + if(parsed.field_value_length > 0 && !set_vc_field(block, &parsed, &dummy, raw, violation)) { free_field(&parsed); return false; } diff --git a/3rdparty/libflac/src/flac/vorbiscomment.h b/3rdparty/libflac/src/flac/vorbiscomment.h index 1ff70067867..a6dcb164bf9 100644 --- a/3rdparty/libflac/src/flac/vorbiscomment.h +++ b/3rdparty/libflac/src/flac/vorbiscomment.h @@ -1,5 +1,6 @@ /* flac - Command-line FLAC encoder/decoder - * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson + * 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 @@ -11,9 +12,9 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * You 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 |