From 40501a87751e2f39f6631ac3aef40df4223451d3 Mon Sep 17 00:00:00 2001 From: Zakk Date: Tue, 12 Mar 2024 19:28:51 -0400 Subject: [PATCH] Update to latest libchdr zstd compression and removal of flac (moved to single file implementation) --- Makefile | 8 +- lib/flac/include/FLAC/all.h | 371 - lib/flac/include/FLAC/assert.h | 46 - lib/flac/include/FLAC/callback.h | 185 - lib/flac/include/FLAC/export.h | 97 - lib/flac/include/FLAC/format.h | 1025 -- lib/flac/include/FLAC/metadata.h | 2182 --- lib/flac/include/FLAC/ordinals.h | 85 - lib/flac/include/FLAC/stream_decoder.h | 1559 -- lib/flac/include/FLAC/stream_encoder.h | 1790 --- lib/flac/src/bitmath.c | 73 - lib/flac/src/bitreader.c | 1092 -- lib/flac/src/bitwriter.c | 885 -- lib/flac/src/cpu.c | 285 - lib/flac/src/crc.c | 436 - lib/flac/src/fixed.c | 395 - lib/flac/src/flac.pc.in | 12 - lib/flac/src/float.c | 302 - lib/flac/src/format.c | 589 - lib/flac/src/include/private/Makefile.am | 53 - lib/flac/src/include/private/Makefile.in | 607 - lib/flac/src/include/private/all.h | 50 - lib/flac/src/include/private/bitmath.h | 210 - lib/flac/src/include/private/bitreader.h | 91 - lib/flac/src/include/private/bitwriter.h | 104 - lib/flac/src/include/private/cpu.h | 195 - lib/flac/src/include/private/crc.h | 60 - lib/flac/src/include/private/fixed.h | 107 - lib/flac/src/include/private/float.h | 95 - lib/flac/src/include/private/format.h | 45 - lib/flac/src/include/private/lpc.h | 263 - lib/flac/src/include/private/macros.h | 72 - lib/flac/src/include/private/md5.h | 50 - lib/flac/src/include/private/memory.h | 58 - lib/flac/src/include/private/metadata.h | 46 - .../src/include/private/ogg_decoder_aspect.h | 80 - .../src/include/private/ogg_encoder_aspect.h | 63 - lib/flac/src/include/private/ogg_helper.h | 44 - lib/flac/src/include/private/ogg_mapping.h | 64 - lib/flac/src/include/private/stream_encoder.h | 67 - .../include/private/stream_encoder_framing.h | 46 - lib/flac/src/include/private/window.h | 74 - lib/flac/src/include/protected/Makefile.am | 35 - lib/flac/src/include/protected/Makefile.in | 589 - lib/flac/src/include/protected/all.h | 39 - .../src/include/protected/stream_decoder.h | 65 - .../src/include/protected/stream_encoder.h | 118 - lib/flac/src/include/share/Makefile.am | 19 - lib/flac/src/include/share/Makefile.in | 682 - lib/flac/src/include/share/alloc.h | 219 - lib/flac/src/include/share/compat.h | 205 - lib/flac/src/include/share/endswap.h | 84 - lib/flac/src/include/share/getopt.h | 184 - lib/flac/src/include/share/grabbag.h | 30 - .../src/include/share/grabbag/Makefile.am | 8 - .../src/include/share/grabbag/Makefile.in | 492 - lib/flac/src/include/share/grabbag/cuesheet.h | 43 - lib/flac/src/include/share/grabbag/file.h | 65 - lib/flac/src/include/share/grabbag/picture.h | 54 - .../src/include/share/grabbag/replaygain.h | 73 - .../src/include/share/grabbag/seektable.h | 39 - lib/flac/src/include/share/macros.h | 45 - lib/flac/src/include/share/msvc2005_int.h | 53 - lib/flac/src/include/share/private.h | 45 - .../src/include/share/replaygain_analysis.h | 59 - .../src/include/share/replaygain_synthesis.h | 52 - lib/flac/src/include/share/safe_str.h | 69 - lib/flac/src/include/share/utf8.h | 25 - lib/flac/src/include/share/win_utf8_io.h | 61 - .../include/share/windows_unicode_filenames.h | 63 - lib/flac/src/lpc.c | 1357 -- lib/flac/src/md5.c | 517 - lib/flac/src/memory.c | 219 - lib/flac/src/metadata_iterators.c | 3481 ----- lib/flac/src/metadata_object.c | 1821 --- lib/flac/src/stream_decoder.c | 3404 ----- lib/flac/src/stream_encoder.c | 4578 ------ lib/flac/src/stream_encoder_framing.c | 554 - lib/flac/src/window.c | 282 - lib/libchdr/include/dr_libs/dr_flac.h | 12536 ++++++++++++++++ lib/libchdr/include/libchdr/chd.h | 11 +- lib/libchdr/include/libchdr/chdconfig.h | 2 +- lib/libchdr/include/libchdr/coretypes.h | 67 +- lib/libchdr/include/libchdr/flac.h | 9 +- lib/libchdr/libchdr_cdrom.c | 2 +- lib/libchdr/libchdr_chd.c | 789 +- lib/libchdr/libchdr_flac.c | 250 +- lib/libchdr/libchdr_huffman.c | 6 +- lib/zstd/lib/common/allocations.h | 55 + lib/zstd/lib/common/bits.h | 200 + lib/zstd/lib/common/bitstream.h | 437 + lib/zstd/lib/common/compiler.h | 358 + lib/zstd/lib/common/cpu.h | 213 + lib/zstd/lib/common/debug.c | 24 + lib/zstd/lib/common/debug.h | 107 + lib/zstd/lib/common/entropy_common.c | 340 + lib/zstd/lib/common/error_private.c | 63 + lib/zstd/lib/common/error_private.h | 159 + lib/zstd/lib/common/fse.h | 639 + lib/zstd/lib/common/fse_decompress.c | 311 + lib/zstd/lib/common/huf.h | 273 + lib/zstd/lib/common/mem.h | 435 + lib/zstd/lib/common/pool.c | 371 + lib/zstd/lib/common/pool.h | 90 + lib/zstd/lib/common/portability_macros.h | 156 + lib/zstd/lib/common/threading.c | 176 + lib/zstd/lib/common/threading.h | 150 + lib/zstd/lib/common/xxhash.c | 24 + lib/zstd/lib/common/xxhash.h | 5686 +++++++ lib/zstd/lib/common/zstd_common.c | 48 + lib/zstd/lib/common/zstd_deps.h | 111 + lib/zstd/lib/common/zstd_internal.h | 392 + lib/zstd/lib/common/zstd_trace.h | 163 + lib/zstd/lib/decompress/huf_decompress.c | 1882 +++ lib/zstd/lib/decompress/zstd_ddict.c | 244 + lib/zstd/lib/decompress/zstd_ddict.h | 44 + lib/zstd/lib/decompress/zstd_decompress.c | 2355 +++ .../lib/decompress/zstd_decompress_block.c | 2192 +++ .../lib/decompress/zstd_decompress_block.h | 73 + .../lib/decompress/zstd_decompress_internal.h | 238 + lib/zstd/lib/zdict.h | 474 + lib/zstd/lib/zstd.h | 3020 ++++ lib/zstd/lib/zstd_errors.h | 114 + support/chd/mister_chd.cpp | 2 +- 124 files changed, 35053 insertions(+), 33927 deletions(-) delete mode 100644 lib/flac/include/FLAC/all.h delete mode 100644 lib/flac/include/FLAC/assert.h delete mode 100644 lib/flac/include/FLAC/callback.h delete mode 100644 lib/flac/include/FLAC/export.h delete mode 100644 lib/flac/include/FLAC/format.h delete mode 100644 lib/flac/include/FLAC/metadata.h delete mode 100644 lib/flac/include/FLAC/ordinals.h delete mode 100644 lib/flac/include/FLAC/stream_decoder.h delete mode 100644 lib/flac/include/FLAC/stream_encoder.h delete mode 100644 lib/flac/src/bitmath.c delete mode 100644 lib/flac/src/bitreader.c delete mode 100644 lib/flac/src/bitwriter.c delete mode 100644 lib/flac/src/cpu.c delete mode 100644 lib/flac/src/crc.c delete mode 100644 lib/flac/src/fixed.c delete mode 100644 lib/flac/src/flac.pc.in delete mode 100644 lib/flac/src/float.c delete mode 100644 lib/flac/src/format.c delete mode 100644 lib/flac/src/include/private/Makefile.am delete mode 100644 lib/flac/src/include/private/Makefile.in delete mode 100644 lib/flac/src/include/private/all.h delete mode 100644 lib/flac/src/include/private/bitmath.h delete mode 100644 lib/flac/src/include/private/bitreader.h delete mode 100644 lib/flac/src/include/private/bitwriter.h delete mode 100644 lib/flac/src/include/private/cpu.h delete mode 100644 lib/flac/src/include/private/crc.h delete mode 100644 lib/flac/src/include/private/fixed.h delete mode 100644 lib/flac/src/include/private/float.h delete mode 100644 lib/flac/src/include/private/format.h delete mode 100644 lib/flac/src/include/private/lpc.h delete mode 100644 lib/flac/src/include/private/macros.h delete mode 100644 lib/flac/src/include/private/md5.h delete mode 100644 lib/flac/src/include/private/memory.h delete mode 100644 lib/flac/src/include/private/metadata.h delete mode 100644 lib/flac/src/include/private/ogg_decoder_aspect.h delete mode 100644 lib/flac/src/include/private/ogg_encoder_aspect.h delete mode 100644 lib/flac/src/include/private/ogg_helper.h delete mode 100644 lib/flac/src/include/private/ogg_mapping.h delete mode 100644 lib/flac/src/include/private/stream_encoder.h delete mode 100644 lib/flac/src/include/private/stream_encoder_framing.h delete mode 100644 lib/flac/src/include/private/window.h delete mode 100644 lib/flac/src/include/protected/Makefile.am delete mode 100644 lib/flac/src/include/protected/Makefile.in delete mode 100644 lib/flac/src/include/protected/all.h delete mode 100644 lib/flac/src/include/protected/stream_decoder.h delete mode 100644 lib/flac/src/include/protected/stream_encoder.h delete mode 100644 lib/flac/src/include/share/Makefile.am delete mode 100644 lib/flac/src/include/share/Makefile.in delete mode 100644 lib/flac/src/include/share/alloc.h delete mode 100644 lib/flac/src/include/share/compat.h delete mode 100644 lib/flac/src/include/share/endswap.h delete mode 100644 lib/flac/src/include/share/getopt.h delete mode 100644 lib/flac/src/include/share/grabbag.h delete mode 100644 lib/flac/src/include/share/grabbag/Makefile.am delete mode 100644 lib/flac/src/include/share/grabbag/Makefile.in delete mode 100644 lib/flac/src/include/share/grabbag/cuesheet.h delete mode 100644 lib/flac/src/include/share/grabbag/file.h delete mode 100644 lib/flac/src/include/share/grabbag/picture.h delete mode 100644 lib/flac/src/include/share/grabbag/replaygain.h delete mode 100644 lib/flac/src/include/share/grabbag/seektable.h delete mode 100644 lib/flac/src/include/share/macros.h delete mode 100644 lib/flac/src/include/share/msvc2005_int.h delete mode 100644 lib/flac/src/include/share/private.h delete mode 100644 lib/flac/src/include/share/replaygain_analysis.h delete mode 100644 lib/flac/src/include/share/replaygain_synthesis.h delete mode 100644 lib/flac/src/include/share/safe_str.h delete mode 100644 lib/flac/src/include/share/utf8.h delete mode 100644 lib/flac/src/include/share/win_utf8_io.h delete mode 100644 lib/flac/src/include/share/windows_unicode_filenames.h delete mode 100644 lib/flac/src/lpc.c delete mode 100644 lib/flac/src/md5.c delete mode 100644 lib/flac/src/memory.c delete mode 100644 lib/flac/src/metadata_iterators.c delete mode 100644 lib/flac/src/metadata_object.c delete mode 100644 lib/flac/src/stream_decoder.c delete mode 100644 lib/flac/src/stream_encoder.c delete mode 100644 lib/flac/src/stream_encoder_framing.c delete mode 100644 lib/flac/src/window.c create mode 100644 lib/libchdr/include/dr_libs/dr_flac.h create mode 100644 lib/zstd/lib/common/allocations.h create mode 100644 lib/zstd/lib/common/bits.h create mode 100644 lib/zstd/lib/common/bitstream.h create mode 100644 lib/zstd/lib/common/compiler.h create mode 100644 lib/zstd/lib/common/cpu.h create mode 100644 lib/zstd/lib/common/debug.c create mode 100644 lib/zstd/lib/common/debug.h create mode 100644 lib/zstd/lib/common/entropy_common.c create mode 100644 lib/zstd/lib/common/error_private.c create mode 100644 lib/zstd/lib/common/error_private.h create mode 100644 lib/zstd/lib/common/fse.h create mode 100644 lib/zstd/lib/common/fse_decompress.c create mode 100644 lib/zstd/lib/common/huf.h create mode 100644 lib/zstd/lib/common/mem.h create mode 100644 lib/zstd/lib/common/pool.c create mode 100644 lib/zstd/lib/common/pool.h create mode 100644 lib/zstd/lib/common/portability_macros.h create mode 100644 lib/zstd/lib/common/threading.c create mode 100644 lib/zstd/lib/common/threading.h create mode 100644 lib/zstd/lib/common/xxhash.c create mode 100644 lib/zstd/lib/common/xxhash.h create mode 100644 lib/zstd/lib/common/zstd_common.c create mode 100644 lib/zstd/lib/common/zstd_deps.h create mode 100644 lib/zstd/lib/common/zstd_internal.h create mode 100644 lib/zstd/lib/common/zstd_trace.h create mode 100644 lib/zstd/lib/decompress/huf_decompress.c create mode 100644 lib/zstd/lib/decompress/zstd_ddict.c create mode 100644 lib/zstd/lib/decompress/zstd_ddict.h create mode 100644 lib/zstd/lib/decompress/zstd_decompress.c create mode 100644 lib/zstd/lib/decompress/zstd_decompress_block.c create mode 100644 lib/zstd/lib/decompress/zstd_decompress_block.h create mode 100644 lib/zstd/lib/decompress/zstd_decompress_internal.h create mode 100644 lib/zstd/lib/zdict.h create mode 100644 lib/zstd/lib/zstd.h create mode 100644 lib/zstd/lib/zstd_errors.h diff --git a/Makefile b/Makefile index fb8d6c9..b5f03ab 100644 --- a/Makefile +++ b/Makefile @@ -21,9 +21,8 @@ INCLUDE += -I./lib/libco INCLUDE += -I./lib/miniz INCLUDE += -I./lib/md5 INCLUDE += -I./lib/lzma +INCLUDE += -I./lib/zstd/lib INCLUDE += -I./lib/libchdr/include -INCLUDE += -I./lib/flac/include -INCLUDE += -I./lib/flac/src/include INCLUDE += -I./lib/bluetooth INCLUDE += -I./lib/serial_server/library @@ -32,7 +31,8 @@ C_SRC = $(wildcard *.c) \ $(wildcard ./lib/miniz/*.c) \ $(wildcard ./lib/md5/*.c) \ $(wildcard ./lib/lzma/*.c) \ - $(wildcard ./lib/flac/src/*.c) \ + $(wildcard ./lib/zstd/lib/common/*.c) \ + $(wildcard ./lib/zstd/lib/decompress/*.c) \ $(wildcard ./lib/libchdr/*.c) \ lib/libco/arm.c @@ -47,7 +47,7 @@ IMLIB2_LIB = -Llib/imlib2 -lfreetype -lbz2 -lpng16 -lz -lImlib2 OBJ = $(C_SRC:.c=.c.o) $(CPP_SRC:.cpp=.cpp.o) $(IMG:.png=.png.o) DEP = $(C_SRC:.c=.c.d) $(CPP_SRC:.cpp=.cpp.d) -DFLAGS = $(INCLUDE) -D_7ZIP_ST -DPACKAGE_VERSION=\"1.3.3\" -DFLAC_API_EXPORTS -DFLAC__HAS_OGG=0 -DHAVE_LROUND -DHAVE_STDINT_H -DHAVE_STDLIB_H -DHAVE_SYS_PARAM_H -DENABLE_64_BIT_WORDS=0 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -DVDATE=\"`date +"%y%m%d"`\" +DFLAGS = $(INCLUDE) -D_7ZIP_ST -DPACKAGE_VERSION=\"1.3.3\" -DHAVE_LROUND -DHAVE_STDINT_H -DHAVE_STDLIB_H -DHAVE_SYS_PARAM_H -DENABLE_64_BIT_WORDS=0 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -DVDATE=\"`date +"%y%m%d"`\" CFLAGS = $(DFLAGS) -Wall -Wextra -Wno-strict-aliasing -Wno-stringop-overflow -Wno-stringop-truncation -Wno-format-truncation -Wno-psabi -Wno-restrict -c -O3 LFLAGS = -lc -lstdc++ -lm -lrt $(IMLIB2_LIB) -Llib/bluetooth -lbluetooth -lpthread diff --git a/lib/flac/include/FLAC/all.h b/lib/flac/include/FLAC/all.h deleted file mode 100644 index b37a68f..0000000 --- a/lib/flac/include/FLAC/all.h +++ /dev/null @@ -1,371 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__ALL_H -#define FLAC__ALL_H - -#include "export.h" - -#include "assert.h" -#include "callback.h" -#include "format.h" -#include "metadata.h" -#include "ordinals.h" -#include "stream_decoder.h" -#include "stream_encoder.h" - -/** \mainpage - * - * \section intro Introduction - * - * This is the documentation for the FLAC C and C++ APIs. It is - * highly interconnected; this introduction should give you a top - * level idea of the structure and how to find the information you - * need. As a prerequisite you should have at least a basic - * knowledge of the FLAC format, documented - * here. - * - * \section c_api FLAC C API - * - * The FLAC C API is the interface to libFLAC, a set of structures - * describing the components of FLAC streams, and functions for - * encoding and decoding streams, as well as manipulating FLAC - * metadata in files. The public include files will be installed - * in your include area (for example /usr/include/FLAC/...). - * - * By writing a little code and linking against libFLAC, it is - * relatively easy to add FLAC support to another program. The - * library is licensed under Xiph's BSD license. - * Complete source code of libFLAC as well as the command-line - * encoder and plugins is available and is a useful source of - * examples. - * - * Aside from encoders and decoders, libFLAC provides a powerful - * metadata interface for manipulating metadata in FLAC files. It - * allows the user to add, delete, and modify FLAC metadata blocks - * and it can automatically take advantage of PADDING blocks to avoid - * rewriting the entire FLAC file when changing the size of the - * metadata. - * - * libFLAC usually only requires the standard C library and C math - * library. In particular, threading is not used so there is no - * dependency on a thread library. However, libFLAC does not use - * global variables and should be thread-safe. - * - * libFLAC also supports encoding to and decoding from Ogg FLAC. - * However the metadata editing interfaces currently have limited - * read-only support for Ogg FLAC files. - * - * \section cpp_api FLAC C++ API - * - * The FLAC C++ API is a set of classes that encapsulate the - * structures and functions in libFLAC. They provide slightly more - * functionality with respect to metadata but are otherwise - * equivalent. For the most part, they share the same usage as - * their counterparts in libFLAC, and the FLAC C API documentation - * can be used as a supplement. The public include files - * for the C++ API will be installed in your include area (for - * example /usr/include/FLAC++/...). - * - * libFLAC++ is also licensed under - * Xiph's BSD license. - * - * \section getting_started Getting Started - * - * A good starting point for learning the API is to browse through - * the modules. Modules are logical - * groupings of related functions or classes, which correspond roughly - * to header files or sections of header files. Each module includes a - * detailed description of the general usage of its functions or - * classes. - * - * From there you can go on to look at the documentation of - * individual functions. You can see different views of the individual - * functions through the links in top bar across this page. - * - * If you prefer a more hands-on approach, you can jump right to some - * example code. - * - * \section porting_guide Porting Guide - * - * Starting with FLAC 1.1.3 a \link porting Porting Guide \endlink - * has been introduced which gives detailed instructions on how to - * port your code to newer versions of FLAC. - * - * \section embedded_developers Embedded Developers - * - * libFLAC has grown larger over time as more functionality has been - * included, but much of it may be unnecessary for a particular embedded - * implementation. Unused parts may be pruned by some simple editing of - * src/libFLAC/Makefile.am. In general, the decoders, encoders, and - * metadata interface are all independent from each other. - * - * It is easiest to just describe the dependencies: - * - * - All modules depend on the \link flac_format Format \endlink module. - * - The decoders and encoders depend on the bitbuffer. - * - The decoder is independent of the encoder. The encoder uses the - * decoder because of the verify feature, but this can be removed if - * not needed. - * - Parts of the metadata interface require the stream decoder (but not - * the encoder). - * - Ogg support is selectable through the compile time macro - * \c FLAC__HAS_OGG. - * - * For example, if your application only requires the stream decoder, no - * encoder, and no metadata interface, you can remove the stream encoder - * and the metadata interface, which will greatly reduce the size of the - * library. - * - * Also, there are several places in the libFLAC code with comments marked - * with "OPT:" where a #define can be changed to enable code that might be - * faster on a specific platform. Experimenting with these can yield faster - * binaries. - */ - -/** \defgroup porting Porting Guide for New Versions - * - * This module describes differences in the library interfaces from - * version to version. It assists in the porting of code that uses - * the libraries to newer versions of FLAC. - * - * One simple facility for making porting easier that has been added - * in FLAC 1.1.3 is a set of \c #defines in \c export.h of each - * library's includes (e.g. \c include/FLAC/export.h). The - * \c #defines mirror the libraries' - * libtool version numbers, - * e.g. in libFLAC there are \c FLAC_API_VERSION_CURRENT, - * \c FLAC_API_VERSION_REVISION, and \c FLAC_API_VERSION_AGE. - * These can be used to support multiple versions of an API during the - * transition phase, e.g. - * - * \code - * #if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT <= 7 - * legacy code - * #else - * new code - * #endif - * \endcode - * - * The source will work for multiple versions and the legacy code can - * easily be removed when the transition is complete. - * - * Another available symbol is FLAC_API_SUPPORTS_OGG_FLAC (defined in - * include/FLAC/export.h), which can be used to determine whether or not - * the library has been compiled with support for Ogg FLAC. This is - * simpler than trying to call an Ogg init function and catching the - * error. - */ - -/** \defgroup porting_1_1_2_to_1_1_3 Porting from FLAC 1.1.2 to 1.1.3 - * \ingroup porting - * - * \brief - * This module describes porting from FLAC 1.1.2 to FLAC 1.1.3. - * - * The main change between the APIs in 1.1.2 and 1.1.3 is that they have - * been simplified. First, libOggFLAC has been merged into libFLAC and - * libOggFLAC++ has been merged into libFLAC++. Second, both the three - * decoding layers and three encoding layers have been merged into a - * single stream decoder and stream encoder. That is, the functionality - * of FLAC__SeekableStreamDecoder and FLAC__FileDecoder has been merged - * into FLAC__StreamDecoder, and FLAC__SeekableStreamEncoder and - * FLAC__FileEncoder into FLAC__StreamEncoder. Only the - * FLAC__StreamDecoder and FLAC__StreamEncoder remain. What this means - * is there is now a single API that can be used to encode or decode - * streams to/from native FLAC or Ogg FLAC and the single API can work - * on both seekable and non-seekable streams. - * - * Instead of creating an encoder or decoder of a certain layer, now the - * client will always create a FLAC__StreamEncoder or - * FLAC__StreamDecoder. The old layers are now differentiated by the - * initialization function. For example, for the decoder, - * FLAC__stream_decoder_init() has been replaced by - * FLAC__stream_decoder_init_stream(). This init function takes - * callbacks for the I/O, and the seeking callbacks are optional. This - * allows the client to use the same object for seekable and - * non-seekable streams. For decoding a FLAC file directly, the client - * can use FLAC__stream_decoder_init_file() and pass just a filename - * and fewer callbacks; most of the other callbacks are supplied - * internally. For situations where fopen()ing by filename is not - * possible (e.g. Unicode filenames on Windows) the client can instead - * open the file itself and supply the FILE* to - * FLAC__stream_decoder_init_FILE(). The init functions now returns a - * FLAC__StreamDecoderInitStatus instead of FLAC__StreamDecoderState. - * Since the callbacks and client data are now passed to the init - * function, the FLAC__stream_decoder_set_*_callback() functions and - * FLAC__stream_decoder_set_client_data() are no longer needed. The - * rest of the calls to the decoder are the same as before. - * - * There are counterpart init functions for Ogg FLAC, e.g. - * FLAC__stream_decoder_init_ogg_stream(). All the rest of the calls - * and callbacks are the same as for native FLAC. - * - * As an example, in FLAC 1.1.2 a seekable stream decoder would have - * been set up like so: - * - * \code - * FLAC__SeekableStreamDecoder *decoder = FLAC__seekable_stream_decoder_new(); - * if(decoder == NULL) do_something; - * FLAC__seekable_stream_decoder_set_md5_checking(decoder, true); - * [... other settings ...] - * FLAC__seekable_stream_decoder_set_read_callback(decoder, my_read_callback); - * FLAC__seekable_stream_decoder_set_seek_callback(decoder, my_seek_callback); - * FLAC__seekable_stream_decoder_set_tell_callback(decoder, my_tell_callback); - * FLAC__seekable_stream_decoder_set_length_callback(decoder, my_length_callback); - * FLAC__seekable_stream_decoder_set_eof_callback(decoder, my_eof_callback); - * FLAC__seekable_stream_decoder_set_write_callback(decoder, my_write_callback); - * FLAC__seekable_stream_decoder_set_metadata_callback(decoder, my_metadata_callback); - * FLAC__seekable_stream_decoder_set_error_callback(decoder, my_error_callback); - * FLAC__seekable_stream_decoder_set_client_data(decoder, my_client_data); - * if(FLAC__seekable_stream_decoder_init(decoder) != FLAC__SEEKABLE_STREAM_DECODER_OK) do_something; - * \endcode - * - * In FLAC 1.1.3 it is like this: - * - * \code - * FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new(); - * if(decoder == NULL) do_something; - * FLAC__stream_decoder_set_md5_checking(decoder, true); - * [... other settings ...] - * if(FLAC__stream_decoder_init_stream( - * decoder, - * my_read_callback, - * my_seek_callback, // or NULL - * my_tell_callback, // or NULL - * my_length_callback, // or NULL - * my_eof_callback, // or NULL - * my_write_callback, - * my_metadata_callback, // or NULL - * my_error_callback, - * my_client_data - * ) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something; - * \endcode - * - * or you could do; - * - * \code - * [...] - * FILE *file = fopen("somefile.flac","rb"); - * if(file == NULL) do_somthing; - * if(FLAC__stream_decoder_init_FILE( - * decoder, - * file, - * my_write_callback, - * my_metadata_callback, // or NULL - * my_error_callback, - * my_client_data - * ) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something; - * \endcode - * - * or just: - * - * \code - * [...] - * if(FLAC__stream_decoder_init_file( - * decoder, - * "somefile.flac", - * my_write_callback, - * my_metadata_callback, // or NULL - * my_error_callback, - * my_client_data - * ) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something; - * \endcode - * - * Another small change to the decoder is in how it handles unparseable - * streams. Before, when the decoder found an unparseable stream - * (reserved for when the decoder encounters a stream from a future - * encoder that it can't parse), it changed the state to - * \c FLAC__STREAM_DECODER_UNPARSEABLE_STREAM. Now the decoder instead - * drops sync and calls the error callback with a new error code - * \c FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM. This is - * more robust. If your error callback does not discriminate on the the - * error state, your code does not need to be changed. - * - * The encoder now has a new setting: - * FLAC__stream_encoder_set_apodization(). This is for setting the - * method used to window the data before LPC analysis. You only need to - * add a call to this function if the default is not suitable. There - * are also two new convenience functions that may be useful: - * FLAC__metadata_object_cuesheet_calculate_cddb_id() and - * FLAC__metadata_get_cuesheet(). - * - * The \a bytes parameter to FLAC__StreamDecoderReadCallback, - * FLAC__StreamEncoderReadCallback, and FLAC__StreamEncoderWriteCallback - * is now \c size_t instead of \c uint32_t. - */ - -/** \defgroup porting_1_1_3_to_1_1_4 Porting from FLAC 1.1.3 to 1.1.4 - * \ingroup porting - * - * \brief - * This module describes porting from FLAC 1.1.3 to FLAC 1.1.4. - * - * There were no changes to any of the interfaces from 1.1.3 to 1.1.4. - * There was a slight change in the implementation of - * FLAC__stream_encoder_set_metadata(); the function now makes a copy - * of the \a metadata array of pointers so the client no longer needs - * to maintain it after the call. The objects themselves that are - * pointed to by the array are still not copied though and must be - * maintained until the call to FLAC__stream_encoder_finish(). - */ - -/** \defgroup porting_1_1_4_to_1_2_0 Porting from FLAC 1.1.4 to 1.2.0 - * \ingroup porting - * - * \brief - * This module describes porting from FLAC 1.1.4 to FLAC 1.2.0. - * - * There were only very minor changes to the interfaces from 1.1.4 to 1.2.0. - * In libFLAC, \c FLAC__format_sample_rate_is_subset() was added. - * In libFLAC++, \c FLAC::Decoder::Stream::get_decode_position() was added. - * - * Finally, value of the constant \c FLAC__FRAME_HEADER_RESERVED_LEN - * has changed to reflect the conversion of one of the reserved bits - * into active use. It used to be \c 2 and now is \c 1. However the - * FLAC frame header length has not changed, so to skip the proper - * number of bits, use \c FLAC__FRAME_HEADER_RESERVED_LEN + - * \c FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN - */ - -/** \defgroup flac FLAC C API - * - * The FLAC C API is the interface to libFLAC, a set of structures - * describing the components of FLAC streams, and functions for - * encoding and decoding streams, as well as manipulating FLAC - * metadata in files. - * - * You should start with the format components as all other modules - * are dependent on it. - */ - -#endif diff --git a/lib/flac/include/FLAC/assert.h b/lib/flac/include/FLAC/assert.h deleted file mode 100644 index 55b3477..0000000 --- a/lib/flac/include/FLAC/assert.h +++ /dev/null @@ -1,46 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__ASSERT_H -#define FLAC__ASSERT_H - -/* we need this since some compilers (like MSVC) leave assert()s on release code (and we don't want to use their ASSERT) */ -#ifndef NDEBUG -#include -#define FLAC__ASSERT(x) assert(x) -#define FLAC__ASSERT_DECLARATION(x) x -#else -#define FLAC__ASSERT(x) -#define FLAC__ASSERT_DECLARATION(x) -#endif - -#endif diff --git a/lib/flac/include/FLAC/callback.h b/lib/flac/include/FLAC/callback.h deleted file mode 100644 index 38e2300..0000000 --- a/lib/flac/include/FLAC/callback.h +++ /dev/null @@ -1,185 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2004-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__CALLBACK_H -#define FLAC__CALLBACK_H - -#include "ordinals.h" -#include /* for size_t */ - -/** \file include/FLAC/callback.h - * - * \brief - * This module defines the structures for describing I/O callbacks - * to the other FLAC interfaces. - * - * See the detailed documentation for callbacks in the - * \link flac_callbacks callbacks \endlink module. - */ - -/** \defgroup flac_callbacks FLAC/callback.h: I/O callback structures - * \ingroup flac - * - * \brief - * This module defines the structures for describing I/O callbacks - * to the other FLAC interfaces. - * - * The purpose of the I/O callback functions is to create a common way - * for the metadata interfaces to handle I/O. - * - * Originally the metadata interfaces required filenames as the way of - * specifying FLAC files to operate on. This is problematic in some - * environments so there is an additional option to specify a set of - * callbacks for doing I/O on the FLAC file, instead of the filename. - * - * In addition to the callbacks, a FLAC__IOHandle type is defined as an - * opaque structure for a data source. - * - * The callback function prototypes are similar (but not identical) to the - * stdio functions fread, fwrite, fseek, ftell, feof, and fclose. If you use - * stdio streams to implement the callbacks, you can pass fread, fwrite, and - * fclose anywhere a FLAC__IOCallback_Read, FLAC__IOCallback_Write, or - * FLAC__IOCallback_Close is required, and a FILE* anywhere a FLAC__IOHandle - * is required. \warning You generally CANNOT directly use fseek or ftell - * for FLAC__IOCallback_Seek or FLAC__IOCallback_Tell since on most systems - * these use 32-bit offsets and FLAC requires 64-bit offsets to deal with - * large files. You will have to find an equivalent function (e.g. ftello), - * or write a wrapper. The same is true for feof() since this is usually - * implemented as a macro, not as a function whose address can be taken. - * - * \{ - */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** This is the opaque handle type used by the callbacks. Typically - * this is a \c FILE* or address of a file descriptor. - */ -typedef void* FLAC__IOHandle; - -/** Signature for the read callback. - * The signature and semantics match POSIX fread() implementations - * and can generally be used interchangeably. - * - * \param ptr The address of the read buffer. - * \param size The size of the records to be read. - * \param nmemb The number of records to be read. - * \param handle The handle to the data source. - * \retval size_t - * The number of records read. - */ -typedef size_t (*FLAC__IOCallback_Read) (void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle); - -/** Signature for the write callback. - * The signature and semantics match POSIX fwrite() implementations - * and can generally be used interchangeably. - * - * \param ptr The address of the write buffer. - * \param size The size of the records to be written. - * \param nmemb The number of records to be written. - * \param handle The handle to the data source. - * \retval size_t - * The number of records written. - */ -typedef size_t (*FLAC__IOCallback_Write) (const void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle); - -/** Signature for the seek callback. - * The signature and semantics mostly match POSIX fseek() WITH ONE IMPORTANT - * EXCEPTION: the offset is a 64-bit type whereas fseek() is generally 'long' - * and 32-bits wide. - * - * \param handle The handle to the data source. - * \param offset The new position, relative to \a whence - * \param whence \c SEEK_SET, \c SEEK_CUR, or \c SEEK_END - * \retval int - * \c 0 on success, \c -1 on error. - */ -typedef int (*FLAC__IOCallback_Seek) (FLAC__IOHandle handle, FLAC__int64 offset, int whence); - -/** Signature for the tell callback. - * The signature and semantics mostly match POSIX ftell() WITH ONE IMPORTANT - * EXCEPTION: the offset is a 64-bit type whereas ftell() is generally 'long' - * and 32-bits wide. - * - * \param handle The handle to the data source. - * \retval FLAC__int64 - * The current position on success, \c -1 on error. - */ -typedef FLAC__int64 (*FLAC__IOCallback_Tell) (FLAC__IOHandle handle); - -/** Signature for the EOF callback. - * The signature and semantics mostly match POSIX feof() but WATCHOUT: - * on many systems, feof() is a macro, so in this case a wrapper function - * must be provided instead. - * - * \param handle The handle to the data source. - * \retval int - * \c 0 if not at end of file, nonzero if at end of file. - */ -typedef int (*FLAC__IOCallback_Eof) (FLAC__IOHandle handle); - -/** Signature for the close callback. - * The signature and semantics match POSIX fclose() implementations - * and can generally be used interchangeably. - * - * \param handle The handle to the data source. - * \retval int - * \c 0 on success, \c EOF on error. - */ -typedef int (*FLAC__IOCallback_Close) (FLAC__IOHandle handle); - -/** A structure for holding a set of callbacks. - * Each FLAC interface that requires a FLAC__IOCallbacks structure will - * describe which of the callbacks are required. The ones that are not - * required may be set to NULL. - * - * If the seek requirement for an interface is optional, you can signify that - * a data source is not seekable by setting the \a seek field to \c NULL. - */ -typedef struct { - FLAC__IOCallback_Read read; - FLAC__IOCallback_Write write; - FLAC__IOCallback_Seek seek; - FLAC__IOCallback_Tell tell; - FLAC__IOCallback_Eof eof; - FLAC__IOCallback_Close close; -} FLAC__IOCallbacks; - -/* \} */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/flac/include/FLAC/export.h b/lib/flac/include/FLAC/export.h deleted file mode 100644 index d52f0bb..0000000 --- a/lib/flac/include/FLAC/export.h +++ /dev/null @@ -1,97 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__EXPORT_H -#define FLAC__EXPORT_H - -/** \file include/FLAC/export.h - * - * \brief - * This module contains #defines and symbols for exporting function - * calls, and providing version information and compiled-in features. - * - * See the \link flac_export export \endlink module. - */ - -/** \defgroup flac_export FLAC/export.h: export symbols - * \ingroup flac - * - * \brief - * This module contains #defines and symbols for exporting function - * calls, and providing version information and compiled-in features. - * - * If you are compiling with MSVC and will link to the static library - * (libFLAC.lib) you should define FLAC__NO_DLL in your project to - * make sure the symbols are exported properly. - * - * \{ - */ - -#if defined(FLAC__NO_DLL) -#define FLAC_API - -#elif defined(_MSC_VER) -#ifdef FLAC_API_EXPORTS -#define FLAC_API __declspec(dllexport) -#else -#define FLAC_API __declspec(dllimport) -#endif - -#elif defined(FLAC__USE_VISIBILITY_ATTR) -#define FLAC_API __attribute__ ((visibility ("default"))) - -#else -#define FLAC_API - -#endif - -/** These #defines will mirror the libtool-based library version number, see - * http://www.gnu.org/software/libtool/manual/libtool.html#Libtool-versioning - */ -#define FLAC_API_VERSION_CURRENT 11 -#define FLAC_API_VERSION_REVISION 0 /**< see above */ -#define FLAC_API_VERSION_AGE 3 /**< see above */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** \c 1 if the library has been compiled with support for Ogg FLAC, else \c 0. */ -extern FLAC_API int FLAC_API_SUPPORTS_OGG_FLAC; - -#ifdef __cplusplus -} -#endif - -/* \} */ - -#endif diff --git a/lib/flac/include/FLAC/format.h b/lib/flac/include/FLAC/format.h deleted file mode 100644 index 769ab8a..0000000 --- a/lib/flac/include/FLAC/format.h +++ /dev/null @@ -1,1025 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__FORMAT_H -#define FLAC__FORMAT_H - -#include "export.h" -#include "ordinals.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** \file include/FLAC/format.h - * - * \brief - * This module contains structure definitions for the representation - * of FLAC format components in memory. These are the basic - * structures used by the rest of the interfaces. - * - * See the detailed documentation in the - * \link flac_format format \endlink module. - */ - -/** \defgroup flac_format FLAC/format.h: format components - * \ingroup flac - * - * \brief - * This module contains structure definitions for the representation - * of FLAC format components in memory. These are the basic - * structures used by the rest of the interfaces. - * - * First, you should be familiar with the - * FLAC format. Many of the values here - * follow directly from the specification. As a user of libFLAC, the - * interesting parts really are the structures that describe the frame - * header and metadata blocks. - * - * The format structures here are very primitive, designed to store - * information in an efficient way. Reading information from the - * structures is easy but creating or modifying them directly is - * more complex. For the most part, as a user of a library, editing - * is not necessary; however, for metadata blocks it is, so there are - * convenience functions provided in the \link flac_metadata metadata - * module \endlink to simplify the manipulation of metadata blocks. - * - * \note - * It's not the best convention, but symbols ending in _LEN are in bits - * and _LENGTH are in bytes. _LENGTH symbols are \#defines instead of - * global variables because they are usually used when declaring byte - * arrays and some compilers require compile-time knowledge of array - * sizes when declared on the stack. - * - * \{ - */ - - -/* - Most of the values described in this file are defined by the FLAC - format specification. There is nothing to tune here. -*/ - -/** The largest legal metadata type code. */ -#define FLAC__MAX_METADATA_TYPE_CODE (126u) - -/** The minimum block size, in samples, permitted by the format. */ -#define FLAC__MIN_BLOCK_SIZE (16u) - -/** The maximum block size, in samples, permitted by the format. */ -#define FLAC__MAX_BLOCK_SIZE (65535u) - -/** The maximum block size, in samples, permitted by the FLAC subset for - * sample rates up to 48kHz. */ -#define FLAC__SUBSET_MAX_BLOCK_SIZE_48000HZ (4608u) - -/** The maximum number of channels permitted by the format. */ -#define FLAC__MAX_CHANNELS (8u) - -/** The minimum sample resolution permitted by the format. */ -#define FLAC__MIN_BITS_PER_SAMPLE (4u) - -/** The maximum sample resolution permitted by the format. */ -#define FLAC__MAX_BITS_PER_SAMPLE (32u) - -/** The maximum sample resolution permitted by libFLAC. - * - * \warning - * FLAC__MAX_BITS_PER_SAMPLE is the limit of the FLAC format. However, - * the reference encoder/decoder is currently limited to 24 bits because - * of prevalent 32-bit math, so make sure and use this value when - * appropriate. - */ -#define FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE (24u) - -/** The maximum sample rate permitted by the format. The value is - * ((2 ^ 16) - 1) * 10; see FLAC format - * as to why. - */ -#define FLAC__MAX_SAMPLE_RATE (655350u) - -/** The maximum LPC order permitted by the format. */ -#define FLAC__MAX_LPC_ORDER (32u) - -/** The maximum LPC order permitted by the FLAC subset for sample rates - * up to 48kHz. */ -#define FLAC__SUBSET_MAX_LPC_ORDER_48000HZ (12u) - -/** The minimum quantized linear predictor coefficient precision - * permitted by the format. - */ -#define FLAC__MIN_QLP_COEFF_PRECISION (5u) - -/** The maximum quantized linear predictor coefficient precision - * permitted by the format. - */ -#define FLAC__MAX_QLP_COEFF_PRECISION (15u) - -/** The maximum order of the fixed predictors permitted by the format. */ -#define FLAC__MAX_FIXED_ORDER (4u) - -/** The maximum Rice partition order permitted by the format. */ -#define FLAC__MAX_RICE_PARTITION_ORDER (15u) - -/** The maximum Rice partition order permitted by the FLAC Subset. */ -#define FLAC__SUBSET_MAX_RICE_PARTITION_ORDER (8u) - -/** The version string of the release, stamped onto the libraries and binaries. - * - * \note - * This does not correspond to the shared library version number, which - * is used to determine binary compatibility. - */ -extern FLAC_API const char *FLAC__VERSION_STRING; - -/** The vendor string inserted by the encoder into the VORBIS_COMMENT block. - * This is a NUL-terminated ASCII string; when inserted into the - * VORBIS_COMMENT the trailing null is stripped. - */ -extern FLAC_API const char *FLAC__VENDOR_STRING; - -/** The byte string representation of the beginning of a FLAC stream. */ -extern FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4]; /* = "fLaC" */ - -/** The 32-bit integer big-endian representation of the beginning of - * a FLAC stream. - */ -extern FLAC_API const uint32_t FLAC__STREAM_SYNC; /* = 0x664C6143 */ - -/** The length of the FLAC signature in bits. */ -extern FLAC_API const uint32_t FLAC__STREAM_SYNC_LEN; /* = 32 bits */ - -/** The length of the FLAC signature in bytes. */ -#define FLAC__STREAM_SYNC_LENGTH (4u) - - -/***************************************************************************** - * - * Subframe structures - * - *****************************************************************************/ - -/*****************************************************************************/ - -/** An enumeration of the available entropy coding methods. */ -typedef enum { - FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE = 0, - /**< Residual is coded by partitioning into contexts, each with it's own - * 4-bit Rice parameter. */ - - FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2 = 1 - /**< Residual is coded by partitioning into contexts, each with it's own - * 5-bit Rice parameter. */ -} FLAC__EntropyCodingMethodType; - -/** Maps a FLAC__EntropyCodingMethodType to a C string. - * - * Using a FLAC__EntropyCodingMethodType as the index to this array will - * give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__EntropyCodingMethodTypeString[]; - - -/** Contents of a Rice partitioned residual - */ -typedef struct { - - uint32_t *parameters; - /**< The Rice parameters for each context. */ - - uint32_t *raw_bits; - /**< Widths for escape-coded partitions. Will be non-zero for escaped - * partitions and zero for unescaped partitions. - */ - - uint32_t capacity_by_order; - /**< The capacity of the \a parameters and \a raw_bits arrays - * specified as an order, i.e. the number of array elements - * allocated is 2 ^ \a capacity_by_order. - */ -} FLAC__EntropyCodingMethod_PartitionedRiceContents; - -/** Header for a Rice partitioned residual. (c.f. format specification) - */ -typedef struct { - - uint32_t order; - /**< The partition order, i.e. # of contexts = 2 ^ \a order. */ - - const FLAC__EntropyCodingMethod_PartitionedRiceContents *contents; - /**< The context's Rice parameters and/or raw bits. */ - -} FLAC__EntropyCodingMethod_PartitionedRice; - -extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN; /**< == 4 (bits) */ -extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; /**< == 4 (bits) */ -extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN; /**< == 5 (bits) */ -extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN; /**< == 5 (bits) */ - -extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER; -/**< == (1<format specification) - */ -typedef struct { - FLAC__EntropyCodingMethodType type; - union { - FLAC__EntropyCodingMethod_PartitionedRice partitioned_rice; - } data; -} FLAC__EntropyCodingMethod; - -extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_TYPE_LEN; /**< == 2 (bits) */ - -/*****************************************************************************/ - -/** An enumeration of the available subframe types. */ -typedef enum { - FLAC__SUBFRAME_TYPE_CONSTANT = 0, /**< constant signal */ - FLAC__SUBFRAME_TYPE_VERBATIM = 1, /**< uncompressed signal */ - FLAC__SUBFRAME_TYPE_FIXED = 2, /**< fixed polynomial prediction */ - FLAC__SUBFRAME_TYPE_LPC = 3 /**< linear prediction */ -} FLAC__SubframeType; - -/** Maps a FLAC__SubframeType to a C string. - * - * Using a FLAC__SubframeType as the index to this array will - * give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__SubframeTypeString[]; - - -/** CONSTANT subframe. (c.f. format specification) - */ -typedef struct { - FLAC__int32 value; /**< The constant signal value. */ -} FLAC__Subframe_Constant; - - -/** VERBATIM subframe. (c.f. format specification) - */ -typedef struct { - const FLAC__int32 *data; /**< A pointer to verbatim signal. */ -} FLAC__Subframe_Verbatim; - - -/** FIXED subframe. (c.f. format specification) - */ -typedef struct { - FLAC__EntropyCodingMethod entropy_coding_method; - /**< The residual coding method. */ - - uint32_t order; - /**< The polynomial order. */ - - FLAC__int32 warmup[FLAC__MAX_FIXED_ORDER]; - /**< Warmup samples to prime the predictor, length == order. */ - - const FLAC__int32 *residual; - /**< The residual signal, length == (blocksize minus order) samples. */ -} FLAC__Subframe_Fixed; - - -/** LPC subframe. (c.f. format specification) - */ -typedef struct { - FLAC__EntropyCodingMethod entropy_coding_method; - /**< The residual coding method. */ - - uint32_t order; - /**< The FIR order. */ - - uint32_t qlp_coeff_precision; - /**< Quantized FIR filter coefficient precision in bits. */ - - int quantization_level; - /**< The qlp coeff shift needed. */ - - FLAC__int32 qlp_coeff[FLAC__MAX_LPC_ORDER]; - /**< FIR filter coefficients. */ - - FLAC__int32 warmup[FLAC__MAX_LPC_ORDER]; - /**< Warmup samples to prime the predictor, length == order. */ - - const FLAC__int32 *residual; - /**< The residual signal, length == (blocksize minus order) samples. */ -} FLAC__Subframe_LPC; - -extern FLAC_API const uint32_t FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN; /**< == 4 (bits) */ -extern FLAC_API const uint32_t FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN; /**< == 5 (bits) */ - - -/** FLAC subframe structure. (c.f. format specification) - */ -typedef struct { - FLAC__SubframeType type; - union { - FLAC__Subframe_Constant constant; - FLAC__Subframe_Fixed fixed; - FLAC__Subframe_LPC lpc; - FLAC__Subframe_Verbatim verbatim; - } data; - uint32_t wasted_bits; -} FLAC__Subframe; - -/** == 1 (bit) - * - * This used to be a zero-padding bit (hence the name - * FLAC__SUBFRAME_ZERO_PAD_LEN) but is now a reserved bit. It still has a - * mandatory value of \c 0 but in the future may take on the value \c 0 or \c 1 - * to mean something else. - */ -extern FLAC_API const uint32_t FLAC__SUBFRAME_ZERO_PAD_LEN; -extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_LEN; /**< == 6 (bits) */ -extern FLAC_API const uint32_t FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN; /**< == 1 (bit) */ - -extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK; /**< = 0x00 */ -extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK; /**< = 0x02 */ -extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK; /**< = 0x10 */ -extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK; /**< = 0x40 */ - -/*****************************************************************************/ - - -/***************************************************************************** - * - * Frame structures - * - *****************************************************************************/ - -/** An enumeration of the available channel assignments. */ -typedef enum { - FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT = 0, /**< independent channels */ - FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE = 1, /**< left+side stereo */ - FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE = 2, /**< right+side stereo */ - FLAC__CHANNEL_ASSIGNMENT_MID_SIDE = 3 /**< mid+side stereo */ -} FLAC__ChannelAssignment; - -/** Maps a FLAC__ChannelAssignment to a C string. - * - * Using a FLAC__ChannelAssignment as the index to this array will - * give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__ChannelAssignmentString[]; - -/** An enumeration of the possible frame numbering methods. */ -typedef enum { - FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER, /**< number contains the frame number */ - FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER /**< number contains the sample number of first sample in frame */ -} FLAC__FrameNumberType; - -/** Maps a FLAC__FrameNumberType to a C string. - * - * Using a FLAC__FrameNumberType as the index to this array will - * give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__FrameNumberTypeString[]; - - -/** FLAC frame header structure. (c.f. format specification) - */ -typedef struct { - uint32_t blocksize; - /**< The number of samples per subframe. */ - - uint32_t sample_rate; - /**< The sample rate in Hz. */ - - uint32_t channels; - /**< The number of channels (== number of subframes). */ - - FLAC__ChannelAssignment channel_assignment; - /**< The channel assignment for the frame. */ - - uint32_t bits_per_sample; - /**< The sample resolution. */ - - FLAC__FrameNumberType number_type; - /**< The numbering scheme used for the frame. As a convenience, the - * decoder will always convert a frame number to a sample number because - * the rules are complex. */ - - union { - FLAC__uint32 frame_number; - FLAC__uint64 sample_number; - } number; - /**< The frame number or sample number of first sample in frame; - * use the \a number_type value to determine which to use. */ - - FLAC__uint8 crc; - /**< CRC-8 (polynomial = x^8 + x^2 + x^1 + x^0, initialized with 0) - * of the raw frame header bytes, meaning everything before the CRC byte - * including the sync code. - */ -} FLAC__FrameHeader; - -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC; /**< == 0x3ffe; the frame header sync code */ -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC_LEN; /**< == 14 (bits) */ -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_RESERVED_LEN; /**< == 1 (bits) */ -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN; /**< == 1 (bits) */ -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCK_SIZE_LEN; /**< == 4 (bits) */ -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_SAMPLE_RATE_LEN; /**< == 4 (bits) */ -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN; /**< == 4 (bits) */ -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN; /**< == 3 (bits) */ -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_ZERO_PAD_LEN; /**< == 1 (bit) */ -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_CRC_LEN; /**< == 8 (bits) */ - - -/** FLAC frame footer structure. (c.f. format specification) - */ -typedef struct { - FLAC__uint16 crc; - /**< CRC-16 (polynomial = x^16 + x^15 + x^2 + x^0, initialized with - * 0) of the bytes before the crc, back to and including the frame header - * sync code. - */ -} FLAC__FrameFooter; - -extern FLAC_API const uint32_t FLAC__FRAME_FOOTER_CRC_LEN; /**< == 16 (bits) */ - - -/** FLAC frame structure. (c.f. format specification) - */ -typedef struct { - FLAC__FrameHeader header; - FLAC__Subframe subframes[FLAC__MAX_CHANNELS]; - FLAC__FrameFooter footer; -} FLAC__Frame; - -/*****************************************************************************/ - - -/***************************************************************************** - * - * Meta-data structures - * - *****************************************************************************/ - -/** An enumeration of the available metadata block types. */ -typedef enum { - - FLAC__METADATA_TYPE_STREAMINFO = 0, - /**< STREAMINFO block */ - - FLAC__METADATA_TYPE_PADDING = 1, - /**< PADDING block */ - - FLAC__METADATA_TYPE_APPLICATION = 2, - /**< APPLICATION block */ - - FLAC__METADATA_TYPE_SEEKTABLE = 3, - /**< SEEKTABLE block */ - - FLAC__METADATA_TYPE_VORBIS_COMMENT = 4, - /**< VORBISCOMMENT block (a.k.a. FLAC tags) */ - - FLAC__METADATA_TYPE_CUESHEET = 5, - /**< CUESHEET block */ - - FLAC__METADATA_TYPE_PICTURE = 6, - /**< PICTURE block */ - - FLAC__METADATA_TYPE_UNDEFINED = 7, - /**< marker to denote beginning of undefined type range; this number will increase as new metadata types are added */ - - FLAC__MAX_METADATA_TYPE = FLAC__MAX_METADATA_TYPE_CODE, - /**< No type will ever be greater than this. There is not enough room in the protocol block. */ -} FLAC__MetadataType; - -/** Maps a FLAC__MetadataType to a C string. - * - * Using a FLAC__MetadataType as the index to this array will - * give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__MetadataTypeString[]; - - -/** FLAC STREAMINFO structure. (c.f. format specification) - */ -typedef struct { - uint32_t min_blocksize, max_blocksize; - uint32_t min_framesize, max_framesize; - uint32_t sample_rate; - uint32_t channels; - uint32_t bits_per_sample; - FLAC__uint64 total_samples; - FLAC__byte md5sum[16]; -} FLAC__StreamMetadata_StreamInfo; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN; /**< == 16 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN; /**< == 16 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN; /**< == 24 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN; /**< == 24 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN; /**< == 20 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN; /**< == 3 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN; /**< == 5 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN; /**< == 36 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN; /**< == 128 (bits) */ - -/** The total stream length of the STREAMINFO block in bytes. */ -#define FLAC__STREAM_METADATA_STREAMINFO_LENGTH (34u) - -/** FLAC PADDING structure. (c.f. format specification) - */ -typedef struct { - int dummy; - /**< Conceptually this is an empty struct since we don't store the - * padding bytes. Empty structs are not allowed by some C compilers, - * hence the dummy. - */ -} FLAC__StreamMetadata_Padding; - - -/** FLAC APPLICATION structure. (c.f. format specification) - */ -typedef struct { - FLAC__byte id[4]; - FLAC__byte *data; -} FLAC__StreamMetadata_Application; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_APPLICATION_ID_LEN; /**< == 32 (bits) */ - -/** SeekPoint structure used in SEEKTABLE blocks. (c.f. format specification) - */ -typedef struct { - FLAC__uint64 sample_number; - /**< The sample number of the target frame. */ - - FLAC__uint64 stream_offset; - /**< The offset, in bytes, of the target frame with respect to - * beginning of the first frame. */ - - uint32_t frame_samples; - /**< The number of samples in the target frame. */ -} FLAC__StreamMetadata_SeekPoint; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN; /**< == 64 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN; /**< == 64 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN; /**< == 16 (bits) */ - -/** The total stream length of a seek point in bytes. */ -#define FLAC__STREAM_METADATA_SEEKPOINT_LENGTH (18u) - -/** The value used in the \a sample_number field of - * FLAC__StreamMetadataSeekPoint used to indicate a placeholder - * point (== 0xffffffffffffffff). - */ -extern FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER; - - -/** FLAC SEEKTABLE structure. (c.f. format specification) - * - * \note From the format specification: - * - The seek points must be sorted by ascending sample number. - * - Each seek point's sample number must be the first sample of the - * target frame. - * - Each seek point's sample number must be unique within the table. - * - Existence of a SEEKTABLE block implies a correct setting of - * total_samples in the stream_info block. - * - Behavior is undefined when more than one SEEKTABLE block is - * present in a stream. - */ -typedef struct { - uint32_t num_points; - FLAC__StreamMetadata_SeekPoint *points; -} FLAC__StreamMetadata_SeekTable; - - -/** Vorbis comment entry structure used in VORBIS_COMMENT blocks. (c.f. format specification) - * - * For convenience, the APIs maintain a trailing NUL character at the end of - * \a entry which is not counted toward \a length, i.e. - * \code strlen(entry) == length \endcode - */ -typedef struct { - FLAC__uint32 length; - FLAC__byte *entry; -} FLAC__StreamMetadata_VorbisComment_Entry; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN; /**< == 32 (bits) */ - - -/** FLAC VORBIS_COMMENT structure. (c.f. format specification) - */ -typedef struct { - FLAC__StreamMetadata_VorbisComment_Entry vendor_string; - FLAC__uint32 num_comments; - FLAC__StreamMetadata_VorbisComment_Entry *comments; -} FLAC__StreamMetadata_VorbisComment; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN; /**< == 32 (bits) */ - - -/** FLAC CUESHEET track index structure. (See the - * format specification for - * the full description of each field.) - */ -typedef struct { - FLAC__uint64 offset; - /**< Offset in samples, relative to the track offset, of the index - * point. - */ - - FLAC__byte number; - /**< The index point number. */ -} FLAC__StreamMetadata_CueSheet_Index; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN; /**< == 64 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN; /**< == 8 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN; /**< == 3*8 (bits) */ - - -/** FLAC CUESHEET track structure. (See the - * format specification for - * the full description of each field.) - */ -typedef struct { - FLAC__uint64 offset; - /**< Track offset in samples, relative to the beginning of the FLAC audio stream. */ - - FLAC__byte number; - /**< The track number. */ - - char isrc[13]; - /**< Track ISRC. This is a 12-digit alphanumeric code plus a trailing \c NUL byte */ - - uint32_t type:1; - /**< The track type: 0 for audio, 1 for non-audio. */ - - uint32_t pre_emphasis:1; - /**< The pre-emphasis flag: 0 for no pre-emphasis, 1 for pre-emphasis. */ - - FLAC__byte num_indices; - /**< The number of track index points. */ - - FLAC__StreamMetadata_CueSheet_Index *indices; - /**< NULL if num_indices == 0, else pointer to array of index points. */ - -} FLAC__StreamMetadata_CueSheet_Track; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN; /**< == 64 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN; /**< == 8 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN; /**< == 12*8 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN; /**< == 1 (bit) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN; /**< == 1 (bit) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN; /**< == 6+13*8 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN; /**< == 8 (bits) */ - - -/** FLAC CUESHEET structure. (See the - * format specification - * for the full description of each field.) - */ -typedef struct { - char media_catalog_number[129]; - /**< Media catalog number, in ASCII printable characters 0x20-0x7e. In - * general, the media catalog number may be 0 to 128 bytes long; any - * unused characters should be right-padded with NUL characters. - */ - - FLAC__uint64 lead_in; - /**< The number of lead-in samples. */ - - FLAC__bool is_cd; - /**< \c true if CUESHEET corresponds to a Compact Disc, else \c false. */ - - uint32_t num_tracks; - /**< The number of tracks. */ - - FLAC__StreamMetadata_CueSheet_Track *tracks; - /**< NULL if num_tracks == 0, else pointer to array of tracks. */ - -} FLAC__StreamMetadata_CueSheet; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN; /**< == 128*8 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN; /**< == 64 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN; /**< == 1 (bit) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN; /**< == 7+258*8 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN; /**< == 8 (bits) */ - - -/** An enumeration of the PICTURE types (see FLAC__StreamMetadataPicture and id3 v2.4 APIC tag). */ -typedef enum { - FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER = 0, /**< Other */ - FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD = 1, /**< 32x32 pixels 'file icon' (PNG only) */ - FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON = 2, /**< Other file icon */ - FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER = 3, /**< Cover (front) */ - FLAC__STREAM_METADATA_PICTURE_TYPE_BACK_COVER = 4, /**< Cover (back) */ - FLAC__STREAM_METADATA_PICTURE_TYPE_LEAFLET_PAGE = 5, /**< Leaflet page */ - FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA = 6, /**< Media (e.g. label side of CD) */ - FLAC__STREAM_METADATA_PICTURE_TYPE_LEAD_ARTIST = 7, /**< Lead artist/lead performer/soloist */ - FLAC__STREAM_METADATA_PICTURE_TYPE_ARTIST = 8, /**< Artist/performer */ - FLAC__STREAM_METADATA_PICTURE_TYPE_CONDUCTOR = 9, /**< Conductor */ - FLAC__STREAM_METADATA_PICTURE_TYPE_BAND = 10, /**< Band/Orchestra */ - FLAC__STREAM_METADATA_PICTURE_TYPE_COMPOSER = 11, /**< Composer */ - FLAC__STREAM_METADATA_PICTURE_TYPE_LYRICIST = 12, /**< Lyricist/text writer */ - FLAC__STREAM_METADATA_PICTURE_TYPE_RECORDING_LOCATION = 13, /**< Recording Location */ - FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_RECORDING = 14, /**< During recording */ - FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_PERFORMANCE = 15, /**< During performance */ - FLAC__STREAM_METADATA_PICTURE_TYPE_VIDEO_SCREEN_CAPTURE = 16, /**< Movie/video screen capture */ - FLAC__STREAM_METADATA_PICTURE_TYPE_FISH = 17, /**< A bright coloured fish */ - FLAC__STREAM_METADATA_PICTURE_TYPE_ILLUSTRATION = 18, /**< Illustration */ - FLAC__STREAM_METADATA_PICTURE_TYPE_BAND_LOGOTYPE = 19, /**< Band/artist logotype */ - FLAC__STREAM_METADATA_PICTURE_TYPE_PUBLISHER_LOGOTYPE = 20, /**< Publisher/Studio logotype */ - FLAC__STREAM_METADATA_PICTURE_TYPE_UNDEFINED -} FLAC__StreamMetadata_Picture_Type; - -/** Maps a FLAC__StreamMetadata_Picture_Type to a C string. - * - * Using a FLAC__StreamMetadata_Picture_Type as the index to this array - * will give the string equivalent. The contents should not be - * modified. - */ -extern FLAC_API const char * const FLAC__StreamMetadata_Picture_TypeString[]; - -/** FLAC PICTURE structure. (See the - * format specification - * for the full description of each field.) - */ -typedef struct { - FLAC__StreamMetadata_Picture_Type type; - /**< The kind of picture stored. */ - - char *mime_type; - /**< Picture data's MIME type, in ASCII printable characters - * 0x20-0x7e, NUL terminated. For best compatibility with players, - * use picture data of MIME type \c image/jpeg or \c image/png. A - * MIME type of '-->' is also allowed, in which case the picture - * data should be a complete URL. In file storage, the MIME type is - * stored as a 32-bit length followed by the ASCII string with no NUL - * terminator, but is converted to a plain C string in this structure - * for convenience. - */ - - FLAC__byte *description; - /**< Picture's description in UTF-8, NUL terminated. In file storage, - * the description is stored as a 32-bit length followed by the UTF-8 - * string with no NUL terminator, but is converted to a plain C string - * in this structure for convenience. - */ - - FLAC__uint32 width; - /**< Picture's width in pixels. */ - - FLAC__uint32 height; - /**< Picture's height in pixels. */ - - FLAC__uint32 depth; - /**< Picture's color depth in bits-per-pixel. */ - - FLAC__uint32 colors; - /**< For indexed palettes (like GIF), picture's number of colors (the - * number of palette entries), or \c 0 for non-indexed (i.e. 2^depth). - */ - - FLAC__uint32 data_length; - /**< Length of binary picture data in bytes. */ - - FLAC__byte *data; - /**< Binary picture data. */ - -} FLAC__StreamMetadata_Picture; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_TYPE_LEN; /**< == 32 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN; /**< == 32 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN; /**< == 32 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN; /**< == 32 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN; /**< == 32 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN; /**< == 32 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_COLORS_LEN; /**< == 32 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN; /**< == 32 (bits) */ - - -/** Structure that is used when a metadata block of unknown type is loaded. - * The contents are opaque. The structure is used only internally to - * correctly handle unknown metadata. - */ -typedef struct { - FLAC__byte *data; -} FLAC__StreamMetadata_Unknown; - - -/** FLAC metadata block structure. (c.f. format specification) - */ -typedef struct { - FLAC__MetadataType type; - /**< The type of the metadata block; used determine which member of the - * \a data union to dereference. If type >= FLAC__METADATA_TYPE_UNDEFINED - * then \a data.unknown must be used. */ - - FLAC__bool is_last; - /**< \c true if this metadata block is the last, else \a false */ - - uint32_t length; - /**< Length, in bytes, of the block data as it appears in the stream. */ - - union { - FLAC__StreamMetadata_StreamInfo stream_info; - FLAC__StreamMetadata_Padding padding; - FLAC__StreamMetadata_Application application; - FLAC__StreamMetadata_SeekTable seek_table; - FLAC__StreamMetadata_VorbisComment vorbis_comment; - FLAC__StreamMetadata_CueSheet cue_sheet; - FLAC__StreamMetadata_Picture picture; - FLAC__StreamMetadata_Unknown unknown; - } data; - /**< Polymorphic block data; use the \a type value to determine which - * to use. */ -} FLAC__StreamMetadata; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_IS_LAST_LEN; /**< == 1 (bit) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_TYPE_LEN; /**< == 7 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_LENGTH_LEN; /**< == 24 (bits) */ - -/** The total stream length of a metadata block header in bytes. */ -#define FLAC__STREAM_METADATA_HEADER_LENGTH (4u) - -/*****************************************************************************/ - - -/***************************************************************************** - * - * Utility functions - * - *****************************************************************************/ - -/** Tests that a sample rate is valid for FLAC. - * - * \param sample_rate The sample rate to test for compliance. - * \retval FLAC__bool - * \c true if the given sample rate conforms to the specification, else - * \c false. - */ -FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(uint32_t sample_rate); - -/** Tests that a blocksize at the given sample rate is valid for the FLAC - * subset. - * - * \param blocksize The blocksize to test for compliance. - * \param sample_rate The sample rate is needed, since the valid subset - * blocksize depends on the sample rate. - * \retval FLAC__bool - * \c true if the given blocksize conforms to the specification for the - * subset at the given sample rate, else \c false. - */ -FLAC_API FLAC__bool FLAC__format_blocksize_is_subset(uint32_t blocksize, uint32_t sample_rate); - -/** Tests that a sample rate is valid for the FLAC subset. The subset rules - * for valid sample rates are slightly more complex since the rate has to - * be expressible completely in the frame header. - * - * \param sample_rate The sample rate to test for compliance. - * \retval FLAC__bool - * \c true if the given sample rate conforms to the specification for the - * subset, else \c false. - */ -FLAC_API FLAC__bool FLAC__format_sample_rate_is_subset(uint32_t sample_rate); - -/** Check a Vorbis comment entry name to see if it conforms to the Vorbis - * comment specification. - * - * Vorbis comment names must be composed only of characters from - * [0x20-0x3C,0x3E-0x7D]. - * - * \param name A NUL-terminated string to be checked. - * \assert - * \code name != NULL \endcode - * \retval FLAC__bool - * \c false if entry name is illegal, else \c true. - */ -FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_name_is_legal(const char *name); - -/** Check a Vorbis comment entry value to see if it conforms to the Vorbis - * comment specification. - * - * Vorbis comment values must be valid UTF-8 sequences. - * - * \param value A string to be checked. - * \param length A the length of \a value in bytes. May be - * \c (uint32_t)(-1) to indicate that \a value is a plain - * UTF-8 NUL-terminated string. - * \assert - * \code value != NULL \endcode - * \retval FLAC__bool - * \c false if entry name is illegal, else \c true. - */ -FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, uint32_t length); - -/** Check a Vorbis comment entry to see if it conforms to the Vorbis - * comment specification. - * - * Vorbis comment entries must be of the form 'name=value', and 'name' and - * 'value' must be legal according to - * FLAC__format_vorbiscomment_entry_name_is_legal() and - * FLAC__format_vorbiscomment_entry_value_is_legal() respectively. - * - * \param entry An entry to be checked. - * \param length The length of \a entry in bytes. - * \assert - * \code value != NULL \endcode - * \retval FLAC__bool - * \c false if entry name is illegal, else \c true. - */ -FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, uint32_t length); - -/** Check a seek table to see if it conforms to the FLAC specification. - * See the format specification for limits on the contents of the - * seek table. - * - * \param seek_table A pointer to a seek table to be checked. - * \assert - * \code seek_table != NULL \endcode - * \retval FLAC__bool - * \c false if seek table is illegal, else \c true. - */ -FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_SeekTable *seek_table); - -/** Sort a seek table's seek points according to the format specification. - * This includes a "unique-ification" step to remove duplicates, i.e. - * seek points with identical \a sample_number values. Duplicate seek - * points are converted into placeholder points and sorted to the end of - * the table. - * - * \param seek_table A pointer to a seek table to be sorted. - * \assert - * \code seek_table != NULL \endcode - * \retval uint32_t - * The number of duplicate seek points converted into placeholders. - */ -FLAC_API uint32_t FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table); - -/** Check a cue sheet to see if it conforms to the FLAC specification. - * See the format specification for limits on the contents of the - * cue sheet. - * - * \param cue_sheet A pointer to an existing cue sheet to be checked. - * \param check_cd_da_subset If \c true, check CUESHEET against more - * stringent requirements for a CD-DA (audio) disc. - * \param violation Address of a pointer to a string. If there is a - * violation, a pointer to a string explanation of the - * violation will be returned here. \a violation may be - * \c NULL if you don't need the returned string. Do not - * free the returned string; it will always point to static - * data. - * \assert - * \code cue_sheet != NULL \endcode - * \retval FLAC__bool - * \c false if cue sheet is illegal, else \c true. - */ -FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation); - -/** Check picture data to see if it conforms to the FLAC specification. - * See the format specification for limits on the contents of the - * PICTURE block. - * - * \param picture A pointer to existing picture data to be checked. - * \param violation Address of a pointer to a string. If there is a - * violation, a pointer to a string explanation of the - * violation will be returned here. \a violation may be - * \c NULL if you don't need the returned string. Do not - * free the returned string; it will always point to static - * data. - * \assert - * \code picture != NULL \endcode - * \retval FLAC__bool - * \c false if picture data is illegal, else \c true. - */ -FLAC_API FLAC__bool FLAC__format_picture_is_legal(const FLAC__StreamMetadata_Picture *picture, const char **violation); - -/* \} */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/flac/include/FLAC/metadata.h b/lib/flac/include/FLAC/metadata.h deleted file mode 100644 index 4c67b87..0000000 --- a/lib/flac/include/FLAC/metadata.h +++ /dev/null @@ -1,2182 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__METADATA_H -#define FLAC__METADATA_H - -#include /* for off_t */ -#include "export.h" -#include "callback.h" -#include "format.h" - -/* -------------------------------------------------------------------- - (For an example of how all these routines are used, see the source - code for the unit tests in src/test_libFLAC/metadata_*.c, or - metaflac in src/metaflac/) - ------------------------------------------------------------------*/ - -/** \file include/FLAC/metadata.h - * - * \brief - * This module provides functions for creating and manipulating FLAC - * metadata blocks in memory, and three progressively more powerful - * interfaces for traversing and editing metadata in FLAC files. - * - * See the detailed documentation for each interface in the - * \link flac_metadata metadata \endlink module. - */ - -/** \defgroup flac_metadata FLAC/metadata.h: metadata interfaces - * \ingroup flac - * - * \brief - * This module provides functions for creating and manipulating FLAC - * metadata blocks in memory, and three progressively more powerful - * interfaces for traversing and editing metadata in native FLAC files. - * Note that currently only the Chain interface (level 2) supports Ogg - * FLAC files, and it is read-only i.e. no writing back changed - * metadata to file. - * - * There are three metadata interfaces of increasing complexity: - * - * Level 0: - * Read-only access to the STREAMINFO, VORBIS_COMMENT, CUESHEET, and - * PICTURE blocks. - * - * Level 1: - * Read-write access to all metadata blocks. This level is write- - * efficient in most cases (more on this below), and uses less memory - * than level 2. - * - * Level 2: - * Read-write access to all metadata blocks. This level is write- - * efficient in all cases, but uses more memory since all metadata for - * the whole file is read into memory and manipulated before writing - * out again. - * - * What do we mean by efficient? Since FLAC metadata appears at the - * beginning of the file, when writing metadata back to a FLAC file - * it is possible to grow or shrink the metadata such that the entire - * file must be rewritten. However, if the size remains the same during - * changes or PADDING blocks are utilized, only the metadata needs to be - * overwritten, which is much faster. - * - * Efficient means the whole file is rewritten at most one time, and only - * when necessary. Level 1 is not efficient only in the case that you - * cause more than one metadata block to grow or shrink beyond what can - * be accommodated by padding. In this case you should probably use level - * 2, which allows you to edit all the metadata for a file in memory and - * write it out all at once. - * - * All levels know how to skip over and not disturb an ID3v2 tag at the - * front of the file. - * - * All levels access files via their filenames. In addition, level 2 - * has additional alternative read and write functions that take an I/O - * handle and callbacks, for situations where access by filename is not - * possible. - * - * In addition to the three interfaces, this module defines functions for - * creating and manipulating various metadata objects in memory. As we see - * from the Format module, FLAC metadata blocks in memory are very primitive - * structures for storing information in an efficient way. Reading - * information from the structures is easy but creating or modifying them - * directly is more complex. The metadata object routines here facilitate - * this by taking care of the consistency and memory management drudgery. - * - * Unless you will be using the level 1 or 2 interfaces to modify existing - * metadata however, you will not probably not need these. - * - * From a dependency standpoint, none of the encoders or decoders require - * the metadata module. This is so that embedded users can strip out the - * metadata module from libFLAC to reduce the size and complexity. - */ - -#ifdef __cplusplus -extern "C" { -#endif - - -/** \defgroup flac_metadata_level0 FLAC/metadata.h: metadata level 0 interface - * \ingroup flac_metadata - * - * \brief - * The level 0 interface consists of individual routines to read the - * STREAMINFO, VORBIS_COMMENT, CUESHEET, and PICTURE blocks, requiring - * only a filename. - * - * They try to skip any ID3v2 tag at the head of the file. - * - * \{ - */ - -/** Read the STREAMINFO metadata block of the given FLAC file. This function - * will try to skip any ID3v2 tag at the head of the file. - * - * \param filename The path to the FLAC file to read. - * \param streaminfo A pointer to space for the STREAMINFO block. Since - * FLAC__StreamMetadata is a simple structure with no - * memory allocation involved, you pass the address of - * an existing structure. It need not be initialized. - * \assert - * \code filename != NULL \endcode - * \code streaminfo != NULL \endcode - * \retval FLAC__bool - * \c true if a valid STREAMINFO block was read from \a filename. Returns - * \c false if there was a memory allocation error, a file decoder error, - * or the file contained no STREAMINFO block. (A memory allocation error - * is possible because this function must set up a file decoder.) - */ -FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo); - -/** Read the VORBIS_COMMENT metadata block of the given FLAC file. This - * function will try to skip any ID3v2 tag at the head of the file. - * - * \param filename The path to the FLAC file to read. - * \param tags The address where the returned pointer will be - * stored. The \a tags object must be deleted by - * the caller using FLAC__metadata_object_delete(). - * \assert - * \code filename != NULL \endcode - * \code tags != NULL \endcode - * \retval FLAC__bool - * \c true if a valid VORBIS_COMMENT block was read from \a filename, - * and \a *tags will be set to the address of the metadata structure. - * Returns \c false if there was a memory allocation error, a file - * decoder error, or the file contained no VORBIS_COMMENT block, and - * \a *tags will be set to \c NULL. - */ -FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMetadata **tags); - -/** Read the CUESHEET metadata block of the given FLAC file. This - * function will try to skip any ID3v2 tag at the head of the file. - * - * \param filename The path to the FLAC file to read. - * \param cuesheet The address where the returned pointer will be - * stored. The \a cuesheet object must be deleted by - * the caller using FLAC__metadata_object_delete(). - * \assert - * \code filename != NULL \endcode - * \code cuesheet != NULL \endcode - * \retval FLAC__bool - * \c true if a valid CUESHEET block was read from \a filename, - * and \a *cuesheet will be set to the address of the metadata - * structure. Returns \c false if there was a memory allocation - * error, a file decoder error, or the file contained no CUESHEET - * block, and \a *cuesheet will be set to \c NULL. - */ -FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__StreamMetadata **cuesheet); - -/** Read a PICTURE metadata block of the given FLAC file. This - * function will try to skip any ID3v2 tag at the head of the file. - * Since there can be more than one PICTURE block in a file, this - * function takes a number of parameters that act as constraints to - * the search. The PICTURE block with the largest area matching all - * the constraints will be returned, or \a *picture will be set to - * \c NULL if there was no such block. - * - * \param filename The path to the FLAC file to read. - * \param picture The address where the returned pointer will be - * stored. The \a picture object must be deleted by - * the caller using FLAC__metadata_object_delete(). - * \param type The desired picture type. Use \c -1 to mean - * "any type". - * \param mime_type The desired MIME type, e.g. "image/jpeg". The - * string will be matched exactly. Use \c NULL to - * mean "any MIME type". - * \param description The desired description. The string will be - * matched exactly. Use \c NULL to mean "any - * description". - * \param max_width The maximum width in pixels desired. Use - * \c (uint32_t)(-1) to mean "any width". - * \param max_height The maximum height in pixels desired. Use - * \c (uint32_t)(-1) to mean "any height". - * \param max_depth The maximum color depth in bits-per-pixel desired. - * Use \c (uint32_t)(-1) to mean "any depth". - * \param max_colors The maximum number of colors desired. Use - * \c (uint32_t)(-1) to mean "any number of colors". - * \assert - * \code filename != NULL \endcode - * \code picture != NULL \endcode - * \retval FLAC__bool - * \c true if a valid PICTURE block was read from \a filename, - * and \a *picture will be set to the address of the metadata - * structure. Returns \c false if there was a memory allocation - * error, a file decoder error, or the file contained no PICTURE - * block, and \a *picture will be set to \c NULL. - */ -FLAC_API FLAC__bool FLAC__metadata_get_picture(const char *filename, FLAC__StreamMetadata **picture, FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, uint32_t max_width, uint32_t max_height, uint32_t max_depth, uint32_t max_colors); - -/* \} */ - - -/** \defgroup flac_metadata_level1 FLAC/metadata.h: metadata level 1 interface - * \ingroup flac_metadata - * - * \brief - * The level 1 interface provides read-write access to FLAC file metadata and - * operates directly on the FLAC file. - * - * The general usage of this interface is: - * - * - Create an iterator using FLAC__metadata_simple_iterator_new() - * - Attach it to a file using FLAC__metadata_simple_iterator_init() and check - * the exit code. Call FLAC__metadata_simple_iterator_is_writable() to - * see if the file is writable, or only read access is allowed. - * - Use FLAC__metadata_simple_iterator_next() and - * FLAC__metadata_simple_iterator_prev() to traverse the blocks. - * This is does not read the actual blocks themselves. - * FLAC__metadata_simple_iterator_next() is relatively fast. - * FLAC__metadata_simple_iterator_prev() is slower since it needs to search - * forward from the front of the file. - * - Use FLAC__metadata_simple_iterator_get_block_type() or - * FLAC__metadata_simple_iterator_get_block() to access the actual data at - * the current iterator position. The returned object is yours to modify - * and free. - * - Use FLAC__metadata_simple_iterator_set_block() to write a modified block - * back. You must have write permission to the original file. Make sure to - * read the whole comment to FLAC__metadata_simple_iterator_set_block() - * below. - * - Use FLAC__metadata_simple_iterator_insert_block_after() to add new blocks. - * Use the object creation functions from - * \link flac_metadata_object here \endlink to generate new objects. - * - Use FLAC__metadata_simple_iterator_delete_block() to remove the block - * currently referred to by the iterator, or replace it with padding. - * - Destroy the iterator with FLAC__metadata_simple_iterator_delete() when - * finished. - * - * \note - * The FLAC file remains open the whole time between - * FLAC__metadata_simple_iterator_init() and - * FLAC__metadata_simple_iterator_delete(), so make sure you are not altering - * the file during this time. - * - * \note - * Do not modify the \a is_last, \a length, or \a type fields of returned - * FLAC__StreamMetadata objects. These are managed automatically. - * - * \note - * If any of the modification functions - * (FLAC__metadata_simple_iterator_set_block(), - * FLAC__metadata_simple_iterator_delete_block(), - * FLAC__metadata_simple_iterator_insert_block_after(), etc.) return \c false, - * you should delete the iterator as it may no longer be valid. - * - * \{ - */ - -struct FLAC__Metadata_SimpleIterator; -/** The opaque structure definition for the level 1 iterator type. - * See the - * \link flac_metadata_level1 metadata level 1 module \endlink - * for a detailed description. - */ -typedef struct FLAC__Metadata_SimpleIterator FLAC__Metadata_SimpleIterator; - -/** Status type for FLAC__Metadata_SimpleIterator. - * - * The iterator's current status can be obtained by calling FLAC__metadata_simple_iterator_status(). - */ -typedef enum { - - FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK = 0, - /**< The iterator is in the normal OK state */ - - FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT, - /**< The data passed into a function violated the function's usage criteria */ - - FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE, - /**< The iterator could not open the target file */ - - FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE, - /**< The iterator could not find the FLAC signature at the start of the file */ - - FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE, - /**< The iterator tried to write to a file that was not writable */ - - FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA, - /**< The iterator encountered input that does not conform to the FLAC metadata specification */ - - FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR, - /**< The iterator encountered an error while reading the FLAC file */ - - FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR, - /**< The iterator encountered an error while seeking in the FLAC file */ - - FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR, - /**< The iterator encountered an error while writing the FLAC file */ - - FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR, - /**< The iterator encountered an error renaming the FLAC file */ - - FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR, - /**< The iterator encountered an error removing the temporary file */ - - FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR, - /**< Memory allocation failed */ - - FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR - /**< The caller violated an assertion or an unexpected error occurred */ - -} FLAC__Metadata_SimpleIteratorStatus; - -/** Maps a FLAC__Metadata_SimpleIteratorStatus to a C string. - * - * Using a FLAC__Metadata_SimpleIteratorStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__Metadata_SimpleIteratorStatusString[]; - - -/** Create a new iterator instance. - * - * \retval FLAC__Metadata_SimpleIterator* - * \c NULL if there was an error allocating memory, else the new instance. - */ -FLAC_API FLAC__Metadata_SimpleIterator *FLAC__metadata_simple_iterator_new(void); - -/** Free an iterator instance. Deletes the object pointed to by \a iterator. - * - * \param iterator A pointer to an existing iterator. - * \assert - * \code iterator != NULL \endcode - */ -FLAC_API void FLAC__metadata_simple_iterator_delete(FLAC__Metadata_SimpleIterator *iterator); - -/** Get the current status of the iterator. Call this after a function - * returns \c false to get the reason for the error. Also resets the status - * to FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK. - * - * \param iterator A pointer to an existing iterator. - * \assert - * \code iterator != NULL \endcode - * \retval FLAC__Metadata_SimpleIteratorStatus - * The current status of the iterator. - */ -FLAC_API FLAC__Metadata_SimpleIteratorStatus FLAC__metadata_simple_iterator_status(FLAC__Metadata_SimpleIterator *iterator); - -/** Initialize the iterator to point to the first metadata block in the - * given FLAC file. - * - * \param iterator A pointer to an existing iterator. - * \param filename The path to the FLAC file. - * \param read_only If \c true, the FLAC file will be opened - * in read-only mode; if \c false, the FLAC - * file will be opened for edit even if no - * edits are performed. - * \param preserve_file_stats If \c true, the owner and modification - * time will be preserved even if the FLAC - * file is written to. - * \assert - * \code iterator != NULL \endcode - * \code filename != NULL \endcode - * \retval FLAC__bool - * \c false if a memory allocation error occurs, the file can't be - * opened, or another error occurs, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool read_only, FLAC__bool preserve_file_stats); - -/** Returns \c true if the FLAC file is writable. If \c false, calls to - * FLAC__metadata_simple_iterator_set_block() and - * FLAC__metadata_simple_iterator_insert_block_after() will fail. - * - * \param iterator A pointer to an existing iterator. - * \assert - * \code iterator != NULL \endcode - * \retval FLAC__bool - * See above. - */ -FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_writable(const FLAC__Metadata_SimpleIterator *iterator); - -/** Moves the iterator forward one metadata block, returning \c false if - * already at the end. - * - * \param iterator A pointer to an existing initialized iterator. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_simple_iterator_init() - * \retval FLAC__bool - * \c false if already at the last metadata block of the chain, else - * \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_simple_iterator_next(FLAC__Metadata_SimpleIterator *iterator); - -/** Moves the iterator backward one metadata block, returning \c false if - * already at the beginning. - * - * \param iterator A pointer to an existing initialized iterator. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_simple_iterator_init() - * \retval FLAC__bool - * \c false if already at the first metadata block of the chain, else - * \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIterator *iterator); - -/** Returns a flag telling if the current metadata block is the last. - * - * \param iterator A pointer to an existing initialized iterator. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_simple_iterator_init() - * \retval FLAC__bool - * \c true if the current metadata block is the last in the file, - * else \c false. - */ -FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_last(const FLAC__Metadata_SimpleIterator *iterator); - -/** Get the offset of the metadata block at the current position. This - * avoids reading the actual block data which can save time for large - * blocks. - * - * \param iterator A pointer to an existing initialized iterator. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_simple_iterator_init() - * \retval off_t - * The offset of the metadata block at the current iterator position. - * This is the byte offset relative to the beginning of the file of - * the current metadata block's header. - */ -FLAC_API off_t FLAC__metadata_simple_iterator_get_block_offset(const FLAC__Metadata_SimpleIterator *iterator); - -/** Get the type of the metadata block at the current position. This - * avoids reading the actual block data which can save time for large - * blocks. - * - * \param iterator A pointer to an existing initialized iterator. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_simple_iterator_init() - * \retval FLAC__MetadataType - * The type of the metadata block at the current iterator position. - */ -FLAC_API FLAC__MetadataType FLAC__metadata_simple_iterator_get_block_type(const FLAC__Metadata_SimpleIterator *iterator); - -/** Get the length of the metadata block at the current position. This - * avoids reading the actual block data which can save time for large - * blocks. - * - * \param iterator A pointer to an existing initialized iterator. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_simple_iterator_init() - * \retval uint32_t - * The length of the metadata block at the current iterator position. - * The is same length as that in the - * metadata block header, - * i.e. the length of the metadata body that follows the header. - */ -FLAC_API uint32_t FLAC__metadata_simple_iterator_get_block_length(const FLAC__Metadata_SimpleIterator *iterator); - -/** Get the application ID of the \c APPLICATION block at the current - * position. This avoids reading the actual block data which can save - * time for large blocks. - * - * \param iterator A pointer to an existing initialized iterator. - * \param id A pointer to a buffer of at least \c 4 bytes where - * the ID will be stored. - * \assert - * \code iterator != NULL \endcode - * \code id != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_simple_iterator_init() - * \retval FLAC__bool - * \c true if the ID was successfully read, else \c false, in which - * case you should check FLAC__metadata_simple_iterator_status() to - * find out why. If the status is - * \c FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT, then the - * current metadata block is not an \c APPLICATION block. Otherwise - * if the status is - * \c FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR or - * \c FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR, an I/O error - * occurred and the iterator can no longer be used. - */ -FLAC_API FLAC__bool FLAC__metadata_simple_iterator_get_application_id(FLAC__Metadata_SimpleIterator *iterator, FLAC__byte *id); - -/** Get the metadata block at the current position. You can modify the - * block but must use FLAC__metadata_simple_iterator_set_block() to - * write it back to the FLAC file. - * - * You must call FLAC__metadata_object_delete() on the returned object - * when you are finished with it. - * - * \param iterator A pointer to an existing initialized iterator. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_simple_iterator_init() - * \retval FLAC__StreamMetadata* - * The current metadata block, or \c NULL if there was a memory - * allocation error. - */ -FLAC_API FLAC__StreamMetadata *FLAC__metadata_simple_iterator_get_block(FLAC__Metadata_SimpleIterator *iterator); - -/** Write a block back to the FLAC file. This function tries to be - * as efficient as possible; how the block is actually written is - * shown by the following: - * - * Existing block is a STREAMINFO block and the new block is a - * STREAMINFO block: the new block is written in place. Make sure - * you know what you're doing when changing the values of a - * STREAMINFO block. - * - * Existing block is a STREAMINFO block and the new block is a - * not a STREAMINFO block: this is an error since the first block - * must be a STREAMINFO block. Returns \c false without altering the - * file. - * - * Existing block is not a STREAMINFO block and the new block is a - * STREAMINFO block: this is an error since there may be only one - * STREAMINFO block. Returns \c false without altering the file. - * - * Existing block and new block are the same length: the existing - * block will be replaced by the new block, written in place. - * - * Existing block is longer than new block: if use_padding is \c true, - * the existing block will be overwritten in place with the new - * block followed by a PADDING block, if possible, to make the total - * size the same as the existing block. Remember that a padding - * block requires at least four bytes so if the difference in size - * between the new block and existing block is less than that, the - * entire file will have to be rewritten, using the new block's - * exact size. If use_padding is \c false, the entire file will be - * rewritten, replacing the existing block by the new block. - * - * Existing block is shorter than new block: if use_padding is \c true, - * the function will try and expand the new block into the following - * PADDING block, if it exists and doing so won't shrink the PADDING - * block to less than 4 bytes. If there is no following PADDING - * block, or it will shrink to less than 4 bytes, or use_padding is - * \c false, the entire file is rewritten, replacing the existing block - * with the new block. Note that in this case any following PADDING - * block is preserved as is. - * - * After writing the block, the iterator will remain in the same - * place, i.e. pointing to the new block. - * - * \param iterator A pointer to an existing initialized iterator. - * \param block The block to set. - * \param use_padding See above. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_simple_iterator_init() - * \code block != NULL \endcode - * \retval FLAC__bool - * \c true if successful, else \c false. - */ -FLAC_API FLAC__bool FLAC__metadata_simple_iterator_set_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding); - -/** This is similar to FLAC__metadata_simple_iterator_set_block() - * except that instead of writing over an existing block, it appends - * a block after the existing block. \a use_padding is again used to - * tell the function to try an expand into following padding in an - * attempt to avoid rewriting the entire file. - * - * This function will fail and return \c false if given a STREAMINFO - * block. - * - * After writing the block, the iterator will be pointing to the - * new block. - * - * \param iterator A pointer to an existing initialized iterator. - * \param block The block to set. - * \param use_padding See above. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_simple_iterator_init() - * \code block != NULL \endcode - * \retval FLAC__bool - * \c true if successful, else \c false. - */ -FLAC_API FLAC__bool FLAC__metadata_simple_iterator_insert_block_after(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding); - -/** Deletes the block at the current position. This will cause the - * entire FLAC file to be rewritten, unless \a use_padding is \c true, - * in which case the block will be replaced by an equal-sized PADDING - * block. The iterator will be left pointing to the block before the - * one just deleted. - * - * You may not delete the STREAMINFO block. - * - * \param iterator A pointer to an existing initialized iterator. - * \param use_padding See above. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_simple_iterator_init() - * \retval FLAC__bool - * \c true if successful, else \c false. - */ -FLAC_API FLAC__bool FLAC__metadata_simple_iterator_delete_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool use_padding); - -/* \} */ - - -/** \defgroup flac_metadata_level2 FLAC/metadata.h: metadata level 2 interface - * \ingroup flac_metadata - * - * \brief - * The level 2 interface provides read-write access to FLAC file metadata; - * all metadata is read into memory, operated on in memory, and then written - * to file, which is more efficient than level 1 when editing multiple blocks. - * - * Currently Ogg FLAC is supported for read only, via - * FLAC__metadata_chain_read_ogg() but a subsequent - * FLAC__metadata_chain_write() will fail. - * - * The general usage of this interface is: - * - * - Create a new chain using FLAC__metadata_chain_new(). A chain is a - * linked list of FLAC metadata blocks. - * - Read all metadata into the chain from a FLAC file using - * FLAC__metadata_chain_read() or FLAC__metadata_chain_read_ogg() and - * check the status. - * - Optionally, consolidate the padding using - * FLAC__metadata_chain_merge_padding() or - * FLAC__metadata_chain_sort_padding(). - * - Create a new iterator using FLAC__metadata_iterator_new() - * - Initialize the iterator to point to the first element in the chain - * using FLAC__metadata_iterator_init() - * - Traverse the chain using FLAC__metadata_iterator_next and - * FLAC__metadata_iterator_prev(). - * - Get a block for reading or modification using - * FLAC__metadata_iterator_get_block(). The pointer to the object - * inside the chain is returned, so the block is yours to modify. - * Changes will be reflected in the FLAC file when you write the - * chain. You can also add and delete blocks (see functions below). - * - When done, write out the chain using FLAC__metadata_chain_write(). - * Make sure to read the whole comment to the function below. - * - Delete the chain using FLAC__metadata_chain_delete(). - * - * \note - * Even though the FLAC file is not open while the chain is being - * manipulated, you must not alter the file externally during - * this time. The chain assumes the FLAC file will not change - * between the time of FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg() - * and FLAC__metadata_chain_write(). - * - * \note - * Do not modify the is_last, length, or type fields of returned - * FLAC__StreamMetadata objects. These are managed automatically. - * - * \note - * The metadata objects returned by FLAC__metadata_iterator_get_block() - * are owned by the chain; do not FLAC__metadata_object_delete() them. - * In the same way, blocks passed to FLAC__metadata_iterator_set_block() - * become owned by the chain and they will be deleted when the chain is - * deleted. - * - * \{ - */ - -struct FLAC__Metadata_Chain; -/** The opaque structure definition for the level 2 chain type. - */ -typedef struct FLAC__Metadata_Chain FLAC__Metadata_Chain; - -struct FLAC__Metadata_Iterator; -/** The opaque structure definition for the level 2 iterator type. - */ -typedef struct FLAC__Metadata_Iterator FLAC__Metadata_Iterator; - -typedef enum { - FLAC__METADATA_CHAIN_STATUS_OK = 0, - /**< The chain is in the normal OK state */ - - FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT, - /**< The data passed into a function violated the function's usage criteria */ - - FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE, - /**< The chain could not open the target file */ - - FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE, - /**< The chain could not find the FLAC signature at the start of the file */ - - FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE, - /**< The chain tried to write to a file that was not writable */ - - FLAC__METADATA_CHAIN_STATUS_BAD_METADATA, - /**< The chain encountered input that does not conform to the FLAC metadata specification */ - - FLAC__METADATA_CHAIN_STATUS_READ_ERROR, - /**< The chain encountered an error while reading the FLAC file */ - - FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR, - /**< The chain encountered an error while seeking in the FLAC file */ - - FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR, - /**< The chain encountered an error while writing the FLAC file */ - - FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR, - /**< The chain encountered an error renaming the FLAC file */ - - FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR, - /**< The chain encountered an error removing the temporary file */ - - FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR, - /**< Memory allocation failed */ - - FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR, - /**< The caller violated an assertion or an unexpected error occurred */ - - FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS, - /**< One or more of the required callbacks was NULL */ - - FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH, - /**< FLAC__metadata_chain_write() was called on a chain read by - * FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(), - * or - * FLAC__metadata_chain_write_with_callbacks()/FLAC__metadata_chain_write_with_callbacks_and_tempfile() - * was called on a chain read by - * FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg(). - * Matching read/write methods must always be used. */ - - FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL - /**< FLAC__metadata_chain_write_with_callbacks() was called when the - * chain write requires a tempfile; use - * FLAC__metadata_chain_write_with_callbacks_and_tempfile() instead. - * Or, FLAC__metadata_chain_write_with_callbacks_and_tempfile() was - * called when the chain write does not require a tempfile; use - * FLAC__metadata_chain_write_with_callbacks() instead. - * Always check FLAC__metadata_chain_check_if_tempfile_needed() - * before writing via callbacks. */ - -} FLAC__Metadata_ChainStatus; - -/** Maps a FLAC__Metadata_ChainStatus to a C string. - * - * Using a FLAC__Metadata_ChainStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__Metadata_ChainStatusString[]; - -/*********** FLAC__Metadata_Chain ***********/ - -/** Create a new chain instance. - * - * \retval FLAC__Metadata_Chain* - * \c NULL if there was an error allocating memory, else the new instance. - */ -FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new(void); - -/** Free a chain instance. Deletes the object pointed to by \a chain. - * - * \param chain A pointer to an existing chain. - * \assert - * \code chain != NULL \endcode - */ -FLAC_API void FLAC__metadata_chain_delete(FLAC__Metadata_Chain *chain); - -/** Get the current status of the chain. Call this after a function - * returns \c false to get the reason for the error. Also resets the - * status to FLAC__METADATA_CHAIN_STATUS_OK. - * - * \param chain A pointer to an existing chain. - * \assert - * \code chain != NULL \endcode - * \retval FLAC__Metadata_ChainStatus - * The current status of the chain. - */ -FLAC_API FLAC__Metadata_ChainStatus FLAC__metadata_chain_status(FLAC__Metadata_Chain *chain); - -/** Read all metadata from a FLAC file into the chain. - * - * \param chain A pointer to an existing chain. - * \param filename The path to the FLAC file to read. - * \assert - * \code chain != NULL \endcode - * \code filename != NULL \endcode - * \retval FLAC__bool - * \c true if a valid list of metadata blocks was read from - * \a filename, else \c false. On failure, check the status with - * FLAC__metadata_chain_status(). - */ -FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const char *filename); - -/** Read all metadata from an Ogg FLAC file into the chain. - * - * \note Ogg FLAC metadata data writing is not supported yet and - * FLAC__metadata_chain_write() will fail. - * - * \param chain A pointer to an existing chain. - * \param filename The path to the Ogg FLAC file to read. - * \assert - * \code chain != NULL \endcode - * \code filename != NULL \endcode - * \retval FLAC__bool - * \c true if a valid list of metadata blocks was read from - * \a filename, else \c false. On failure, check the status with - * FLAC__metadata_chain_status(). - */ -FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg(FLAC__Metadata_Chain *chain, const char *filename); - -/** Read all metadata from a FLAC stream into the chain via I/O callbacks. - * - * The \a handle need only be open for reading, but must be seekable. - * The equivalent minimum stdio fopen() file mode is \c "r" (or \c "rb" - * for Windows). - * - * \param chain A pointer to an existing chain. - * \param handle The I/O handle of the FLAC stream to read. The - * handle will NOT be closed after the metadata is read; - * that is the duty of the caller. - * \param callbacks - * A set of callbacks to use for I/O. The mandatory - * callbacks are \a read, \a seek, and \a tell. - * \assert - * \code chain != NULL \endcode - * \retval FLAC__bool - * \c true if a valid list of metadata blocks was read from - * \a handle, else \c false. On failure, check the status with - * FLAC__metadata_chain_status(). - */ -FLAC_API FLAC__bool FLAC__metadata_chain_read_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks); - -/** Read all metadata from an Ogg FLAC stream into the chain via I/O callbacks. - * - * The \a handle need only be open for reading, but must be seekable. - * The equivalent minimum stdio fopen() file mode is \c "r" (or \c "rb" - * for Windows). - * - * \note Ogg FLAC metadata data writing is not supported yet and - * FLAC__metadata_chain_write() will fail. - * - * \param chain A pointer to an existing chain. - * \param handle The I/O handle of the Ogg FLAC stream to read. The - * handle will NOT be closed after the metadata is read; - * that is the duty of the caller. - * \param callbacks - * A set of callbacks to use for I/O. The mandatory - * callbacks are \a read, \a seek, and \a tell. - * \assert - * \code chain != NULL \endcode - * \retval FLAC__bool - * \c true if a valid list of metadata blocks was read from - * \a handle, else \c false. On failure, check the status with - * FLAC__metadata_chain_status(). - */ -FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks); - -/** Checks if writing the given chain would require the use of a - * temporary file, or if it could be written in place. - * - * Under certain conditions, padding can be utilized so that writing - * edited metadata back to the FLAC file does not require rewriting the - * entire file. If rewriting is required, then a temporary workfile is - * required. When writing metadata using callbacks, you must check - * this function to know whether to call - * FLAC__metadata_chain_write_with_callbacks() or - * FLAC__metadata_chain_write_with_callbacks_and_tempfile(). When - * writing with FLAC__metadata_chain_write(), the temporary file is - * handled internally. - * - * \param chain A pointer to an existing chain. - * \param use_padding - * Whether or not padding will be allowed to be used - * during the write. The value of \a use_padding given - * here must match the value later passed to - * FLAC__metadata_chain_write_with_callbacks() or - * FLAC__metadata_chain_write_with_callbacks_with_tempfile(). - * \assert - * \code chain != NULL \endcode - * \retval FLAC__bool - * \c true if writing the current chain would require a tempfile, or - * \c false if metadata can be written in place. - */ -FLAC_API FLAC__bool FLAC__metadata_chain_check_if_tempfile_needed(FLAC__Metadata_Chain *chain, FLAC__bool use_padding); - -/** Write all metadata out to the FLAC file. This function tries to be as - * efficient as possible; how the metadata is actually written is shown by - * the following: - * - * If the current chain is the same size as the existing metadata, the new - * data is written in place. - * - * If the current chain is longer than the existing metadata, and - * \a use_padding is \c true, and the last block is a PADDING block of - * sufficient length, the function will truncate the final padding block - * so that the overall size of the metadata is the same as the existing - * metadata, and then just rewrite the metadata. Otherwise, if not all of - * the above conditions are met, the entire FLAC file must be rewritten. - * If you want to use padding this way it is a good idea to call - * FLAC__metadata_chain_sort_padding() first so that you have the maximum - * amount of padding to work with, unless you need to preserve ordering - * of the PADDING blocks for some reason. - * - * If the current chain is shorter than the existing metadata, and - * \a use_padding is \c true, and the final block is a PADDING block, the padding - * is extended to make the overall size the same as the existing data. If - * \a use_padding is \c true and the last block is not a PADDING block, a new - * PADDING block is added to the end of the new data to make it the same - * size as the existing data (if possible, see the note to - * FLAC__metadata_simple_iterator_set_block() about the four byte limit) - * and the new data is written in place. If none of the above apply or - * \a use_padding is \c false, the entire FLAC file is rewritten. - * - * If \a preserve_file_stats is \c true, the owner and modification time will - * be preserved even if the FLAC file is written. - * - * For this write function to be used, the chain must have been read with - * FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg(), not - * FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(). - * - * \param chain A pointer to an existing chain. - * \param use_padding See above. - * \param preserve_file_stats See above. - * \assert - * \code chain != NULL \endcode - * \retval FLAC__bool - * \c true if the write succeeded, else \c false. On failure, - * check the status with FLAC__metadata_chain_status(). - */ -FLAC_API FLAC__bool FLAC__metadata_chain_write(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats); - -/** Write all metadata out to a FLAC stream via callbacks. - * - * (See FLAC__metadata_chain_write() for the details on how padding is - * used to write metadata in place if possible.) - * - * The \a handle must be open for updating and be seekable. The - * equivalent minimum stdio fopen() file mode is \c "r+" (or \c "r+b" - * for Windows). - * - * For this write function to be used, the chain must have been read with - * FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(), - * not FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg(). - * Also, FLAC__metadata_chain_check_if_tempfile_needed() must have returned - * \c false. - * - * \param chain A pointer to an existing chain. - * \param use_padding See FLAC__metadata_chain_write() - * \param handle The I/O handle of the FLAC stream to write. The - * handle will NOT be closed after the metadata is - * written; that is the duty of the caller. - * \param callbacks A set of callbacks to use for I/O. The mandatory - * callbacks are \a write and \a seek. - * \assert - * \code chain != NULL \endcode - * \retval FLAC__bool - * \c true if the write succeeded, else \c false. On failure, - * check the status with FLAC__metadata_chain_status(). - */ -FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks); - -/** Write all metadata out to a FLAC stream via callbacks. - * - * (See FLAC__metadata_chain_write() for the details on how padding is - * used to write metadata in place if possible.) - * - * This version of the write-with-callbacks function must be used when - * FLAC__metadata_chain_check_if_tempfile_needed() returns true. In - * this function, you must supply an I/O handle corresponding to the - * FLAC file to edit, and a temporary handle to which the new FLAC - * file will be written. It is the caller's job to move this temporary - * FLAC file on top of the original FLAC file to complete the metadata - * edit. - * - * The \a handle must be open for reading and be seekable. The - * equivalent minimum stdio fopen() file mode is \c "r" (or \c "rb" - * for Windows). - * - * The \a temp_handle must be open for writing. The - * equivalent minimum stdio fopen() file mode is \c "w" (or \c "wb" - * for Windows). It should be an empty stream, or at least positioned - * at the start-of-file (in which case it is the caller's duty to - * truncate it on return). - * - * For this write function to be used, the chain must have been read with - * FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(), - * not FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg(). - * Also, FLAC__metadata_chain_check_if_tempfile_needed() must have returned - * \c true. - * - * \param chain A pointer to an existing chain. - * \param use_padding See FLAC__metadata_chain_write() - * \param handle The I/O handle of the original FLAC stream to read. - * The handle will NOT be closed after the metadata is - * written; that is the duty of the caller. - * \param callbacks A set of callbacks to use for I/O on \a handle. - * The mandatory callbacks are \a read, \a seek, and - * \a eof. - * \param temp_handle The I/O handle of the FLAC stream to write. The - * handle will NOT be closed after the metadata is - * written; that is the duty of the caller. - * \param temp_callbacks - * A set of callbacks to use for I/O on temp_handle. - * The only mandatory callback is \a write. - * \assert - * \code chain != NULL \endcode - * \retval FLAC__bool - * \c true if the write succeeded, else \c false. On failure, - * check the status with FLAC__metadata_chain_status(). - */ -FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks_and_tempfile(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, FLAC__IOHandle temp_handle, FLAC__IOCallbacks temp_callbacks); - -/** Merge adjacent PADDING blocks into a single block. - * - * \note This function does not write to the FLAC file, it only - * modifies the chain. - * - * \warning Any iterator on the current chain will become invalid after this - * call. You should delete the iterator and get a new one. - * - * \param chain A pointer to an existing chain. - * \assert - * \code chain != NULL \endcode - */ -FLAC_API void FLAC__metadata_chain_merge_padding(FLAC__Metadata_Chain *chain); - -/** This function will move all PADDING blocks to the end on the metadata, - * then merge them into a single block. - * - * \note This function does not write to the FLAC file, it only - * modifies the chain. - * - * \warning Any iterator on the current chain will become invalid after this - * call. You should delete the iterator and get a new one. - * - * \param chain A pointer to an existing chain. - * \assert - * \code chain != NULL \endcode - */ -FLAC_API void FLAC__metadata_chain_sort_padding(FLAC__Metadata_Chain *chain); - - -/*********** FLAC__Metadata_Iterator ***********/ - -/** Create a new iterator instance. - * - * \retval FLAC__Metadata_Iterator* - * \c NULL if there was an error allocating memory, else the new instance. - */ -FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new(void); - -/** Free an iterator instance. Deletes the object pointed to by \a iterator. - * - * \param iterator A pointer to an existing iterator. - * \assert - * \code iterator != NULL \endcode - */ -FLAC_API void FLAC__metadata_iterator_delete(FLAC__Metadata_Iterator *iterator); - -/** Initialize the iterator to point to the first metadata block in the - * given chain. - * - * \param iterator A pointer to an existing iterator. - * \param chain A pointer to an existing and initialized (read) chain. - * \assert - * \code iterator != NULL \endcode - * \code chain != NULL \endcode - */ -FLAC_API void FLAC__metadata_iterator_init(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Chain *chain); - -/** Moves the iterator forward one metadata block, returning \c false if - * already at the end. - * - * \param iterator A pointer to an existing initialized iterator. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_iterator_init() - * \retval FLAC__bool - * \c false if already at the last metadata block of the chain, else - * \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_iterator_next(FLAC__Metadata_Iterator *iterator); - -/** Moves the iterator backward one metadata block, returning \c false if - * already at the beginning. - * - * \param iterator A pointer to an existing initialized iterator. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_iterator_init() - * \retval FLAC__bool - * \c false if already at the first metadata block of the chain, else - * \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_iterator_prev(FLAC__Metadata_Iterator *iterator); - -/** Get the type of the metadata block at the current position. - * - * \param iterator A pointer to an existing initialized iterator. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_iterator_init() - * \retval FLAC__MetadataType - * The type of the metadata block at the current iterator position. - */ -FLAC_API FLAC__MetadataType FLAC__metadata_iterator_get_block_type(const FLAC__Metadata_Iterator *iterator); - -/** Get the metadata block at the current position. You can modify - * the block in place but must write the chain before the changes - * are reflected to the FLAC file. You do not need to call - * FLAC__metadata_iterator_set_block() to reflect the changes; - * the pointer returned by FLAC__metadata_iterator_get_block() - * points directly into the chain. - * - * \warning - * Do not call FLAC__metadata_object_delete() on the returned object; - * to delete a block use FLAC__metadata_iterator_delete_block(). - * - * \param iterator A pointer to an existing initialized iterator. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_iterator_init() - * \retval FLAC__StreamMetadata* - * The current metadata block. - */ -FLAC_API FLAC__StreamMetadata *FLAC__metadata_iterator_get_block(FLAC__Metadata_Iterator *iterator); - -/** Set the metadata block at the current position, replacing the existing - * block. The new block passed in becomes owned by the chain and it will be - * deleted when the chain is deleted. - * - * \param iterator A pointer to an existing initialized iterator. - * \param block A pointer to a metadata block. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_iterator_init() - * \code block != NULL \endcode - * \retval FLAC__bool - * \c false if the conditions in the above description are not met, or - * a memory allocation error occurs, otherwise \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_iterator_set_block(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block); - -/** Removes the current block from the chain. If \a replace_with_padding is - * \c true, the block will instead be replaced with a padding block of equal - * size. You can not delete the STREAMINFO block. The iterator will be - * left pointing to the block before the one just "deleted", even if - * \a replace_with_padding is \c true. - * - * \param iterator A pointer to an existing initialized iterator. - * \param replace_with_padding See above. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_iterator_init() - * \retval FLAC__bool - * \c false if the conditions in the above description are not met, - * otherwise \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_iterator_delete_block(FLAC__Metadata_Iterator *iterator, FLAC__bool replace_with_padding); - -/** Insert a new block before the current block. You cannot insert a block - * before the first STREAMINFO block. You cannot insert a STREAMINFO block - * as there can be only one, the one that already exists at the head when you - * read in a chain. The chain takes ownership of the new block and it will be - * deleted when the chain is deleted. The iterator will be left pointing to - * the new block. - * - * \param iterator A pointer to an existing initialized iterator. - * \param block A pointer to a metadata block to insert. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_iterator_init() - * \retval FLAC__bool - * \c false if the conditions in the above description are not met, or - * a memory allocation error occurs, otherwise \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_before(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block); - -/** Insert a new block after the current block. You cannot insert a STREAMINFO - * block as there can be only one, the one that already exists at the head when - * you read in a chain. The chain takes ownership of the new block and it will - * be deleted when the chain is deleted. The iterator will be left pointing to - * the new block. - * - * \param iterator A pointer to an existing initialized iterator. - * \param block A pointer to a metadata block to insert. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_iterator_init() - * \retval FLAC__bool - * \c false if the conditions in the above description are not met, or - * a memory allocation error occurs, otherwise \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_after(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block); - -/* \} */ - - -/** \defgroup flac_metadata_object FLAC/metadata.h: metadata object methods - * \ingroup flac_metadata - * - * \brief - * This module contains methods for manipulating FLAC metadata objects. - * - * Since many are variable length we have to be careful about the memory - * management. We decree that all pointers to data in the object are - * owned by the object and memory-managed by the object. - * - * Use the FLAC__metadata_object_new() and FLAC__metadata_object_delete() - * functions to create all instances. When using the - * FLAC__metadata_object_set_*() functions to set pointers to data, set - * \a copy to \c true to have the function make it's own copy of the data, or - * to \c false to give the object ownership of your data. In the latter case - * your pointer must be freeable by free() and will be free()d when the object - * is FLAC__metadata_object_delete()d. It is legal to pass a null pointer as - * the data pointer to a FLAC__metadata_object_set_*() function as long as - * the length argument is 0 and the \a copy argument is \c false. - * - * The FLAC__metadata_object_new() and FLAC__metadata_object_clone() function - * will return \c NULL in the case of a memory allocation error, otherwise a new - * object. The FLAC__metadata_object_set_*() functions return \c false in the - * case of a memory allocation error. - * - * We don't have the convenience of C++ here, so note that the library relies - * on you to keep the types straight. In other words, if you pass, for - * example, a FLAC__StreamMetadata* that represents a STREAMINFO block to - * FLAC__metadata_object_application_set_data(), you will get an assertion - * failure. - * - * For convenience the FLAC__metadata_object_vorbiscomment_*() functions - * maintain a trailing NUL on each Vorbis comment entry. This is not counted - * toward the length or stored in the stream, but it can make working with plain - * comments (those that don't contain embedded-NULs in the value) easier. - * Entries passed into these functions have trailing NULs added if missing, and - * returned entries are guaranteed to have a trailing NUL. - * - * The FLAC__metadata_object_vorbiscomment_*() functions that take a Vorbis - * comment entry/name/value will first validate that it complies with the Vorbis - * comment specification and return false if it does not. - * - * There is no need to recalculate the length field on metadata blocks you - * have modified. They will be calculated automatically before they are - * written back to a file. - * - * \{ - */ - - -/** Create a new metadata object instance of the given type. - * - * The object will be "empty"; i.e. values and data pointers will be \c 0, - * with the exception of FLAC__METADATA_TYPE_VORBIS_COMMENT, which will have - * the vendor string set (but zero comments). - * - * Do not pass in a value greater than or equal to - * \a FLAC__METADATA_TYPE_UNDEFINED unless you really know what you're - * doing. - * - * \param type Type of object to create - * \retval FLAC__StreamMetadata* - * \c NULL if there was an error allocating memory or the type code is - * greater than FLAC__MAX_METADATA_TYPE_CODE, else the new instance. - */ -FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type); - -/** Create a copy of an existing metadata object. - * - * The copy is a "deep" copy, i.e. dynamically allocated data within the - * object is also copied. The caller takes ownership of the new block and - * is responsible for freeing it with FLAC__metadata_object_delete(). - * - * \param object Pointer to object to copy. - * \assert - * \code object != NULL \endcode - * \retval FLAC__StreamMetadata* - * \c NULL if there was an error allocating memory, else the new instance. - */ -FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMetadata *object); - -/** Free a metadata object. Deletes the object pointed to by \a object. - * - * The delete is a "deep" delete, i.e. dynamically allocated data within the - * object is also deleted. - * - * \param object A pointer to an existing object. - * \assert - * \code object != NULL \endcode - */ -FLAC_API void FLAC__metadata_object_delete(FLAC__StreamMetadata *object); - -/** Compares two metadata objects. - * - * The compare is "deep", i.e. dynamically allocated data within the - * object is also compared. - * - * \param block1 A pointer to an existing object. - * \param block2 A pointer to an existing object. - * \assert - * \code block1 != NULL \endcode - * \code block2 != NULL \endcode - * \retval FLAC__bool - * \c true if objects are identical, else \c false. - */ -FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *block1, const FLAC__StreamMetadata *block2); - -/** Sets the application data of an APPLICATION block. - * - * If \a copy is \c true, a copy of the data is stored; otherwise, the object - * takes ownership of the pointer. The existing data will be freed if this - * function is successful, otherwise the original data will remain if \a copy - * is \c true and malloc() fails. - * - * \note It is safe to pass a const pointer to \a data if \a copy is \c true. - * - * \param object A pointer to an existing APPLICATION object. - * \param data A pointer to the data to set. - * \param length The length of \a data in bytes. - * \param copy See above. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_APPLICATION \endcode - * \code (data != NULL && length > 0) || - * (data == NULL && length == 0 && copy == false) \endcode - * \retval FLAC__bool - * \c false if \a copy is \c true and malloc() fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, uint32_t length, FLAC__bool copy); - -/** Resize the seekpoint array. - * - * If the size shrinks, elements will truncated; if it grows, new placeholder - * points will be added to the end. - * - * \param object A pointer to an existing SEEKTABLE object. - * \param new_num_points The desired length of the array; may be \c 0. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode - * \code (object->data.seek_table.points == NULL && object->data.seek_table.num_points == 0) || - * (object->data.seek_table.points != NULL && object->data.seek_table.num_points > 0) \endcode - * \retval FLAC__bool - * \c false if memory allocation error, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMetadata *object, uint32_t new_num_points); - -/** Set a seekpoint in a seektable. - * - * \param object A pointer to an existing SEEKTABLE object. - * \param point_num Index into seekpoint array to set. - * \param point The point to set. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode - * \code object->data.seek_table.num_points > point_num \endcode - */ -FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point); - -/** Insert a seekpoint into a seektable. - * - * \param object A pointer to an existing SEEKTABLE object. - * \param point_num Index into seekpoint array to set. - * \param point The point to set. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode - * \code object->data.seek_table.num_points >= point_num \endcode - * \retval FLAC__bool - * \c false if memory allocation error, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point); - -/** Delete a seekpoint from a seektable. - * - * \param object A pointer to an existing SEEKTABLE object. - * \param point_num Index into seekpoint array to set. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode - * \code object->data.seek_table.num_points > point_num \endcode - * \retval FLAC__bool - * \c false if memory allocation error, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_seektable_delete_point(FLAC__StreamMetadata *object, uint32_t point_num); - -/** Check a seektable to see if it conforms to the FLAC specification. - * See the format specification for limits on the contents of the - * seektable. - * - * \param object A pointer to an existing SEEKTABLE object. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode - * \retval FLAC__bool - * \c false if seek table is illegal, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_seektable_is_legal(const FLAC__StreamMetadata *object); - -/** Append a number of placeholder points to the end of a seek table. - * - * \note - * As with the other ..._seektable_template_... functions, you should - * call FLAC__metadata_object_seektable_template_sort() when finished - * to make the seek table legal. - * - * \param object A pointer to an existing SEEKTABLE object. - * \param num The number of placeholder points to append. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode - * \retval FLAC__bool - * \c false if memory allocation fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_placeholders(FLAC__StreamMetadata *object, uint32_t num); - -/** Append a specific seek point template to the end of a seek table. - * - * \note - * As with the other ..._seektable_template_... functions, you should - * call FLAC__metadata_object_seektable_template_sort() when finished - * to make the seek table legal. - * - * \param object A pointer to an existing SEEKTABLE object. - * \param sample_number The sample number of the seek point template. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode - * \retval FLAC__bool - * \c false if memory allocation fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_point(FLAC__StreamMetadata *object, FLAC__uint64 sample_number); - -/** Append specific seek point templates to the end of a seek table. - * - * \note - * As with the other ..._seektable_template_... functions, you should - * call FLAC__metadata_object_seektable_template_sort() when finished - * to make the seek table legal. - * - * \param object A pointer to an existing SEEKTABLE object. - * \param sample_numbers An array of sample numbers for the seek points. - * \param num The number of seek point templates to append. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode - * \retval FLAC__bool - * \c false if memory allocation fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC__StreamMetadata *object, FLAC__uint64 sample_numbers[], uint32_t num); - -/** Append a set of evenly-spaced seek point templates to the end of a - * seek table. - * - * \note - * As with the other ..._seektable_template_... functions, you should - * call FLAC__metadata_object_seektable_template_sort() when finished - * to make the seek table legal. - * - * \param object A pointer to an existing SEEKTABLE object. - * \param num The number of placeholder points to append. - * \param total_samples The total number of samples to be encoded; - * the seekpoints will be spaced approximately - * \a total_samples / \a num samples apart. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode - * \code total_samples > 0 \endcode - * \retval FLAC__bool - * \c false if memory allocation fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points(FLAC__StreamMetadata *object, uint32_t num, FLAC__uint64 total_samples); - -/** Append a set of evenly-spaced seek point templates to the end of a - * seek table. - * - * \note - * As with the other ..._seektable_template_... functions, you should - * call FLAC__metadata_object_seektable_template_sort() when finished - * to make the seek table legal. - * - * \param object A pointer to an existing SEEKTABLE object. - * \param samples The number of samples apart to space the placeholder - * points. The first point will be at sample \c 0, the - * second at sample \a samples, then 2*\a samples, and - * so on. As long as \a samples and \a total_samples - * are greater than \c 0, there will always be at least - * one seekpoint at sample \c 0. - * \param total_samples The total number of samples to be encoded; - * the seekpoints will be spaced - * \a samples samples apart. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode - * \code samples > 0 \endcode - * \code total_samples > 0 \endcode - * \retval FLAC__bool - * \c false if memory allocation fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(FLAC__StreamMetadata *object, uint32_t samples, FLAC__uint64 total_samples); - -/** Sort a seek table's seek points according to the format specification, - * removing duplicates. - * - * \param object A pointer to a seek table to be sorted. - * \param compact If \c false, behaves like FLAC__format_seektable_sort(). - * If \c true, duplicates are deleted and the seek table is - * shrunk appropriately; the number of placeholder points - * present in the seek table will be the same after the call - * as before. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode - * \retval FLAC__bool - * \c false if realloc() fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_sort(FLAC__StreamMetadata *object, FLAC__bool compact); - -/** Sets the vendor string in a VORBIS_COMMENT block. - * - * For convenience, a trailing NUL is added to the entry if it doesn't have - * one already. - * - * If \a copy is \c true, a copy of the entry is stored; otherwise, the object - * takes ownership of the \c entry.entry pointer. - * - * \note If this function returns \c false, the caller still owns the - * pointer. - * - * \param object A pointer to an existing VORBIS_COMMENT object. - * \param entry The entry to set the vendor string to. - * \param copy See above. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode - * \code (entry.entry != NULL && entry.length > 0) || - * (entry.entry == NULL && entry.length == 0) \endcode - * \retval FLAC__bool - * \c false if memory allocation fails or \a entry does not comply with the - * Vorbis comment specification, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_vendor_string(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy); - -/** Resize the comment array. - * - * If the size shrinks, elements will truncated; if it grows, new empty - * fields will be added to the end. - * - * \param object A pointer to an existing VORBIS_COMMENT object. - * \param new_num_comments The desired length of the array; may be \c 0. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode - * \code (object->data.vorbis_comment.comments == NULL && object->data.vorbis_comment.num_comments == 0) || - * (object->data.vorbis_comment.comments != NULL && object->data.vorbis_comment.num_comments > 0) \endcode - * \retval FLAC__bool - * \c false if memory allocation fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__StreamMetadata *object, uint32_t new_num_comments); - -/** Sets a comment in a VORBIS_COMMENT block. - * - * For convenience, a trailing NUL is added to the entry if it doesn't have - * one already. - * - * If \a copy is \c true, a copy of the entry is stored; otherwise, the object - * takes ownership of the \c entry.entry pointer. - * - * \note If this function returns \c false, the caller still owns the - * pointer. - * - * \param object A pointer to an existing VORBIS_COMMENT object. - * \param comment_num Index into comment array to set. - * \param entry The entry to set the comment to. - * \param copy See above. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode - * \code comment_num < object->data.vorbis_comment.num_comments \endcode - * \code (entry.entry != NULL && entry.length > 0) || - * (entry.entry == NULL && entry.length == 0) \endcode - * \retval FLAC__bool - * \c false if memory allocation fails or \a entry does not comply with the - * Vorbis comment specification, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__StreamMetadata *object, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy); - -/** Insert a comment in a VORBIS_COMMENT block at the given index. - * - * For convenience, a trailing NUL is added to the entry if it doesn't have - * one already. - * - * If \a copy is \c true, a copy of the entry is stored; otherwise, the object - * takes ownership of the \c entry.entry pointer. - * - * \note If this function returns \c false, the caller still owns the - * pointer. - * - * \param object A pointer to an existing VORBIS_COMMENT object. - * \param comment_num The index at which to insert the comment. The comments - * at and after \a comment_num move right one position. - * To append a comment to the end, set \a comment_num to - * \c object->data.vorbis_comment.num_comments . - * \param entry The comment to insert. - * \param copy See above. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode - * \code object->data.vorbis_comment.num_comments >= comment_num \endcode - * \code (entry.entry != NULL && entry.length > 0) || - * (entry.entry == NULL && entry.length == 0 && copy == false) \endcode - * \retval FLAC__bool - * \c false if memory allocation fails or \a entry does not comply with the - * Vorbis comment specification, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__StreamMetadata *object, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy); - -/** Appends a comment to a VORBIS_COMMENT block. - * - * For convenience, a trailing NUL is added to the entry if it doesn't have - * one already. - * - * If \a copy is \c true, a copy of the entry is stored; otherwise, the object - * takes ownership of the \c entry.entry pointer. - * - * \note If this function returns \c false, the caller still owns the - * pointer. - * - * \param object A pointer to an existing VORBIS_COMMENT object. - * \param entry The comment to insert. - * \param copy See above. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode - * \code (entry.entry != NULL && entry.length > 0) || - * (entry.entry == NULL && entry.length == 0 && copy == false) \endcode - * \retval FLAC__bool - * \c false if memory allocation fails or \a entry does not comply with the - * Vorbis comment specification, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_append_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy); - -/** Replaces comments in a VORBIS_COMMENT block with a new one. - * - * For convenience, a trailing NUL is added to the entry if it doesn't have - * one already. - * - * Depending on the value of \a all, either all or just the first comment - * whose field name(s) match the given entry's name will be replaced by the - * given entry. If no comments match, \a entry will simply be appended. - * - * If \a copy is \c true, a copy of the entry is stored; otherwise, the object - * takes ownership of the \c entry.entry pointer. - * - * \note If this function returns \c false, the caller still owns the - * pointer. - * - * \param object A pointer to an existing VORBIS_COMMENT object. - * \param entry The comment to insert. - * \param all If \c true, all comments whose field name matches - * \a entry's field name will be removed, and \a entry will - * be inserted at the position of the first matching - * comment. If \c false, only the first comment whose - * field name matches \a entry's field name will be - * replaced with \a entry. - * \param copy See above. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode - * \code (entry.entry != NULL && entry.length > 0) || - * (entry.entry == NULL && entry.length == 0 && copy == false) \endcode - * \retval FLAC__bool - * \c false if memory allocation fails or \a entry does not comply with the - * Vorbis comment specification, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_replace_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool all, FLAC__bool copy); - -/** Delete a comment in a VORBIS_COMMENT block at the given index. - * - * \param object A pointer to an existing VORBIS_COMMENT object. - * \param comment_num The index of the comment to delete. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode - * \code object->data.vorbis_comment.num_comments > comment_num \endcode - * \retval FLAC__bool - * \c false if realloc() fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, uint32_t comment_num); - -/** Creates a Vorbis comment entry from NUL-terminated name and value strings. - * - * On return, the filled-in \a entry->entry pointer will point to malloc()ed - * memory and shall be owned by the caller. For convenience the entry will - * have a terminating NUL. - * - * \param entry A pointer to a Vorbis comment entry. The entry's - * \c entry pointer should not point to allocated - * memory as it will be overwritten. - * \param field_name The field name in ASCII, \c NUL terminated. - * \param field_value The field value in UTF-8, \c NUL terminated. - * \assert - * \code entry != NULL \endcode - * \code field_name != NULL \endcode - * \code field_value != NULL \endcode - * \retval FLAC__bool - * \c false if malloc() fails, or if \a field_name or \a field_value does - * not comply with the Vorbis comment specification, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, const char *field_value); - -/** Splits a Vorbis comment entry into NUL-terminated name and value strings. - * - * The returned pointers to name and value will be allocated by malloc() - * and shall be owned by the caller. - * - * \param entry An existing Vorbis comment entry. - * \param field_name The address of where the returned pointer to the - * field name will be stored. - * \param field_value The address of where the returned pointer to the - * field value will be stored. - * \assert - * \code (entry.entry != NULL && entry.length > 0) \endcode - * \code memchr(entry.entry, '=', entry.length) != NULL \endcode - * \code field_name != NULL \endcode - * \code field_value != NULL \endcode - * \retval FLAC__bool - * \c false if memory allocation fails or \a entry does not comply with the - * Vorbis comment specification, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(const FLAC__StreamMetadata_VorbisComment_Entry entry, char **field_name, char **field_value); - -/** Check if the given Vorbis comment entry's field name matches the given - * field name. - * - * \param entry An existing Vorbis comment entry. - * \param field_name The field name to check. - * \param field_name_length The length of \a field_name, not including the - * terminating \c NUL. - * \assert - * \code (entry.entry != NULL && entry.length > 0) \endcode - * \retval FLAC__bool - * \c true if the field names match, else \c false - */ -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry entry, const char *field_name, uint32_t field_name_length); - -/** Find a Vorbis comment with the given field name. - * - * The search begins at entry number \a offset; use an offset of 0 to - * search from the beginning of the comment array. - * - * \param object A pointer to an existing VORBIS_COMMENT object. - * \param offset The offset into the comment array from where to start - * the search. - * \param field_name The field name of the comment to find. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode - * \code field_name != NULL \endcode - * \retval int - * The offset in the comment array of the first comment whose field - * name matches \a field_name, or \c -1 if no match was found. - */ -FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, uint32_t offset, const char *field_name); - -/** Remove first Vorbis comment matching the given field name. - * - * \param object A pointer to an existing VORBIS_COMMENT object. - * \param field_name The field name of comment to delete. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode - * \retval int - * \c -1 for memory allocation error, \c 0 for no matching entries, - * \c 1 for one matching entry deleted. - */ -FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entry_matching(FLAC__StreamMetadata *object, const char *field_name); - -/** Remove all Vorbis comments matching the given field name. - * - * \param object A pointer to an existing VORBIS_COMMENT object. - * \param field_name The field name of comments to delete. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode - * \retval int - * \c -1 for memory allocation error, \c 0 for no matching entries, - * else the number of matching entries deleted. - */ -FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__StreamMetadata *object, const char *field_name); - -/** Create a new CUESHEET track instance. - * - * The object will be "empty"; i.e. values and data pointers will be \c 0. - * - * \retval FLAC__StreamMetadata_CueSheet_Track* - * \c NULL if there was an error allocating memory, else the new instance. - */ -FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new(void); - -/** Create a copy of an existing CUESHEET track object. - * - * The copy is a "deep" copy, i.e. dynamically allocated data within the - * object is also copied. The caller takes ownership of the new object and - * is responsible for freeing it with - * FLAC__metadata_object_cuesheet_track_delete(). - * - * \param object Pointer to object to copy. - * \assert - * \code object != NULL \endcode - * \retval FLAC__StreamMetadata_CueSheet_Track* - * \c NULL if there was an error allocating memory, else the new instance. - */ -FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_clone(const FLAC__StreamMetadata_CueSheet_Track *object); - -/** Delete a CUESHEET track object - * - * \param object A pointer to an existing CUESHEET track object. - * \assert - * \code object != NULL \endcode - */ -FLAC_API void FLAC__metadata_object_cuesheet_track_delete(FLAC__StreamMetadata_CueSheet_Track *object); - -/** Resize a track's index point array. - * - * If the size shrinks, elements will truncated; if it grows, new blank - * indices will be added to the end. - * - * \param object A pointer to an existing CUESHEET object. - * \param track_num The index of the track to modify. NOTE: this is not - * necessarily the same as the track's \a number field. - * \param new_num_indices The desired length of the array; may be \c 0. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode - * \code object->data.cue_sheet.num_tracks > track_num \endcode - * \code (object->data.cue_sheet.tracks[track_num].indices == NULL && object->data.cue_sheet.tracks[track_num].num_indices == 0) || - * (object->data.cue_sheet.tracks[track_num].indices != NULL && object->data.cue_sheet.tracks[track_num].num_indices > 0) \endcode - * \retval FLAC__bool - * \c false if memory allocation error, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t new_num_indices); - -/** Insert an index point in a CUESHEET track at the given index. - * - * \param object A pointer to an existing CUESHEET object. - * \param track_num The index of the track to modify. NOTE: this is not - * necessarily the same as the track's \a number field. - * \param index_num The index into the track's index array at which to - * insert the index point. NOTE: this is not necessarily - * the same as the index point's \a number field. The - * indices at and after \a index_num move right one - * position. To append an index point to the end, set - * \a index_num to - * \c object->data.cue_sheet.tracks[track_num].num_indices . - * \param index The index point to insert. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode - * \code object->data.cue_sheet.num_tracks > track_num \endcode - * \code object->data.cue_sheet.tracks[track_num].num_indices >= index_num \endcode - * \retval FLAC__bool - * \c false if realloc() fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num, FLAC__StreamMetadata_CueSheet_Index index); - -/** Insert a blank index point in a CUESHEET track at the given index. - * - * A blank index point is one in which all field values are zero. - * - * \param object A pointer to an existing CUESHEET object. - * \param track_num The index of the track to modify. NOTE: this is not - * necessarily the same as the track's \a number field. - * \param index_num The index into the track's index array at which to - * insert the index point. NOTE: this is not necessarily - * the same as the index point's \a number field. The - * indices at and after \a index_num move right one - * position. To append an index point to the end, set - * \a index_num to - * \c object->data.cue_sheet.tracks[track_num].num_indices . - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode - * \code object->data.cue_sheet.num_tracks > track_num \endcode - * \code object->data.cue_sheet.tracks[track_num].num_indices >= index_num \endcode - * \retval FLAC__bool - * \c false if realloc() fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num); - -/** Delete an index point in a CUESHEET track at the given index. - * - * \param object A pointer to an existing CUESHEET object. - * \param track_num The index into the track array of the track to - * modify. NOTE: this is not necessarily the same - * as the track's \a number field. - * \param index_num The index into the track's index array of the index - * to delete. NOTE: this is not necessarily the same - * as the index's \a number field. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode - * \code object->data.cue_sheet.num_tracks > track_num \endcode - * \code object->data.cue_sheet.tracks[track_num].num_indices > index_num \endcode - * \retval FLAC__bool - * \c false if realloc() fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num); - -/** Resize the track array. - * - * If the size shrinks, elements will truncated; if it grows, new blank - * tracks will be added to the end. - * - * \param object A pointer to an existing CUESHEET object. - * \param new_num_tracks The desired length of the array; may be \c 0. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode - * \code (object->data.cue_sheet.tracks == NULL && object->data.cue_sheet.num_tracks == 0) || - * (object->data.cue_sheet.tracks != NULL && object->data.cue_sheet.num_tracks > 0) \endcode - * \retval FLAC__bool - * \c false if memory allocation error, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, uint32_t new_num_tracks); - -/** Sets a track in a CUESHEET block. - * - * If \a copy is \c true, a copy of the track is stored; otherwise, the object - * takes ownership of the \a track pointer. - * - * \param object A pointer to an existing CUESHEET object. - * \param track_num Index into track array to set. NOTE: this is not - * necessarily the same as the track's \a number field. - * \param track The track to set the track to. You may safely pass in - * a const pointer if \a copy is \c true. - * \param copy See above. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode - * \code track_num < object->data.cue_sheet.num_tracks \endcode - * \code (track->indices != NULL && track->num_indices > 0) || - * (track->indices == NULL && track->num_indices == 0) \endcode - * \retval FLAC__bool - * \c false if \a copy is \c true and malloc() fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadata *object, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy); - -/** Insert a track in a CUESHEET block at the given index. - * - * If \a copy is \c true, a copy of the track is stored; otherwise, the object - * takes ownership of the \a track pointer. - * - * \param object A pointer to an existing CUESHEET object. - * \param track_num The index at which to insert the track. NOTE: this - * is not necessarily the same as the track's \a number - * field. The tracks at and after \a track_num move right - * one position. To append a track to the end, set - * \a track_num to \c object->data.cue_sheet.num_tracks . - * \param track The track to insert. You may safely pass in a const - * pointer if \a copy is \c true. - * \param copy See above. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode - * \code object->data.cue_sheet.num_tracks >= track_num \endcode - * \retval FLAC__bool - * \c false if \a copy is \c true and malloc() fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy); - -/** Insert a blank track in a CUESHEET block at the given index. - * - * A blank track is one in which all field values are zero. - * - * \param object A pointer to an existing CUESHEET object. - * \param track_num The index at which to insert the track. NOTE: this - * is not necessarily the same as the track's \a number - * field. The tracks at and after \a track_num move right - * one position. To append a track to the end, set - * \a track_num to \c object->data.cue_sheet.num_tracks . - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode - * \code object->data.cue_sheet.num_tracks >= track_num \endcode - * \retval FLAC__bool - * \c false if \a copy is \c true and malloc() fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, uint32_t track_num); - -/** Delete a track in a CUESHEET block at the given index. - * - * \param object A pointer to an existing CUESHEET object. - * \param track_num The index into the track array of the track to - * delete. NOTE: this is not necessarily the same - * as the track's \a number field. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode - * \code object->data.cue_sheet.num_tracks > track_num \endcode - * \retval FLAC__bool - * \c false if realloc() fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, uint32_t track_num); - -/** Check a cue sheet to see if it conforms to the FLAC specification. - * See the format specification for limits on the contents of the - * cue sheet. - * - * \param object A pointer to an existing CUESHEET object. - * \param check_cd_da_subset If \c true, check CUESHEET against more - * stringent requirements for a CD-DA (audio) disc. - * \param violation Address of a pointer to a string. If there is a - * violation, a pointer to a string explanation of the - * violation will be returned here. \a violation may be - * \c NULL if you don't need the returned string. Do not - * free the returned string; it will always point to static - * data. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode - * \retval FLAC__bool - * \c false if cue sheet is illegal, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_is_legal(const FLAC__StreamMetadata *object, FLAC__bool check_cd_da_subset, const char **violation); - -/** Calculate and return the CDDB/freedb ID for a cue sheet. The function - * assumes the cue sheet corresponds to a CD; the result is undefined - * if the cuesheet's is_cd bit is not set. - * - * \param object A pointer to an existing CUESHEET object. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode - * \retval FLAC__uint32 - * The unsigned integer representation of the CDDB/freedb ID - */ -FLAC_API FLAC__uint32 FLAC__metadata_object_cuesheet_calculate_cddb_id(const FLAC__StreamMetadata *object); - -/** Sets the MIME type of a PICTURE block. - * - * If \a copy is \c true, a copy of the string is stored; otherwise, the object - * takes ownership of the pointer. The existing string will be freed if this - * function is successful, otherwise the original string will remain if \a copy - * is \c true and malloc() fails. - * - * \note It is safe to pass a const pointer to \a mime_type if \a copy is \c true. - * - * \param object A pointer to an existing PICTURE object. - * \param mime_type A pointer to the MIME type string. The string must be - * ASCII characters 0x20-0x7e, NUL-terminated. No validation - * is done. - * \param copy See above. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode - * \code (mime_type != NULL) \endcode - * \retval FLAC__bool - * \c false if \a copy is \c true and malloc() fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_picture_set_mime_type(FLAC__StreamMetadata *object, char *mime_type, FLAC__bool copy); - -/** Sets the description of a PICTURE block. - * - * If \a copy is \c true, a copy of the string is stored; otherwise, the object - * takes ownership of the pointer. The existing string will be freed if this - * function is successful, otherwise the original string will remain if \a copy - * is \c true and malloc() fails. - * - * \note It is safe to pass a const pointer to \a description if \a copy is \c true. - * - * \param object A pointer to an existing PICTURE object. - * \param description A pointer to the description string. The string must be - * valid UTF-8, NUL-terminated. No validation is done. - * \param copy See above. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode - * \code (description != NULL) \endcode - * \retval FLAC__bool - * \c false if \a copy is \c true and malloc() fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_picture_set_description(FLAC__StreamMetadata *object, FLAC__byte *description, FLAC__bool copy); - -/** Sets the picture data of a PICTURE block. - * - * If \a copy is \c true, a copy of the data is stored; otherwise, the object - * takes ownership of the pointer. Also sets the \a data_length field of the - * metadata object to what is passed in as the \a length parameter. The - * existing data will be freed if this function is successful, otherwise the - * original data and data_length will remain if \a copy is \c true and - * malloc() fails. - * - * \note It is safe to pass a const pointer to \a data if \a copy is \c true. - * - * \param object A pointer to an existing PICTURE object. - * \param data A pointer to the data to set. - * \param length The length of \a data in bytes. - * \param copy See above. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode - * \code (data != NULL && length > 0) || - * (data == NULL && length == 0 && copy == false) \endcode - * \retval FLAC__bool - * \c false if \a copy is \c true and malloc() fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_picture_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, FLAC__uint32 length, FLAC__bool copy); - -/** Check a PICTURE block to see if it conforms to the FLAC specification. - * See the format specification for limits on the contents of the - * PICTURE block. - * - * \param object A pointer to existing PICTURE block to be checked. - * \param violation Address of a pointer to a string. If there is a - * violation, a pointer to a string explanation of the - * violation will be returned here. \a violation may be - * \c NULL if you don't need the returned string. Do not - * free the returned string; it will always point to static - * data. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode - * \retval FLAC__bool - * \c false if PICTURE block is illegal, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_picture_is_legal(const FLAC__StreamMetadata *object, const char **violation); - -/* \} */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/flac/include/FLAC/ordinals.h b/lib/flac/include/FLAC/ordinals.h deleted file mode 100644 index 75b830d..0000000 --- a/lib/flac/include/FLAC/ordinals.h +++ /dev/null @@ -1,85 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__ORDINALS_H -#define FLAC__ORDINALS_H - -#if defined(_MSC_VER) && _MSC_VER < 1600 - -/* Microsoft Visual Studio earlier than the 2010 version did not provide - * the 1999 ISO C Standard header file . - */ - -typedef signed __int8 FLAC__int8; -typedef signed __int16 FLAC__int16; -typedef signed __int32 FLAC__int32; -typedef signed __int64 FLAC__int64; -typedef unsigned __int8 FLAC__uint8; -typedef unsigned __int16 FLAC__uint16; -typedef unsigned __int32 FLAC__uint32; -typedef unsigned __int64 FLAC__uint64; - -#else - -/* For MSVC 2010 and everything else which provides . */ - -#include - -typedef int8_t FLAC__int8; -typedef uint8_t FLAC__uint8; - -typedef int16_t FLAC__int16; -typedef int32_t FLAC__int32; -typedef int64_t FLAC__int64; -typedef uint16_t FLAC__uint16; -typedef uint32_t FLAC__uint32; -typedef uint64_t FLAC__uint64; - -#endif - -typedef int FLAC__bool; - -typedef FLAC__uint8 FLAC__byte; - - -#ifdef true -#undef true -#endif -#ifdef false -#undef false -#endif -#ifndef __cplusplus -#define true 1 -#define false 0 -#endif - -#endif diff --git a/lib/flac/include/FLAC/stream_decoder.h b/lib/flac/include/FLAC/stream_decoder.h deleted file mode 100644 index 57215c5..0000000 --- a/lib/flac/include/FLAC/stream_decoder.h +++ /dev/null @@ -1,1559 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__STREAM_DECODER_H -#define FLAC__STREAM_DECODER_H - -#include /* for FILE */ -#include "export.h" -#include "format.h" - -#ifdef __cplusplus -extern "C" { -#endif - - -/** \file include/FLAC/stream_decoder.h - * - * \brief - * This module contains the functions which implement the stream - * decoder. - * - * See the detailed documentation in the - * \link flac_stream_decoder stream decoder \endlink module. - */ - -/** \defgroup flac_decoder FLAC/ \*_decoder.h: decoder interfaces - * \ingroup flac - * - * \brief - * This module describes the decoder layers provided by libFLAC. - * - * The stream decoder can be used to decode complete streams either from - * the client via callbacks, or directly from a file, depending on how - * it is initialized. When decoding via callbacks, the client provides - * callbacks for reading FLAC data and writing decoded samples, and - * handling metadata and errors. If the client also supplies seek-related - * callback, the decoder function for sample-accurate seeking within the - * FLAC input is also available. When decoding from a file, the client - * needs only supply a filename or open \c FILE* and write/metadata/error - * callbacks; the rest of the callbacks are supplied internally. For more - * info see the \link flac_stream_decoder stream decoder \endlink module. - */ - -/** \defgroup flac_stream_decoder FLAC/stream_decoder.h: stream decoder interface - * \ingroup flac_decoder - * - * \brief - * This module contains the functions which implement the stream - * decoder. - * - * The stream decoder can decode native FLAC, and optionally Ogg FLAC - * (check FLAC_API_SUPPORTS_OGG_FLAC) streams and files. - * - * The basic usage of this decoder is as follows: - * - The program creates an instance of a decoder using - * FLAC__stream_decoder_new(). - * - The program overrides the default settings using - * FLAC__stream_decoder_set_*() functions. - * - The program initializes the instance to validate the settings and - * prepare for decoding using - * - FLAC__stream_decoder_init_stream() or FLAC__stream_decoder_init_FILE() - * or FLAC__stream_decoder_init_file() for native FLAC, - * - FLAC__stream_decoder_init_ogg_stream() or FLAC__stream_decoder_init_ogg_FILE() - * or FLAC__stream_decoder_init_ogg_file() for Ogg FLAC - * - The program calls the FLAC__stream_decoder_process_*() functions - * to decode data, which subsequently calls the callbacks. - * - The program finishes the decoding with FLAC__stream_decoder_finish(), - * which flushes the input and output and resets the decoder to the - * uninitialized state. - * - The instance may be used again or deleted with - * FLAC__stream_decoder_delete(). - * - * In more detail, the program will create a new instance by calling - * FLAC__stream_decoder_new(), then call FLAC__stream_decoder_set_*() - * functions to override the default decoder options, and call - * one of the FLAC__stream_decoder_init_*() functions. - * - * There are three initialization functions for native FLAC, one for - * setting up the decoder to decode FLAC data from the client via - * callbacks, and two for decoding directly from a FLAC file. - * - * For decoding via callbacks, use FLAC__stream_decoder_init_stream(). - * You must also supply several callbacks for handling I/O. Some (like - * seeking) are optional, depending on the capabilities of the input. - * - * For decoding directly from a file, use FLAC__stream_decoder_init_FILE() - * or FLAC__stream_decoder_init_file(). Then you must only supply an open - * \c FILE* or filename and fewer callbacks; the decoder will handle - * the other callbacks internally. - * - * There are three similarly-named init functions for decoding from Ogg - * FLAC streams. Check \c FLAC_API_SUPPORTS_OGG_FLAC to find out if the - * library has been built with Ogg support. - * - * Once the decoder is initialized, your program will call one of several - * functions to start the decoding process: - * - * - FLAC__stream_decoder_process_single() - Tells the decoder to process at - * most one metadata block or audio frame and return, calling either the - * metadata callback or write callback, respectively, once. If the decoder - * loses sync it will return with only the error callback being called. - * - FLAC__stream_decoder_process_until_end_of_metadata() - Tells the decoder - * to process the stream from the current location and stop upon reaching - * the first audio frame. The client will get one metadata, write, or error - * callback per metadata block, audio frame, or sync error, respectively. - * - FLAC__stream_decoder_process_until_end_of_stream() - Tells the decoder - * to process the stream from the current location until the read callback - * returns FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM or - * FLAC__STREAM_DECODER_READ_STATUS_ABORT. The client will get one metadata, - * write, or error callback per metadata block, audio frame, or sync error, - * respectively. - * - * When the decoder has finished decoding (normally or through an abort), - * the instance is finished by calling FLAC__stream_decoder_finish(), which - * ensures the decoder is in the correct state and frees memory. Then the - * instance may be deleted with FLAC__stream_decoder_delete() or initialized - * again to decode another stream. - * - * Seeking is exposed through the FLAC__stream_decoder_seek_absolute() method. - * At any point after the stream decoder has been initialized, the client can - * call this function to seek to an exact sample within the stream. - * Subsequently, the first time the write callback is called it will be - * passed a (possibly partial) block starting at that sample. - * - * If the client cannot seek via the callback interface provided, but still - * has another way of seeking, it can flush the decoder using - * FLAC__stream_decoder_flush() and start feeding data from the new position - * through the read callback. - * - * The stream decoder also provides MD5 signature checking. If this is - * turned on before initialization, FLAC__stream_decoder_finish() will - * report when the decoded MD5 signature does not match the one stored - * in the STREAMINFO block. MD5 checking is automatically turned off - * (until the next FLAC__stream_decoder_reset()) if there is no signature - * in the STREAMINFO block or when a seek is attempted. - * - * The FLAC__stream_decoder_set_metadata_*() functions deserve special - * attention. By default, the decoder only calls the metadata_callback for - * the STREAMINFO block. These functions allow you to tell the decoder - * explicitly which blocks to parse and return via the metadata_callback - * and/or which to skip. Use a FLAC__stream_decoder_set_metadata_respond_all(), - * FLAC__stream_decoder_set_metadata_ignore() ... or FLAC__stream_decoder_set_metadata_ignore_all(), - * FLAC__stream_decoder_set_metadata_respond() ... sequence to exactly specify - * which blocks to return. Remember that metadata blocks can potentially - * be big (for example, cover art) so filtering out the ones you don't - * use can reduce the memory requirements of the decoder. Also note the - * special forms FLAC__stream_decoder_set_metadata_respond_application(id) - * and FLAC__stream_decoder_set_metadata_ignore_application(id) for - * filtering APPLICATION blocks based on the application ID. - * - * STREAMINFO and SEEKTABLE blocks are always parsed and used internally, but - * they still can legally be filtered from the metadata_callback. - * - * \note - * The "set" functions may only be called when the decoder is in the - * state FLAC__STREAM_DECODER_UNINITIALIZED, i.e. after - * FLAC__stream_decoder_new() or FLAC__stream_decoder_finish(), but - * before FLAC__stream_decoder_init_*(). If this is the case they will - * return \c true, otherwise \c false. - * - * \note - * FLAC__stream_decoder_finish() resets all settings to the constructor - * defaults, including the callbacks. - * - * \{ - */ - - -/** State values for a FLAC__StreamDecoder - * - * The decoder's state can be obtained by calling FLAC__stream_decoder_get_state(). - */ -typedef enum { - - FLAC__STREAM_DECODER_SEARCH_FOR_METADATA = 0, - /**< The decoder is ready to search for metadata. */ - - FLAC__STREAM_DECODER_READ_METADATA, - /**< The decoder is ready to or is in the process of reading metadata. */ - - FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC, - /**< The decoder is ready to or is in the process of searching for the - * frame sync code. - */ - - FLAC__STREAM_DECODER_READ_FRAME, - /**< The decoder is ready to or is in the process of reading a frame. */ - - FLAC__STREAM_DECODER_END_OF_STREAM, - /**< The decoder has reached the end of the stream. */ - - FLAC__STREAM_DECODER_OGG_ERROR, - /**< An error occurred in the underlying Ogg layer. */ - - FLAC__STREAM_DECODER_SEEK_ERROR, - /**< An error occurred while seeking. The decoder must be flushed - * with FLAC__stream_decoder_flush() or reset with - * FLAC__stream_decoder_reset() before decoding can continue. - */ - - FLAC__STREAM_DECODER_ABORTED, - /**< The decoder was aborted by the read or write callback. */ - - FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR, - /**< An error occurred allocating memory. The decoder is in an invalid - * state and can no longer be used. - */ - - FLAC__STREAM_DECODER_UNINITIALIZED - /**< The decoder is in the uninitialized state; one of the - * FLAC__stream_decoder_init_*() functions must be called before samples - * can be processed. - */ - -} FLAC__StreamDecoderState; - -/** Maps a FLAC__StreamDecoderState to a C string. - * - * Using a FLAC__StreamDecoderState as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamDecoderStateString[]; - - -/** Possible return values for the FLAC__stream_decoder_init_*() functions. - */ -typedef enum { - - FLAC__STREAM_DECODER_INIT_STATUS_OK = 0, - /**< Initialization was successful. */ - - FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER, - /**< The library was not compiled with support for the given container - * format. - */ - - FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS, - /**< A required callback was not supplied. */ - - FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR, - /**< An error occurred allocating memory. */ - - FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE, - /**< fopen() failed in FLAC__stream_decoder_init_file() or - * FLAC__stream_decoder_init_ogg_file(). */ - - FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED - /**< FLAC__stream_decoder_init_*() was called when the decoder was - * already initialized, usually because - * FLAC__stream_decoder_finish() was not called. - */ - -} FLAC__StreamDecoderInitStatus; - -/** Maps a FLAC__StreamDecoderInitStatus to a C string. - * - * Using a FLAC__StreamDecoderInitStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamDecoderInitStatusString[]; - - -/** Return values for the FLAC__StreamDecoder read callback. - */ -typedef enum { - - FLAC__STREAM_DECODER_READ_STATUS_CONTINUE, - /**< The read was OK and decoding can continue. */ - - FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM, - /**< The read was attempted while at the end of the stream. Note that - * the client must only return this value when the read callback was - * called when already at the end of the stream. Otherwise, if the read - * itself moves to the end of the stream, the client should still return - * the data and \c FLAC__STREAM_DECODER_READ_STATUS_CONTINUE, and then on - * the next read callback it should return - * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM with a byte count - * of \c 0. - */ - - FLAC__STREAM_DECODER_READ_STATUS_ABORT - /**< An unrecoverable error occurred. The decoder will return from the process call. */ - -} FLAC__StreamDecoderReadStatus; - -/** Maps a FLAC__StreamDecoderReadStatus to a C string. - * - * Using a FLAC__StreamDecoderReadStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamDecoderReadStatusString[]; - - -/** Return values for the FLAC__StreamDecoder seek callback. - */ -typedef enum { - - FLAC__STREAM_DECODER_SEEK_STATUS_OK, - /**< The seek was OK and decoding can continue. */ - - FLAC__STREAM_DECODER_SEEK_STATUS_ERROR, - /**< An unrecoverable error occurred. The decoder will return from the process call. */ - - FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED - /**< Client does not support seeking. */ - -} FLAC__StreamDecoderSeekStatus; - -/** Maps a FLAC__StreamDecoderSeekStatus to a C string. - * - * Using a FLAC__StreamDecoderSeekStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamDecoderSeekStatusString[]; - - -/** Return values for the FLAC__StreamDecoder tell callback. - */ -typedef enum { - - FLAC__STREAM_DECODER_TELL_STATUS_OK, - /**< The tell was OK and decoding can continue. */ - - FLAC__STREAM_DECODER_TELL_STATUS_ERROR, - /**< An unrecoverable error occurred. The decoder will return from the process call. */ - - FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED - /**< Client does not support telling the position. */ - -} FLAC__StreamDecoderTellStatus; - -/** Maps a FLAC__StreamDecoderTellStatus to a C string. - * - * Using a FLAC__StreamDecoderTellStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamDecoderTellStatusString[]; - - -/** Return values for the FLAC__StreamDecoder length callback. - */ -typedef enum { - - FLAC__STREAM_DECODER_LENGTH_STATUS_OK, - /**< The length call was OK and decoding can continue. */ - - FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR, - /**< An unrecoverable error occurred. The decoder will return from the process call. */ - - FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED - /**< Client does not support reporting the length. */ - -} FLAC__StreamDecoderLengthStatus; - -/** Maps a FLAC__StreamDecoderLengthStatus to a C string. - * - * Using a FLAC__StreamDecoderLengthStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamDecoderLengthStatusString[]; - - -/** Return values for the FLAC__StreamDecoder write callback. - */ -typedef enum { - - FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE, - /**< The write was OK and decoding can continue. */ - - FLAC__STREAM_DECODER_WRITE_STATUS_ABORT - /**< An unrecoverable error occurred. The decoder will return from the process call. */ - -} FLAC__StreamDecoderWriteStatus; - -/** Maps a FLAC__StreamDecoderWriteStatus to a C string. - * - * Using a FLAC__StreamDecoderWriteStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamDecoderWriteStatusString[]; - - -/** Possible values passed back to the FLAC__StreamDecoder error callback. - * \c FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC is the generic catch- - * all. The rest could be caused by bad sync (false synchronization on - * data that is not the start of a frame) or corrupted data. The error - * itself is the decoder's best guess at what happened assuming a correct - * sync. For example \c FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER - * could be caused by a correct sync on the start of a frame, but some - * data in the frame header was corrupted. Or it could be the result of - * syncing on a point the stream that looked like the starting of a frame - * but was not. \c FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM - * could be because the decoder encountered a valid frame made by a future - * version of the encoder which it cannot parse, or because of a false - * sync making it appear as though an encountered frame was generated by - * a future encoder. - */ -typedef enum { - - FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC, - /**< An error in the stream caused the decoder to lose synchronization. */ - - FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER, - /**< The decoder encountered a corrupted frame header. */ - - FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH, - /**< The frame's data did not match the CRC in the footer. */ - - FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM - /**< The decoder encountered reserved fields in use in the stream. */ - -} FLAC__StreamDecoderErrorStatus; - -/** Maps a FLAC__StreamDecoderErrorStatus to a C string. - * - * Using a FLAC__StreamDecoderErrorStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamDecoderErrorStatusString[]; - - -/*********************************************************************** - * - * class FLAC__StreamDecoder - * - ***********************************************************************/ - -struct FLAC__StreamDecoderProtected; -struct FLAC__StreamDecoderPrivate; -/** The opaque structure definition for the stream decoder type. - * See the \link flac_stream_decoder stream decoder module \endlink - * for a detailed description. - */ -typedef struct { - struct FLAC__StreamDecoderProtected *protected_; /* avoid the C++ keyword 'protected' */ - struct FLAC__StreamDecoderPrivate *private_; /* avoid the C++ keyword 'private' */ -} FLAC__StreamDecoder; - -/** Signature for the read callback. - * - * A function pointer matching this signature must be passed to - * FLAC__stream_decoder_init*_stream(). The supplied function will be - * called when the decoder needs more input data. The address of the - * buffer to be filled is supplied, along with the number of bytes the - * buffer can hold. The callback may choose to supply less data and - * modify the byte count but must be careful not to overflow the buffer. - * The callback then returns a status code chosen from - * FLAC__StreamDecoderReadStatus. - * - * Here is an example of a read callback for stdio streams: - * \code - * FLAC__StreamDecoderReadStatus read_cb(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) - * { - * FILE *file = ((MyClientData*)client_data)->file; - * if(*bytes > 0) { - * *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, file); - * if(ferror(file)) - * return FLAC__STREAM_DECODER_READ_STATUS_ABORT; - * else if(*bytes == 0) - * return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; - * else - * return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; - * } - * else - * return FLAC__STREAM_DECODER_READ_STATUS_ABORT; - * } - * \endcode - * - * \note In general, FLAC__StreamDecoder functions which change the - * state should not be called on the \a decoder while in the callback. - * - * \param decoder The decoder instance calling the callback. - * \param buffer A pointer to a location for the callee to store - * data to be decoded. - * \param bytes A pointer to the size of the buffer. On entry - * to the callback, it contains the maximum number - * of bytes that may be stored in \a buffer. The - * callee must set it to the actual number of bytes - * stored (0 in case of error or end-of-stream) before - * returning. - * \param client_data The callee's client data set through - * FLAC__stream_decoder_init_*(). - * \retval FLAC__StreamDecoderReadStatus - * The callee's return status. Note that the callback should return - * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM if and only if - * zero bytes were read and there is no more data to be read. - */ -typedef FLAC__StreamDecoderReadStatus (*FLAC__StreamDecoderReadCallback)(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data); - -/** Signature for the seek callback. - * - * A function pointer matching this signature may be passed to - * FLAC__stream_decoder_init*_stream(). The supplied function will be - * called when the decoder needs to seek the input stream. The decoder - * will pass the absolute byte offset to seek to, 0 meaning the - * beginning of the stream. - * - * Here is an example of a seek callback for stdio streams: - * \code - * FLAC__StreamDecoderSeekStatus seek_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data) - * { - * FILE *file = ((MyClientData*)client_data)->file; - * if(file == stdin) - * return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED; - * else if(fseeko(file, (off_t)absolute_byte_offset, SEEK_SET) < 0) - * return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; - * else - * return FLAC__STREAM_DECODER_SEEK_STATUS_OK; - * } - * \endcode - * - * \note In general, FLAC__StreamDecoder functions which change the - * state should not be called on the \a decoder while in the callback. - * - * \param decoder The decoder instance calling the callback. - * \param absolute_byte_offset The offset from the beginning of the stream - * to seek to. - * \param client_data The callee's client data set through - * FLAC__stream_decoder_init_*(). - * \retval FLAC__StreamDecoderSeekStatus - * The callee's return status. - */ -typedef FLAC__StreamDecoderSeekStatus (*FLAC__StreamDecoderSeekCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data); - -/** Signature for the tell callback. - * - * A function pointer matching this signature may be passed to - * FLAC__stream_decoder_init*_stream(). The supplied function will be - * called when the decoder wants to know the current position of the - * stream. The callback should return the byte offset from the - * beginning of the stream. - * - * Here is an example of a tell callback for stdio streams: - * \code - * FLAC__StreamDecoderTellStatus tell_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) - * { - * FILE *file = ((MyClientData*)client_data)->file; - * off_t pos; - * if(file == stdin) - * return FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED; - * else if((pos = ftello(file)) < 0) - * return FLAC__STREAM_DECODER_TELL_STATUS_ERROR; - * else { - * *absolute_byte_offset = (FLAC__uint64)pos; - * return FLAC__STREAM_DECODER_TELL_STATUS_OK; - * } - * } - * \endcode - * - * \note In general, FLAC__StreamDecoder functions which change the - * state should not be called on the \a decoder while in the callback. - * - * \param decoder The decoder instance calling the callback. - * \param absolute_byte_offset A pointer to storage for the current offset - * from the beginning of the stream. - * \param client_data The callee's client data set through - * FLAC__stream_decoder_init_*(). - * \retval FLAC__StreamDecoderTellStatus - * The callee's return status. - */ -typedef FLAC__StreamDecoderTellStatus (*FLAC__StreamDecoderTellCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data); - -/** Signature for the length callback. - * - * A function pointer matching this signature may be passed to - * FLAC__stream_decoder_init*_stream(). The supplied function will be - * called when the decoder wants to know the total length of the stream - * in bytes. - * - * Here is an example of a length callback for stdio streams: - * \code - * FLAC__StreamDecoderLengthStatus length_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data) - * { - * FILE *file = ((MyClientData*)client_data)->file; - * struct stat filestats; - * - * if(file == stdin) - * return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED; - * else if(fstat(fileno(file), &filestats) != 0) - * return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR; - * else { - * *stream_length = (FLAC__uint64)filestats.st_size; - * return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; - * } - * } - * \endcode - * - * \note In general, FLAC__StreamDecoder functions which change the - * state should not be called on the \a decoder while in the callback. - * - * \param decoder The decoder instance calling the callback. - * \param stream_length A pointer to storage for the length of the stream - * in bytes. - * \param client_data The callee's client data set through - * FLAC__stream_decoder_init_*(). - * \retval FLAC__StreamDecoderLengthStatus - * The callee's return status. - */ -typedef FLAC__StreamDecoderLengthStatus (*FLAC__StreamDecoderLengthCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data); - -/** Signature for the EOF callback. - * - * A function pointer matching this signature may be passed to - * FLAC__stream_decoder_init*_stream(). The supplied function will be - * called when the decoder needs to know if the end of the stream has - * been reached. - * - * Here is an example of a EOF callback for stdio streams: - * FLAC__bool eof_cb(const FLAC__StreamDecoder *decoder, void *client_data) - * \code - * { - * FILE *file = ((MyClientData*)client_data)->file; - * return feof(file)? true : false; - * } - * \endcode - * - * \note In general, FLAC__StreamDecoder functions which change the - * state should not be called on the \a decoder while in the callback. - * - * \param decoder The decoder instance calling the callback. - * \param client_data The callee's client data set through - * FLAC__stream_decoder_init_*(). - * \retval FLAC__bool - * \c true if the currently at the end of the stream, else \c false. - */ -typedef FLAC__bool (*FLAC__StreamDecoderEofCallback)(const FLAC__StreamDecoder *decoder, void *client_data); - -/** Signature for the write callback. - * - * A function pointer matching this signature must be passed to one of - * the FLAC__stream_decoder_init_*() functions. - * The supplied function will be called when the decoder has decoded a - * single audio frame. The decoder will pass the frame metadata as well - * as an array of pointers (one for each channel) pointing to the - * decoded audio. - * - * \note In general, FLAC__StreamDecoder functions which change the - * state should not be called on the \a decoder while in the callback. - * - * \param decoder The decoder instance calling the callback. - * \param frame The description of the decoded frame. See - * FLAC__Frame. - * \param buffer An array of pointers to decoded channels of data. - * Each pointer will point to an array of signed - * samples of length \a frame->header.blocksize. - * Channels will be ordered according to the FLAC - * specification; see the documentation for the - * frame header. - * \param client_data The callee's client data set through - * FLAC__stream_decoder_init_*(). - * \retval FLAC__StreamDecoderWriteStatus - * The callee's return status. - */ -typedef FLAC__StreamDecoderWriteStatus (*FLAC__StreamDecoderWriteCallback)(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); - -/** Signature for the metadata callback. - * - * A function pointer matching this signature must be passed to one of - * the FLAC__stream_decoder_init_*() functions. - * The supplied function will be called when the decoder has decoded a - * metadata block. In a valid FLAC file there will always be one - * \c STREAMINFO block, followed by zero or more other metadata blocks. - * These will be supplied by the decoder in the same order as they - * appear in the stream and always before the first audio frame (i.e. - * write callback). The metadata block that is passed in must not be - * modified, and it doesn't live beyond the callback, so you should make - * a copy of it with FLAC__metadata_object_clone() if you will need it - * elsewhere. Since metadata blocks can potentially be large, by - * default the decoder only calls the metadata callback for the - * \c STREAMINFO block; you can instruct the decoder to pass or filter - * other blocks with FLAC__stream_decoder_set_metadata_*() calls. - * - * \note In general, FLAC__StreamDecoder functions which change the - * state should not be called on the \a decoder while in the callback. - * - * \param decoder The decoder instance calling the callback. - * \param metadata The decoded metadata block. - * \param client_data The callee's client data set through - * FLAC__stream_decoder_init_*(). - */ -typedef void (*FLAC__StreamDecoderMetadataCallback)(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); - -/** Signature for the error callback. - * - * A function pointer matching this signature must be passed to one of - * the FLAC__stream_decoder_init_*() functions. - * The supplied function will be called whenever an error occurs during - * decoding. - * - * \note In general, FLAC__StreamDecoder functions which change the - * state should not be called on the \a decoder while in the callback. - * - * \param decoder The decoder instance calling the callback. - * \param status The error encountered by the decoder. - * \param client_data The callee's client data set through - * FLAC__stream_decoder_init_*(). - */ -typedef void (*FLAC__StreamDecoderErrorCallback)(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); - - -/*********************************************************************** - * - * Class constructor/destructor - * - ***********************************************************************/ - -/** Create a new stream decoder instance. The instance is created with - * default settings; see the individual FLAC__stream_decoder_set_*() - * functions for each setting's default. - * - * \retval FLAC__StreamDecoder* - * \c NULL if there was an error allocating memory, else the new instance. - */ -FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new(void); - -/** Free a decoder instance. Deletes the object pointed to by \a decoder. - * - * \param decoder A pointer to an existing decoder. - * \assert - * \code decoder != NULL \endcode - */ -FLAC_API void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder); - - -/*********************************************************************** - * - * Public class method prototypes - * - ***********************************************************************/ - -/** Set the serial number for the FLAC stream within the Ogg container. - * The default behavior is to use the serial number of the first Ogg - * page. Setting a serial number here will explicitly specify which - * stream is to be decoded. - * - * \note - * This does not need to be set for native FLAC decoding. - * - * \default \c use serial number of first page - * \param decoder A decoder instance to set. - * \param serial_number See above. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_ogg_serial_number(FLAC__StreamDecoder *decoder, long serial_number); - -/** Set the "MD5 signature checking" flag. If \c true, the decoder will - * compute the MD5 signature of the unencoded audio data while decoding - * and compare it to the signature from the STREAMINFO block, if it - * exists, during FLAC__stream_decoder_finish(). - * - * MD5 signature checking will be turned off (until the next - * FLAC__stream_decoder_reset()) if there is no signature in the - * STREAMINFO block or when a seek is attempted. - * - * Clients that do not use the MD5 check should leave this off to speed - * up decoding. - * - * \default \c false - * \param decoder A decoder instance to set. - * \param value Flag value (see above). - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_md5_checking(FLAC__StreamDecoder *decoder, FLAC__bool value); - -/** Direct the decoder to pass on all metadata blocks of type \a type. - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \param type See above. - * \assert - * \code decoder != NULL \endcode - * \a type is valid - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond(FLAC__StreamDecoder *decoder, FLAC__MetadataType type); - -/** Direct the decoder to pass on all APPLICATION metadata blocks of the - * given \a id. - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \param id See above. - * \assert - * \code decoder != NULL \endcode - * \code id != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]); - -/** Direct the decoder to pass on all metadata blocks of any type. - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_all(FLAC__StreamDecoder *decoder); - -/** Direct the decoder to filter out all metadata blocks of type \a type. - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \param type See above. - * \assert - * \code decoder != NULL \endcode - * \a type is valid - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore(FLAC__StreamDecoder *decoder, FLAC__MetadataType type); - -/** Direct the decoder to filter out all APPLICATION metadata blocks of - * the given \a id. - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \param id See above. - * \assert - * \code decoder != NULL \endcode - * \code id != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]); - -/** Direct the decoder to filter out all metadata blocks of any type. - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_all(FLAC__StreamDecoder *decoder); - -/** Get the current decoder state. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__StreamDecoderState - * The current decoder state. - */ -FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__StreamDecoder *decoder); - -/** Get the current decoder state as a C string. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval const char * - * The decoder state as a C string. Do not modify the contents. - */ -FLAC_API const char *FLAC__stream_decoder_get_resolved_state_string(const FLAC__StreamDecoder *decoder); - -/** Get the "MD5 signature checking" flag. - * This is the value of the setting, not whether or not the decoder is - * currently checking the MD5 (remember, it can be turned off automatically - * by a seek). When the decoder is reset the flag will be restored to the - * value returned by this function. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * See above. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_get_md5_checking(const FLAC__StreamDecoder *decoder); - -/** Get the total number of samples in the stream being decoded. - * Will only be valid after decoding has started and will contain the - * value from the \c STREAMINFO block. A value of \c 0 means "unknown". - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval uint32_t - * See above. - */ -FLAC_API FLAC__uint64 FLAC__stream_decoder_get_total_samples(const FLAC__StreamDecoder *decoder); - -/** Get the current number of channels in the stream being decoded. - * Will only be valid after decoding has started and will contain the - * value from the most recently decoded frame header. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval uint32_t - * See above. - */ -FLAC_API uint32_t FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder); - -/** Get the current channel assignment in the stream being decoded. - * Will only be valid after decoding has started and will contain the - * value from the most recently decoded frame header. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__ChannelAssignment - * See above. - */ -FLAC_API FLAC__ChannelAssignment FLAC__stream_decoder_get_channel_assignment(const FLAC__StreamDecoder *decoder); - -/** Get the current sample resolution in the stream being decoded. - * Will only be valid after decoding has started and will contain the - * value from the most recently decoded frame header. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval uint32_t - * See above. - */ -FLAC_API uint32_t FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder); - -/** Get the current sample rate in Hz of the stream being decoded. - * Will only be valid after decoding has started and will contain the - * value from the most recently decoded frame header. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval uint32_t - * See above. - */ -FLAC_API uint32_t FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder); - -/** Get the current blocksize of the stream being decoded. - * Will only be valid after decoding has started and will contain the - * value from the most recently decoded frame header. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval uint32_t - * See above. - */ -FLAC_API uint32_t FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder); - -/** Returns the decoder's current read position within the stream. - * The position is the byte offset from the start of the stream. - * Bytes before this position have been fully decoded. Note that - * there may still be undecoded bytes in the decoder's read FIFO. - * The returned position is correct even after a seek. - * - * \warning This function currently only works for native FLAC, - * not Ogg FLAC streams. - * - * \param decoder A decoder instance to query. - * \param position Address at which to return the desired position. - * \assert - * \code decoder != NULL \endcode - * \code position != NULL \endcode - * \retval FLAC__bool - * \c true if successful, \c false if the stream is not native FLAC, - * or there was an error from the 'tell' callback or it returned - * \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_get_decode_position(const FLAC__StreamDecoder *decoder, FLAC__uint64 *position); - -/** Initialize the decoder instance to decode native FLAC streams. - * - * This flavor of initialization sets up the decoder to decode from a - * native FLAC stream. I/O is performed via callbacks to the client. - * For decoding from a plain file via filename or open FILE*, - * FLAC__stream_decoder_init_file() and FLAC__stream_decoder_init_FILE() - * provide a simpler interface. - * - * This function should be called after FLAC__stream_decoder_new() and - * FLAC__stream_decoder_set_*() but before any of the - * FLAC__stream_decoder_process_*() functions. Will set and return the - * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA - * if initialization succeeded. - * - * \param decoder An uninitialized decoder instance. - * \param read_callback See FLAC__StreamDecoderReadCallback. This - * pointer must not be \c NULL. - * \param seek_callback See FLAC__StreamDecoderSeekCallback. This - * pointer may be \c NULL if seeking is not - * supported. If \a seek_callback is not \c NULL then a - * \a tell_callback, \a length_callback, and \a eof_callback must also be supplied. - * Alternatively, a dummy seek callback that just - * returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED - * may also be supplied, all though this is slightly - * less efficient for the decoder. - * \param tell_callback See FLAC__StreamDecoderTellCallback. This - * pointer may be \c NULL if not supported by the client. If - * \a seek_callback is not \c NULL then a - * \a tell_callback must also be supplied. - * Alternatively, a dummy tell callback that just - * returns \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED - * may also be supplied, all though this is slightly - * less efficient for the decoder. - * \param length_callback See FLAC__StreamDecoderLengthCallback. This - * pointer may be \c NULL if not supported by the client. If - * \a seek_callback is not \c NULL then a - * \a length_callback must also be supplied. - * Alternatively, a dummy length callback that just - * returns \c FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED - * may also be supplied, all though this is slightly - * less efficient for the decoder. - * \param eof_callback See FLAC__StreamDecoderEofCallback. This - * pointer may be \c NULL if not supported by the client. If - * \a seek_callback is not \c NULL then a - * \a eof_callback must also be supplied. - * Alternatively, a dummy length callback that just - * returns \c false - * may also be supplied, all though this is slightly - * less efficient for the decoder. - * \param write_callback See FLAC__StreamDecoderWriteCallback. This - * pointer must not be \c NULL. - * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This - * pointer may be \c NULL if the callback is not - * desired. - * \param error_callback See FLAC__StreamDecoderErrorCallback. This - * pointer must not be \c NULL. - * \param client_data This value will be supplied to callbacks in their - * \a client_data argument. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__StreamDecoderInitStatus - * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; - * see FLAC__StreamDecoderInitStatus for the meanings of other return values. - */ -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_stream( - FLAC__StreamDecoder *decoder, - FLAC__StreamDecoderReadCallback read_callback, - FLAC__StreamDecoderSeekCallback seek_callback, - FLAC__StreamDecoderTellCallback tell_callback, - FLAC__StreamDecoderLengthCallback length_callback, - FLAC__StreamDecoderEofCallback eof_callback, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -); - -/** Initialize the decoder instance to decode Ogg FLAC streams. - * - * This flavor of initialization sets up the decoder to decode from a - * FLAC stream in an Ogg container. I/O is performed via callbacks to the - * client. For decoding from a plain file via filename or open FILE*, - * FLAC__stream_decoder_init_ogg_file() and FLAC__stream_decoder_init_ogg_FILE() - * provide a simpler interface. - * - * This function should be called after FLAC__stream_decoder_new() and - * FLAC__stream_decoder_set_*() but before any of the - * FLAC__stream_decoder_process_*() functions. Will set and return the - * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA - * if initialization succeeded. - * - * \note Support for Ogg FLAC in the library is optional. If this - * library has been built without support for Ogg FLAC, this function - * will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER. - * - * \param decoder An uninitialized decoder instance. - * \param read_callback See FLAC__StreamDecoderReadCallback. This - * pointer must not be \c NULL. - * \param seek_callback See FLAC__StreamDecoderSeekCallback. This - * pointer may be \c NULL if seeking is not - * supported. If \a seek_callback is not \c NULL then a - * \a tell_callback, \a length_callback, and \a eof_callback must also be supplied. - * Alternatively, a dummy seek callback that just - * returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED - * may also be supplied, all though this is slightly - * less efficient for the decoder. - * \param tell_callback See FLAC__StreamDecoderTellCallback. This - * pointer may be \c NULL if not supported by the client. If - * \a seek_callback is not \c NULL then a - * \a tell_callback must also be supplied. - * Alternatively, a dummy tell callback that just - * returns \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED - * may also be supplied, all though this is slightly - * less efficient for the decoder. - * \param length_callback See FLAC__StreamDecoderLengthCallback. This - * pointer may be \c NULL if not supported by the client. If - * \a seek_callback is not \c NULL then a - * \a length_callback must also be supplied. - * Alternatively, a dummy length callback that just - * returns \c FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED - * may also be supplied, all though this is slightly - * less efficient for the decoder. - * \param eof_callback See FLAC__StreamDecoderEofCallback. This - * pointer may be \c NULL if not supported by the client. If - * \a seek_callback is not \c NULL then a - * \a eof_callback must also be supplied. - * Alternatively, a dummy length callback that just - * returns \c false - * may also be supplied, all though this is slightly - * less efficient for the decoder. - * \param write_callback See FLAC__StreamDecoderWriteCallback. This - * pointer must not be \c NULL. - * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This - * pointer may be \c NULL if the callback is not - * desired. - * \param error_callback See FLAC__StreamDecoderErrorCallback. This - * pointer must not be \c NULL. - * \param client_data This value will be supplied to callbacks in their - * \a client_data argument. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__StreamDecoderInitStatus - * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; - * see FLAC__StreamDecoderInitStatus for the meanings of other return values. - */ -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_stream( - FLAC__StreamDecoder *decoder, - FLAC__StreamDecoderReadCallback read_callback, - FLAC__StreamDecoderSeekCallback seek_callback, - FLAC__StreamDecoderTellCallback tell_callback, - FLAC__StreamDecoderLengthCallback length_callback, - FLAC__StreamDecoderEofCallback eof_callback, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -); - -/** Initialize the decoder instance to decode native FLAC files. - * - * This flavor of initialization sets up the decoder to decode from a - * plain native FLAC file. For non-stdio streams, you must use - * FLAC__stream_decoder_init_stream() and provide callbacks for the I/O. - * - * This function should be called after FLAC__stream_decoder_new() and - * FLAC__stream_decoder_set_*() but before any of the - * FLAC__stream_decoder_process_*() functions. Will set and return the - * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA - * if initialization succeeded. - * - * \param decoder An uninitialized decoder instance. - * \param file An open FLAC file. The file should have been - * opened with mode \c "rb" and rewound. The file - * becomes owned by the decoder and should not be - * manipulated by the client while decoding. - * Unless \a file is \c stdin, it will be closed - * when FLAC__stream_decoder_finish() is called. - * Note however that seeking will not work when - * decoding from \c stdin since it is not seekable. - * \param write_callback See FLAC__StreamDecoderWriteCallback. This - * pointer must not be \c NULL. - * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This - * pointer may be \c NULL if the callback is not - * desired. - * \param error_callback See FLAC__StreamDecoderErrorCallback. This - * pointer must not be \c NULL. - * \param client_data This value will be supplied to callbacks in their - * \a client_data argument. - * \assert - * \code decoder != NULL \endcode - * \code file != NULL \endcode - * \retval FLAC__StreamDecoderInitStatus - * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; - * see FLAC__StreamDecoderInitStatus for the meanings of other return values. - */ -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_FILE( - FLAC__StreamDecoder *decoder, - FILE *file, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -); - -/** Initialize the decoder instance to decode Ogg FLAC files. - * - * This flavor of initialization sets up the decoder to decode from a - * plain Ogg FLAC file. For non-stdio streams, you must use - * FLAC__stream_decoder_init_ogg_stream() and provide callbacks for the I/O. - * - * This function should be called after FLAC__stream_decoder_new() and - * FLAC__stream_decoder_set_*() but before any of the - * FLAC__stream_decoder_process_*() functions. Will set and return the - * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA - * if initialization succeeded. - * - * \note Support for Ogg FLAC in the library is optional. If this - * library has been built without support for Ogg FLAC, this function - * will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER. - * - * \param decoder An uninitialized decoder instance. - * \param file An open FLAC file. The file should have been - * opened with mode \c "rb" and rewound. The file - * becomes owned by the decoder and should not be - * manipulated by the client while decoding. - * Unless \a file is \c stdin, it will be closed - * when FLAC__stream_decoder_finish() is called. - * Note however that seeking will not work when - * decoding from \c stdin since it is not seekable. - * \param write_callback See FLAC__StreamDecoderWriteCallback. This - * pointer must not be \c NULL. - * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This - * pointer may be \c NULL if the callback is not - * desired. - * \param error_callback See FLAC__StreamDecoderErrorCallback. This - * pointer must not be \c NULL. - * \param client_data This value will be supplied to callbacks in their - * \a client_data argument. - * \assert - * \code decoder != NULL \endcode - * \code file != NULL \endcode - * \retval FLAC__StreamDecoderInitStatus - * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; - * see FLAC__StreamDecoderInitStatus for the meanings of other return values. - */ -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_FILE( - FLAC__StreamDecoder *decoder, - FILE *file, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -); - -/** Initialize the decoder instance to decode native FLAC files. - * - * This flavor of initialization sets up the decoder to decode from a plain - * native FLAC file. If POSIX fopen() semantics are not sufficient, (for - * example, with Unicode filenames on Windows), you must use - * FLAC__stream_decoder_init_FILE(), or FLAC__stream_decoder_init_stream() - * and provide callbacks for the I/O. - * - * This function should be called after FLAC__stream_decoder_new() and - * FLAC__stream_decoder_set_*() but before any of the - * FLAC__stream_decoder_process_*() functions. Will set and return the - * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA - * if initialization succeeded. - * - * \param decoder An uninitialized decoder instance. - * \param filename The name of the file to decode from. The file will - * be opened with fopen(). Use \c NULL to decode from - * \c stdin. Note that \c stdin is not seekable. - * \param write_callback See FLAC__StreamDecoderWriteCallback. This - * pointer must not be \c NULL. - * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This - * pointer may be \c NULL if the callback is not - * desired. - * \param error_callback See FLAC__StreamDecoderErrorCallback. This - * pointer must not be \c NULL. - * \param client_data This value will be supplied to callbacks in their - * \a client_data argument. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__StreamDecoderInitStatus - * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; - * see FLAC__StreamDecoderInitStatus for the meanings of other return values. - */ -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_file( - FLAC__StreamDecoder *decoder, - const char *filename, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -); - -/** Initialize the decoder instance to decode Ogg FLAC files. - * - * This flavor of initialization sets up the decoder to decode from a plain - * Ogg FLAC file. If POSIX fopen() semantics are not sufficient, (for - * example, with Unicode filenames on Windows), you must use - * FLAC__stream_decoder_init_ogg_FILE(), or FLAC__stream_decoder_init_ogg_stream() - * and provide callbacks for the I/O. - * - * This function should be called after FLAC__stream_decoder_new() and - * FLAC__stream_decoder_set_*() but before any of the - * FLAC__stream_decoder_process_*() functions. Will set and return the - * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA - * if initialization succeeded. - * - * \note Support for Ogg FLAC in the library is optional. If this - * library has been built without support for Ogg FLAC, this function - * will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER. - * - * \param decoder An uninitialized decoder instance. - * \param filename The name of the file to decode from. The file will - * be opened with fopen(). Use \c NULL to decode from - * \c stdin. Note that \c stdin is not seekable. - * \param write_callback See FLAC__StreamDecoderWriteCallback. This - * pointer must not be \c NULL. - * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This - * pointer may be \c NULL if the callback is not - * desired. - * \param error_callback See FLAC__StreamDecoderErrorCallback. This - * pointer must not be \c NULL. - * \param client_data This value will be supplied to callbacks in their - * \a client_data argument. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__StreamDecoderInitStatus - * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; - * see FLAC__StreamDecoderInitStatus for the meanings of other return values. - */ -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_file( - FLAC__StreamDecoder *decoder, - const char *filename, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -); - -/** Finish the decoding process. - * Flushes the decoding buffer, releases resources, resets the decoder - * settings to their defaults, and returns the decoder state to - * FLAC__STREAM_DECODER_UNINITIALIZED. - * - * In the event of a prematurely-terminated decode, it is not strictly - * necessary to call this immediately before FLAC__stream_decoder_delete() - * but it is good practice to match every FLAC__stream_decoder_init_*() - * with a FLAC__stream_decoder_finish(). - * - * \param decoder An uninitialized decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if MD5 checking is on AND a STREAMINFO block was available - * AND the MD5 signature in the STREAMINFO block was non-zero AND the - * signature does not match the one computed by the decoder; else - * \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder); - -/** Flush the stream input. - * The decoder's input buffer will be cleared and the state set to - * \c FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC. This will also turn - * off MD5 checking. - * - * \param decoder A decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c true if successful, else \c false if a memory allocation - * error occurs (in which case the state will be set to - * \c FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR). - */ -FLAC_API FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder); - -/** Reset the decoding process. - * The decoder's input buffer will be cleared and the state set to - * \c FLAC__STREAM_DECODER_SEARCH_FOR_METADATA. This is similar to - * FLAC__stream_decoder_finish() except that the settings are - * preserved; there is no need to call FLAC__stream_decoder_init_*() - * before decoding again. MD5 checking will be restored to its original - * setting. - * - * If the decoder is seekable, or was initialized with - * FLAC__stream_decoder_init*_FILE() or FLAC__stream_decoder_init*_file(), - * the decoder will also attempt to seek to the beginning of the file. - * If this rewind fails, this function will return \c false. It follows - * that FLAC__stream_decoder_reset() cannot be used when decoding from - * \c stdin. - * - * If the decoder was initialized with FLAC__stream_encoder_init*_stream() - * and is not seekable (i.e. no seek callback was provided or the seek - * callback returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED), it - * is the duty of the client to start feeding data from the beginning of - * the stream on the next FLAC__stream_decoder_process_*() call. - * - * \param decoder A decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c true if successful, else \c false if a memory allocation occurs - * (in which case the state will be set to - * \c FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR) or a seek error - * occurs (the state will be unchanged). - */ -FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder); - -/** Decode one metadata block or audio frame. - * This version instructs the decoder to decode a either a single metadata - * block or a single frame and stop, unless the callbacks return a fatal - * error or the read callback returns - * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM. - * - * As the decoder needs more input it will call the read callback. - * Depending on what was decoded, the metadata or write callback will be - * called with the decoded metadata block or audio frame. - * - * Unless there is a fatal read error or end of stream, this function - * will return once one whole frame is decoded. In other words, if the - * stream is not synchronized or points to a corrupt frame header, the - * decoder will continue to try and resync until it gets to a valid - * frame, then decode one frame, then return. If the decoder points to - * a frame whose frame CRC in the frame footer does not match the - * computed frame CRC, this function will issue a - * FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH error to the - * error callback, and return, having decoded one complete, although - * corrupt, frame. (Such corrupted frames are sent as silence of the - * correct length to the write callback.) - * - * \param decoder An initialized decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if any fatal read, write, or memory allocation error - * occurred (meaning decoding must stop), else \c true; for more - * information about the decoder, check the decoder state with - * FLAC__stream_decoder_get_state(). - */ -FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *decoder); - -/** Decode until the end of the metadata. - * This version instructs the decoder to decode from the current position - * and continue until all the metadata has been read, or until the - * callbacks return a fatal error or the read callback returns - * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM. - * - * As the decoder needs more input it will call the read callback. - * As each metadata block is decoded, the metadata callback will be called - * with the decoded metadata. - * - * \param decoder An initialized decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if any fatal read, write, or memory allocation error - * occurred (meaning decoding must stop), else \c true; for more - * information about the decoder, check the decoder state with - * FLAC__stream_decoder_get_state(). - */ -FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__StreamDecoder *decoder); - -/** Decode until the end of the stream. - * This version instructs the decoder to decode from the current position - * and continue until the end of stream (the read callback returns - * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM), or until the - * callbacks return a fatal error. - * - * As the decoder needs more input it will call the read callback. - * As each metadata block and frame is decoded, the metadata or write - * callback will be called with the decoded metadata or frame. - * - * \param decoder An initialized decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if any fatal read, write, or memory allocation error - * occurred (meaning decoding must stop), else \c true; for more - * information about the decoder, check the decoder state with - * FLAC__stream_decoder_get_state(). - */ -FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder); - -/** Skip one audio frame. - * This version instructs the decoder to 'skip' a single frame and stop, - * unless the callbacks return a fatal error or the read callback returns - * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM. - * - * The decoding flow is the same as what occurs when - * FLAC__stream_decoder_process_single() is called to process an audio - * frame, except that this function does not decode the parsed data into - * PCM or call the write callback. The integrity of the frame is still - * checked the same way as in the other process functions. - * - * This function will return once one whole frame is skipped, in the - * same way that FLAC__stream_decoder_process_single() will return once - * one whole frame is decoded. - * - * This function can be used in more quickly determining FLAC frame - * boundaries when decoding of the actual data is not needed, for - * example when an application is separating a FLAC stream into frames - * for editing or storing in a container. To do this, the application - * can use FLAC__stream_decoder_skip_single_frame() to quickly advance - * to the next frame, then use - * FLAC__stream_decoder_get_decode_position() to find the new frame - * boundary. - * - * This function should only be called when the stream has advanced - * past all the metadata, otherwise it will return \c false. - * - * \param decoder An initialized decoder instance not in a metadata - * state. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if any fatal read, write, or memory allocation error - * occurred (meaning decoding must stop), or if the decoder - * is in the FLAC__STREAM_DECODER_SEARCH_FOR_METADATA or - * FLAC__STREAM_DECODER_READ_METADATA state, else \c true; for more - * information about the decoder, check the decoder state with - * FLAC__stream_decoder_get_state(). - */ -FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder *decoder); - -/** Flush the input and seek to an absolute sample. - * Decoding will resume at the given sample. Note that because of - * this, the next write callback may contain a partial block. The - * client must support seeking the input or this function will fail - * and return \c false. Furthermore, if the decoder state is - * \c FLAC__STREAM_DECODER_SEEK_ERROR, then the decoder must be flushed - * with FLAC__stream_decoder_flush() or reset with - * FLAC__stream_decoder_reset() before decoding can continue. - * - * \param decoder A decoder instance. - * \param sample The target sample number to seek to. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c true if successful, else \c false. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_seek_absolute(FLAC__StreamDecoder *decoder, FLAC__uint64 sample); - -/* \} */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/flac/include/FLAC/stream_encoder.h b/lib/flac/include/FLAC/stream_encoder.h deleted file mode 100644 index d154ac4..0000000 --- a/lib/flac/include/FLAC/stream_encoder.h +++ /dev/null @@ -1,1790 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__STREAM_ENCODER_H -#define FLAC__STREAM_ENCODER_H - -#include /* for FILE */ -#include "export.h" -#include "format.h" -#include "stream_decoder.h" - -#ifdef __cplusplus -extern "C" { -#endif - - -/** \file include/FLAC/stream_encoder.h - * - * \brief - * This module contains the functions which implement the stream - * encoder. - * - * See the detailed documentation in the - * \link flac_stream_encoder stream encoder \endlink module. - */ - -/** \defgroup flac_encoder FLAC/ \*_encoder.h: encoder interfaces - * \ingroup flac - * - * \brief - * This module describes the encoder layers provided by libFLAC. - * - * The stream encoder can be used to encode complete streams either to the - * client via callbacks, or directly to a file, depending on how it is - * initialized. When encoding via callbacks, the client provides a write - * callback which will be called whenever FLAC data is ready to be written. - * If the client also supplies a seek callback, the encoder will also - * automatically handle the writing back of metadata discovered while - * encoding, like stream info, seek points offsets, etc. When encoding to - * a file, the client needs only supply a filename or open \c FILE* and an - * optional progress callback for periodic notification of progress; the - * write and seek callbacks are supplied internally. For more info see the - * \link flac_stream_encoder stream encoder \endlink module. - */ - -/** \defgroup flac_stream_encoder FLAC/stream_encoder.h: stream encoder interface - * \ingroup flac_encoder - * - * \brief - * This module contains the functions which implement the stream - * encoder. - * - * The stream encoder can encode to native FLAC, and optionally Ogg FLAC - * (check FLAC_API_SUPPORTS_OGG_FLAC) streams and files. - * - * The basic usage of this encoder is as follows: - * - The program creates an instance of an encoder using - * FLAC__stream_encoder_new(). - * - The program overrides the default settings using - * FLAC__stream_encoder_set_*() functions. At a minimum, the following - * functions should be called: - * - FLAC__stream_encoder_set_channels() - * - FLAC__stream_encoder_set_bits_per_sample() - * - FLAC__stream_encoder_set_sample_rate() - * - FLAC__stream_encoder_set_ogg_serial_number() (if encoding to Ogg FLAC) - * - FLAC__stream_encoder_set_total_samples_estimate() (if known) - * - If the application wants to control the compression level or set its own - * metadata, then the following should also be called: - * - FLAC__stream_encoder_set_compression_level() - * - FLAC__stream_encoder_set_verify() - * - FLAC__stream_encoder_set_metadata() - * - The rest of the set functions should only be called if the client needs - * exact control over how the audio is compressed; thorough understanding - * of the FLAC format is necessary to achieve good results. - * - The program initializes the instance to validate the settings and - * prepare for encoding using - * - FLAC__stream_encoder_init_stream() or FLAC__stream_encoder_init_FILE() - * or FLAC__stream_encoder_init_file() for native FLAC - * - FLAC__stream_encoder_init_ogg_stream() or FLAC__stream_encoder_init_ogg_FILE() - * or FLAC__stream_encoder_init_ogg_file() for Ogg FLAC - * - The program calls FLAC__stream_encoder_process() or - * FLAC__stream_encoder_process_interleaved() to encode data, which - * subsequently calls the callbacks when there is encoder data ready - * to be written. - * - The program finishes the encoding with FLAC__stream_encoder_finish(), - * which causes the encoder to encode any data still in its input pipe, - * update the metadata with the final encoding statistics if output - * seeking is possible, and finally reset the encoder to the - * uninitialized state. - * - The instance may be used again or deleted with - * FLAC__stream_encoder_delete(). - * - * In more detail, the stream encoder functions similarly to the - * \link flac_stream_decoder stream decoder \endlink, but has fewer - * callbacks and more options. Typically the client will create a new - * instance by calling FLAC__stream_encoder_new(), then set the necessary - * parameters with FLAC__stream_encoder_set_*(), and initialize it by - * calling one of the FLAC__stream_encoder_init_*() functions. - * - * Unlike the decoders, the stream encoder has many options that can - * affect the speed and compression ratio. When setting these parameters - * you should have some basic knowledge of the format (see the - * user-level documentation - * or the formal description). The - * FLAC__stream_encoder_set_*() functions themselves do not validate the - * values as many are interdependent. The FLAC__stream_encoder_init_*() - * functions will do this, so make sure to pay attention to the state - * returned by FLAC__stream_encoder_init_*() to make sure that it is - * FLAC__STREAM_ENCODER_INIT_STATUS_OK. Any parameters that are not set - * before FLAC__stream_encoder_init_*() will take on the defaults from - * the constructor. - * - * There are three initialization functions for native FLAC, one for - * setting up the encoder to encode FLAC data to the client via - * callbacks, and two for encoding directly to a file. - * - * For encoding via callbacks, use FLAC__stream_encoder_init_stream(). - * You must also supply a write callback which will be called anytime - * there is raw encoded data to write. If the client can seek the output - * it is best to also supply seek and tell callbacks, as this allows the - * encoder to go back after encoding is finished to write back - * information that was collected while encoding, like seek point offsets, - * frame sizes, etc. - * - * For encoding directly to a file, use FLAC__stream_encoder_init_FILE() - * or FLAC__stream_encoder_init_file(). Then you must only supply a - * filename or open \c FILE*; the encoder will handle all the callbacks - * internally. You may also supply a progress callback for periodic - * notification of the encoding progress. - * - * There are three similarly-named init functions for encoding to Ogg - * FLAC streams. Check \c FLAC_API_SUPPORTS_OGG_FLAC to find out if the - * library has been built with Ogg support. - * - * The call to FLAC__stream_encoder_init_*() currently will also immediately - * call the write callback several times, once with the \c fLaC signature, - * and once for each encoded metadata block. Note that for Ogg FLAC - * encoding you will usually get at least twice the number of callbacks than - * with native FLAC, one for the Ogg page header and one for the page body. - * - * After initializing the instance, the client may feed audio data to the - * encoder in one of two ways: - * - * - Channel separate, through FLAC__stream_encoder_process() - The client - * will pass an array of pointers to buffers, one for each channel, to - * the encoder, each of the same length. The samples need not be - * block-aligned, but each channel should have the same number of samples. - * - Channel interleaved, through - * FLAC__stream_encoder_process_interleaved() - The client will pass a single - * pointer to data that is channel-interleaved (i.e. channel0_sample0, - * channel1_sample0, ... , channelN_sample0, channel0_sample1, ...). - * Again, the samples need not be block-aligned but they must be - * sample-aligned, i.e. the first value should be channel0_sample0 and - * the last value channelN_sampleM. - * - * Note that for either process call, each sample in the buffers should be a - * signed integer, right-justified to the resolution set by - * FLAC__stream_encoder_set_bits_per_sample(). For example, if the resolution - * is 16 bits per sample, the samples should all be in the range [-32768,32767]. - * - * When the client is finished encoding data, it calls - * FLAC__stream_encoder_finish(), which causes the encoder to encode any - * data still in its input pipe, and call the metadata callback with the - * final encoding statistics. Then the instance may be deleted with - * FLAC__stream_encoder_delete() or initialized again to encode another - * stream. - * - * For programs that write their own metadata, but that do not know the - * actual metadata until after encoding, it is advantageous to instruct - * the encoder to write a PADDING block of the correct size, so that - * instead of rewriting the whole stream after encoding, the program can - * just overwrite the PADDING block. If only the maximum size of the - * metadata is known, the program can write a slightly larger padding - * block, then split it after encoding. - * - * Make sure you understand how lengths are calculated. All FLAC metadata - * blocks have a 4 byte header which contains the type and length. This - * length does not include the 4 bytes of the header. See the format page - * for the specification of metadata blocks and their lengths. - * - * \note - * If you are writing the FLAC data to a file via callbacks, make sure it - * is open for update (e.g. mode "w+" for stdio streams). This is because - * after the first encoding pass, the encoder will try to seek back to the - * beginning of the stream, to the STREAMINFO block, to write some data - * there. (If using FLAC__stream_encoder_init*_file() or - * FLAC__stream_encoder_init*_FILE(), the file is managed internally.) - * - * \note - * The "set" functions may only be called when the encoder is in the - * state FLAC__STREAM_ENCODER_UNINITIALIZED, i.e. after - * FLAC__stream_encoder_new() or FLAC__stream_encoder_finish(), but - * before FLAC__stream_encoder_init_*(). If this is the case they will - * return \c true, otherwise \c false. - * - * \note - * FLAC__stream_encoder_finish() resets all settings to the constructor - * defaults. - * - * \{ - */ - - -/** State values for a FLAC__StreamEncoder. - * - * The encoder's state can be obtained by calling FLAC__stream_encoder_get_state(). - * - * If the encoder gets into any other state besides \c FLAC__STREAM_ENCODER_OK - * or \c FLAC__STREAM_ENCODER_UNINITIALIZED, it becomes invalid for encoding and - * must be deleted with FLAC__stream_encoder_delete(). - */ -typedef enum { - - FLAC__STREAM_ENCODER_OK = 0, - /**< The encoder is in the normal OK state and samples can be processed. */ - - FLAC__STREAM_ENCODER_UNINITIALIZED, - /**< The encoder is in the uninitialized state; one of the - * FLAC__stream_encoder_init_*() functions must be called before samples - * can be processed. - */ - - FLAC__STREAM_ENCODER_OGG_ERROR, - /**< An error occurred in the underlying Ogg layer. */ - - FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR, - /**< An error occurred in the underlying verify stream decoder; - * check FLAC__stream_encoder_get_verify_decoder_state(). - */ - - FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA, - /**< The verify decoder detected a mismatch between the original - * audio signal and the decoded audio signal. - */ - - FLAC__STREAM_ENCODER_CLIENT_ERROR, - /**< One of the callbacks returned a fatal error. */ - - FLAC__STREAM_ENCODER_IO_ERROR, - /**< An I/O error occurred while opening/reading/writing a file. - * Check \c errno. - */ - - FLAC__STREAM_ENCODER_FRAMING_ERROR, - /**< An error occurred while writing the stream; usually, the - * write_callback returned an error. - */ - - FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR - /**< Memory allocation failed. */ - -} FLAC__StreamEncoderState; - -/** Maps a FLAC__StreamEncoderState to a C string. - * - * Using a FLAC__StreamEncoderState as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamEncoderStateString[]; - - -/** Possible return values for the FLAC__stream_encoder_init_*() functions. - */ -typedef enum { - - FLAC__STREAM_ENCODER_INIT_STATUS_OK = 0, - /**< Initialization was successful. */ - - FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR, - /**< General failure to set up encoder; call FLAC__stream_encoder_get_state() for cause. */ - - FLAC__STREAM_ENCODER_INIT_STATUS_UNSUPPORTED_CONTAINER, - /**< The library was not compiled with support for the given container - * format. - */ - - FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_CALLBACKS, - /**< A required callback was not supplied. */ - - FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_NUMBER_OF_CHANNELS, - /**< The encoder has an invalid setting for number of channels. */ - - FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BITS_PER_SAMPLE, - /**< The encoder has an invalid setting for bits-per-sample. - * FLAC supports 4-32 bps but the reference encoder currently supports - * only up to 24 bps. - */ - - FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_SAMPLE_RATE, - /**< The encoder has an invalid setting for the input sample rate. */ - - FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BLOCK_SIZE, - /**< The encoder has an invalid setting for the block size. */ - - FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_MAX_LPC_ORDER, - /**< The encoder has an invalid setting for the maximum LPC order. */ - - FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_QLP_COEFF_PRECISION, - /**< The encoder has an invalid setting for the precision of the quantized linear predictor coefficients. */ - - FLAC__STREAM_ENCODER_INIT_STATUS_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER, - /**< The specified block size is less than the maximum LPC order. */ - - FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE, - /**< The encoder is bound to the Subset but other settings violate it. */ - - FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA, - /**< The metadata input to the encoder is invalid, in one of the following ways: - * - FLAC__stream_encoder_set_metadata() was called with a null pointer but a block count > 0 - * - One of the metadata blocks contains an undefined type - * - It contains an illegal CUESHEET as checked by FLAC__format_cuesheet_is_legal() - * - It contains an illegal SEEKTABLE as checked by FLAC__format_seektable_is_legal() - * - It contains more than one SEEKTABLE block or more than one VORBIS_COMMENT block - */ - - FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED - /**< FLAC__stream_encoder_init_*() was called when the encoder was - * already initialized, usually because - * FLAC__stream_encoder_finish() was not called. - */ - -} FLAC__StreamEncoderInitStatus; - -/** Maps a FLAC__StreamEncoderInitStatus to a C string. - * - * Using a FLAC__StreamEncoderInitStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamEncoderInitStatusString[]; - - -/** Return values for the FLAC__StreamEncoder read callback. - */ -typedef enum { - - FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE, - /**< The read was OK and decoding can continue. */ - - FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM, - /**< The read was attempted at the end of the stream. */ - - FLAC__STREAM_ENCODER_READ_STATUS_ABORT, - /**< An unrecoverable error occurred. */ - - FLAC__STREAM_ENCODER_READ_STATUS_UNSUPPORTED - /**< Client does not support reading back from the output. */ - -} FLAC__StreamEncoderReadStatus; - -/** Maps a FLAC__StreamEncoderReadStatus to a C string. - * - * Using a FLAC__StreamEncoderReadStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamEncoderReadStatusString[]; - - -/** Return values for the FLAC__StreamEncoder write callback. - */ -typedef enum { - - FLAC__STREAM_ENCODER_WRITE_STATUS_OK = 0, - /**< The write was OK and encoding can continue. */ - - FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR - /**< An unrecoverable error occurred. The encoder will return from the process call. */ - -} FLAC__StreamEncoderWriteStatus; - -/** Maps a FLAC__StreamEncoderWriteStatus to a C string. - * - * Using a FLAC__StreamEncoderWriteStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamEncoderWriteStatusString[]; - - -/** Return values for the FLAC__StreamEncoder seek callback. - */ -typedef enum { - - FLAC__STREAM_ENCODER_SEEK_STATUS_OK, - /**< The seek was OK and encoding can continue. */ - - FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR, - /**< An unrecoverable error occurred. */ - - FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED - /**< Client does not support seeking. */ - -} FLAC__StreamEncoderSeekStatus; - -/** Maps a FLAC__StreamEncoderSeekStatus to a C string. - * - * Using a FLAC__StreamEncoderSeekStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamEncoderSeekStatusString[]; - - -/** Return values for the FLAC__StreamEncoder tell callback. - */ -typedef enum { - - FLAC__STREAM_ENCODER_TELL_STATUS_OK, - /**< The tell was OK and encoding can continue. */ - - FLAC__STREAM_ENCODER_TELL_STATUS_ERROR, - /**< An unrecoverable error occurred. */ - - FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED - /**< Client does not support seeking. */ - -} FLAC__StreamEncoderTellStatus; - -/** Maps a FLAC__StreamEncoderTellStatus to a C string. - * - * Using a FLAC__StreamEncoderTellStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamEncoderTellStatusString[]; - - -/*********************************************************************** - * - * class FLAC__StreamEncoder - * - ***********************************************************************/ - -struct FLAC__StreamEncoderProtected; -struct FLAC__StreamEncoderPrivate; -/** The opaque structure definition for the stream encoder type. - * See the \link flac_stream_encoder stream encoder module \endlink - * for a detailed description. - */ -typedef struct { - struct FLAC__StreamEncoderProtected *protected_; /* avoid the C++ keyword 'protected' */ - struct FLAC__StreamEncoderPrivate *private_; /* avoid the C++ keyword 'private' */ -} FLAC__StreamEncoder; - -/** Signature for the read callback. - * - * A function pointer matching this signature must be passed to - * FLAC__stream_encoder_init_ogg_stream() if seeking is supported. - * The supplied function will be called when the encoder needs to read back - * encoded data. This happens during the metadata callback, when the encoder - * has to read, modify, and rewrite the metadata (e.g. seekpoints) gathered - * while encoding. The address of the buffer to be filled is supplied, along - * with the number of bytes the buffer can hold. The callback may choose to - * supply less data and modify the byte count but must be careful not to - * overflow the buffer. The callback then returns a status code chosen from - * FLAC__StreamEncoderReadStatus. - * - * Here is an example of a read callback for stdio streams: - * \code - * FLAC__StreamEncoderReadStatus read_cb(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data) - * { - * FILE *file = ((MyClientData*)client_data)->file; - * if(*bytes > 0) { - * *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, file); - * if(ferror(file)) - * return FLAC__STREAM_ENCODER_READ_STATUS_ABORT; - * else if(*bytes == 0) - * return FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM; - * else - * return FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE; - * } - * else - * return FLAC__STREAM_ENCODER_READ_STATUS_ABORT; - * } - * \endcode - * - * \note In general, FLAC__StreamEncoder functions which change the - * state should not be called on the \a encoder while in the callback. - * - * \param encoder The encoder instance calling the callback. - * \param buffer A pointer to a location for the callee to store - * data to be encoded. - * \param bytes A pointer to the size of the buffer. On entry - * to the callback, it contains the maximum number - * of bytes that may be stored in \a buffer. The - * callee must set it to the actual number of bytes - * stored (0 in case of error or end-of-stream) before - * returning. - * \param client_data The callee's client data set through - * FLAC__stream_encoder_set_client_data(). - * \retval FLAC__StreamEncoderReadStatus - * The callee's return status. - */ -typedef FLAC__StreamEncoderReadStatus (*FLAC__StreamEncoderReadCallback)(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data); - -/** Signature for the write callback. - * - * A function pointer matching this signature must be passed to - * FLAC__stream_encoder_init*_stream(). The supplied function will be called - * by the encoder anytime there is raw encoded data ready to write. It may - * include metadata mixed with encoded audio frames and the data is not - * guaranteed to be aligned on frame or metadata block boundaries. - * - * The only duty of the callback is to write out the \a bytes worth of data - * in \a buffer to the current position in the output stream. The arguments - * \a samples and \a current_frame are purely informational. If \a samples - * is greater than \c 0, then \a current_frame will hold the current frame - * number that is being written; otherwise it indicates that the write - * callback is being called to write metadata. - * - * \note - * Unlike when writing to native FLAC, when writing to Ogg FLAC the - * write callback will be called twice when writing each audio - * frame; once for the page header, and once for the page body. - * When writing the page header, the \a samples argument to the - * write callback will be \c 0. - * - * \note In general, FLAC__StreamEncoder functions which change the - * state should not be called on the \a encoder while in the callback. - * - * \param encoder The encoder instance calling the callback. - * \param buffer An array of encoded data of length \a bytes. - * \param bytes The byte length of \a buffer. - * \param samples The number of samples encoded by \a buffer. - * \c 0 has a special meaning; see above. - * \param current_frame The number of the current frame being encoded. - * \param client_data The callee's client data set through - * FLAC__stream_encoder_init_*(). - * \retval FLAC__StreamEncoderWriteStatus - * The callee's return status. - */ -typedef FLAC__StreamEncoderWriteStatus (*FLAC__StreamEncoderWriteCallback)(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, void *client_data); - -/** Signature for the seek callback. - * - * A function pointer matching this signature may be passed to - * FLAC__stream_encoder_init*_stream(). The supplied function will be called - * when the encoder needs to seek the output stream. The encoder will pass - * the absolute byte offset to seek to, 0 meaning the beginning of the stream. - * - * Here is an example of a seek callback for stdio streams: - * \code - * FLAC__StreamEncoderSeekStatus seek_cb(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data) - * { - * FILE *file = ((MyClientData*)client_data)->file; - * if(file == stdin) - * return FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED; - * else if(fseeko(file, (off_t)absolute_byte_offset, SEEK_SET) < 0) - * return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR; - * else - * return FLAC__STREAM_ENCODER_SEEK_STATUS_OK; - * } - * \endcode - * - * \note In general, FLAC__StreamEncoder functions which change the - * state should not be called on the \a encoder while in the callback. - * - * \param encoder The encoder instance calling the callback. - * \param absolute_byte_offset The offset from the beginning of the stream - * to seek to. - * \param client_data The callee's client data set through - * FLAC__stream_encoder_init_*(). - * \retval FLAC__StreamEncoderSeekStatus - * The callee's return status. - */ -typedef FLAC__StreamEncoderSeekStatus (*FLAC__StreamEncoderSeekCallback)(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data); - -/** Signature for the tell callback. - * - * A function pointer matching this signature may be passed to - * FLAC__stream_encoder_init*_stream(). The supplied function will be called - * when the encoder needs to know the current position of the output stream. - * - * \warning - * The callback must return the true current byte offset of the output to - * which the encoder is writing. If you are buffering the output, make - * sure and take this into account. If you are writing directly to a - * FILE* from your write callback, ftell() is sufficient. If you are - * writing directly to a file descriptor from your write callback, you - * can use lseek(fd, SEEK_CUR, 0). The encoder may later seek back to - * these points to rewrite metadata after encoding. - * - * Here is an example of a tell callback for stdio streams: - * \code - * FLAC__StreamEncoderTellStatus tell_cb(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data) - * { - * FILE *file = ((MyClientData*)client_data)->file; - * off_t pos; - * if(file == stdin) - * return FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED; - * else if((pos = ftello(file)) < 0) - * return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR; - * else { - * *absolute_byte_offset = (FLAC__uint64)pos; - * return FLAC__STREAM_ENCODER_TELL_STATUS_OK; - * } - * } - * \endcode - * - * \note In general, FLAC__StreamEncoder functions which change the - * state should not be called on the \a encoder while in the callback. - * - * \param encoder The encoder instance calling the callback. - * \param absolute_byte_offset The address at which to store the current - * position of the output. - * \param client_data The callee's client data set through - * FLAC__stream_encoder_init_*(). - * \retval FLAC__StreamEncoderTellStatus - * The callee's return status. - */ -typedef FLAC__StreamEncoderTellStatus (*FLAC__StreamEncoderTellCallback)(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data); - -/** Signature for the metadata callback. - * - * A function pointer matching this signature may be passed to - * FLAC__stream_encoder_init*_stream(). The supplied function will be called - * once at the end of encoding with the populated STREAMINFO structure. This - * is so the client can seek back to the beginning of the file and write the - * STREAMINFO block with the correct statistics after encoding (like - * minimum/maximum frame size and total samples). - * - * \note In general, FLAC__StreamEncoder functions which change the - * state should not be called on the \a encoder while in the callback. - * - * \param encoder The encoder instance calling the callback. - * \param metadata The final populated STREAMINFO block. - * \param client_data The callee's client data set through - * FLAC__stream_encoder_init_*(). - */ -typedef void (*FLAC__StreamEncoderMetadataCallback)(const FLAC__StreamEncoder *encoder, const FLAC__StreamMetadata *metadata, void *client_data); - -/** Signature for the progress callback. - * - * A function pointer matching this signature may be passed to - * FLAC__stream_encoder_init*_file() or FLAC__stream_encoder_init*_FILE(). - * The supplied function will be called when the encoder has finished - * writing a frame. The \c total_frames_estimate argument to the - * callback will be based on the value from - * FLAC__stream_encoder_set_total_samples_estimate(). - * - * \note In general, FLAC__StreamEncoder functions which change the - * state should not be called on the \a encoder while in the callback. - * - * \param encoder The encoder instance calling the callback. - * \param bytes_written Bytes written so far. - * \param samples_written Samples written so far. - * \param frames_written Frames written so far. - * \param total_frames_estimate The estimate of the total number of - * frames to be written. - * \param client_data The callee's client data set through - * FLAC__stream_encoder_init_*(). - */ -typedef void (*FLAC__StreamEncoderProgressCallback)(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, uint32_t frames_written, uint32_t total_frames_estimate, void *client_data); - - -/*********************************************************************** - * - * Class constructor/destructor - * - ***********************************************************************/ - -/** Create a new stream encoder instance. The instance is created with - * default settings; see the individual FLAC__stream_encoder_set_*() - * functions for each setting's default. - * - * \retval FLAC__StreamEncoder* - * \c NULL if there was an error allocating memory, else the new instance. - */ -FLAC_API FLAC__StreamEncoder *FLAC__stream_encoder_new(void); - -/** Free an encoder instance. Deletes the object pointed to by \a encoder. - * - * \param encoder A pointer to an existing encoder. - * \assert - * \code encoder != NULL \endcode - */ -FLAC_API void FLAC__stream_encoder_delete(FLAC__StreamEncoder *encoder); - - -/*********************************************************************** - * - * Public class method prototypes - * - ***********************************************************************/ - -/** Set the serial number for the FLAC stream to use in the Ogg container. - * - * \note - * This does not need to be set for native FLAC encoding. - * - * \note - * It is recommended to set a serial number explicitly as the default of '0' - * may collide with other streams. - * - * \default \c 0 - * \param encoder An encoder instance to set. - * \param serial_number See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_ogg_serial_number(FLAC__StreamEncoder *encoder, long serial_number); - -/** Set the "verify" flag. If \c true, the encoder will verify it's own - * encoded output by feeding it through an internal decoder and comparing - * the original signal against the decoded signal. If a mismatch occurs, - * the process call will return \c false. Note that this will slow the - * encoding process by the extra time required for decoding and comparison. - * - * \default \c false - * \param encoder An encoder instance to set. - * \param value Flag value (see above). - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_verify(FLAC__StreamEncoder *encoder, FLAC__bool value); - -/** Set the Subset flag. If \c true, - * the encoder will comply with the Subset and will check the - * settings during FLAC__stream_encoder_init_*() to see if all settings - * comply. If \c false, the settings may take advantage of the full - * range that the format allows. - * - * Make sure you know what it entails before setting this to \c false. - * - * \default \c true - * \param encoder An encoder instance to set. - * \param value Flag value (see above). - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_streamable_subset(FLAC__StreamEncoder *encoder, FLAC__bool value); - -/** Set the number of channels to be encoded. - * - * \default \c 2 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_channels(FLAC__StreamEncoder *encoder, uint32_t value); - -/** Set the sample resolution of the input to be encoded. - * - * \warning - * Do not feed the encoder data that is wider than the value you - * set here or you will generate an invalid stream. - * - * \default \c 16 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_bits_per_sample(FLAC__StreamEncoder *encoder, uint32_t value); - -/** Set the sample rate (in Hz) of the input to be encoded. - * - * \default \c 44100 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *encoder, uint32_t value); - -/** Set the compression level - * - * The compression level is roughly proportional to the amount of effort - * the encoder expends to compress the file. A higher level usually - * means more computation but higher compression. The default level is - * suitable for most applications. - * - * Currently the levels range from \c 0 (fastest, least compression) to - * \c 8 (slowest, most compression). A value larger than \c 8 will be - * treated as \c 8. - * - * This function automatically calls the following other \c _set_ - * functions with appropriate values, so the client does not need to - * unless it specifically wants to override them: - * - FLAC__stream_encoder_set_do_mid_side_stereo() - * - FLAC__stream_encoder_set_loose_mid_side_stereo() - * - FLAC__stream_encoder_set_apodization() - * - FLAC__stream_encoder_set_max_lpc_order() - * - FLAC__stream_encoder_set_qlp_coeff_precision() - * - FLAC__stream_encoder_set_do_qlp_coeff_prec_search() - * - FLAC__stream_encoder_set_do_escape_coding() - * - FLAC__stream_encoder_set_do_exhaustive_model_search() - * - FLAC__stream_encoder_set_min_residual_partition_order() - * - FLAC__stream_encoder_set_max_residual_partition_order() - * - FLAC__stream_encoder_set_rice_parameter_search_dist() - * - * The actual values set for each level are: - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
leveldo mid-side stereoloose mid-side stereoapodizationmax lpc orderqlp coeff precisionqlp coeff prec searchescape codingexhaustive model searchmin residual partition ordermax residual partition orderrice parameter search dist
0 false false tukey(0.5) 0 0 false false false 0 3 0
1 true true tukey(0.5) 0 0 false false false 0 3 0
2 true false tukey(0.5) 0 0 false false false 0 3 0
3 false false tukey(0.5) 6 0 false false false 0 4 0
4 true true tukey(0.5) 8 0 false false false 0 4 0
5 true false tukey(0.5) 8 0 false false false 0 5 0
6 true false tukey(0.5);partial_tukey(2) 8 0 false false false 0 6 0
7 true false tukey(0.5);partial_tukey(2) 12 0 false false false 0 6 0
8 true false tukey(0.5);partial_tukey(2);punchout_tukey(3) 12 0 false false false 0 6 0
- * - * \default \c 5 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_compression_level(FLAC__StreamEncoder *encoder, uint32_t value); - -/** Set the blocksize to use while encoding. - * - * The number of samples to use per frame. Use \c 0 to let the encoder - * estimate a blocksize; this is usually best. - * - * \default \c 0 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_blocksize(FLAC__StreamEncoder *encoder, uint32_t value); - -/** Set to \c true to enable mid-side encoding on stereo input. The - * number of channels must be 2 for this to have any effect. Set to - * \c false to use only independent channel coding. - * - * \default \c true - * \param encoder An encoder instance to set. - * \param value Flag value (see above). - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_do_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value); - -/** Set to \c true to enable adaptive switching between mid-side and - * left-right encoding on stereo input. Set to \c false to use - * exhaustive searching. Setting this to \c true requires - * FLAC__stream_encoder_set_do_mid_side_stereo() to also be set to - * \c true in order to have any effect. - * - * \default \c false - * \param encoder An encoder instance to set. - * \param value Flag value (see above). - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_loose_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value); - -/** Sets the apodization function(s) the encoder will use when windowing - * audio data for LPC analysis. - * - * The \a specification is a plain ASCII string which specifies exactly - * which functions to use. There may be more than one (up to 32), - * separated by \c ';' characters. Some functions take one or more - * comma-separated arguments in parentheses. - * - * The available functions are \c bartlett, \c bartlett_hann, - * \c blackman, \c blackman_harris_4term_92db, \c connes, \c flattop, - * \c gauss(STDDEV), \c hamming, \c hann, \c kaiser_bessel, \c nuttall, - * \c rectangle, \c triangle, \c tukey(P), \c partial_tukey(n[/ov[/P]]), - * \c punchout_tukey(n[/ov[/P]]), \c welch. - * - * For \c gauss(STDDEV), STDDEV specifies the standard deviation - * (0blocksize / (2 ^ order). - * - * Set both min and max values to \c 0 to force a single context, - * whose Rice parameter is based on the residual signal variance. - * Otherwise, set a min and max order, and the encoder will search - * all orders, using the mean of each context for its Rice parameter, - * and use the best. - * - * \default \c 0 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_min_residual_partition_order(FLAC__StreamEncoder *encoder, uint32_t value); - -/** Set the maximum partition order to search when coding the residual. - * This is used in tandem with - * FLAC__stream_encoder_set_min_residual_partition_order(). - * - * The partition order determines the context size in the residual. - * The context size will be approximately blocksize / (2 ^ order). - * - * Set both min and max values to \c 0 to force a single context, - * whose Rice parameter is based on the residual signal variance. - * Otherwise, set a min and max order, and the encoder will search - * all orders, using the mean of each context for its Rice parameter, - * and use the best. - * - * \default \c 5 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_max_residual_partition_order(FLAC__StreamEncoder *encoder, uint32_t value); - -/** Deprecated. Setting this value has no effect. - * - * \default \c 0 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_rice_parameter_search_dist(FLAC__StreamEncoder *encoder, uint32_t value); - -/** Set an estimate of the total samples that will be encoded. - * This is merely an estimate and may be set to \c 0 if unknown. - * This value will be written to the STREAMINFO block before encoding, - * and can remove the need for the caller to rewrite the value later - * if the value is known before encoding. - * - * \default \c 0 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_total_samples_estimate(FLAC__StreamEncoder *encoder, FLAC__uint64 value); - -/** Set the metadata blocks to be emitted to the stream before encoding. - * A value of \c NULL, \c 0 implies no metadata; otherwise, supply an - * array of pointers to metadata blocks. The array is non-const since - * the encoder may need to change the \a is_last flag inside them, and - * in some cases update seek point offsets. Otherwise, the encoder will - * not modify or free the blocks. It is up to the caller to free the - * metadata blocks after encoding finishes. - * - * \note - * The encoder stores only copies of the pointers in the \a metadata array; - * the metadata blocks themselves must survive at least until after - * FLAC__stream_encoder_finish() returns. Do not free the blocks until then. - * - * \note - * The STREAMINFO block is always written and no STREAMINFO block may - * occur in the supplied array. - * - * \note - * By default the encoder does not create a SEEKTABLE. If one is supplied - * in the \a metadata array, but the client has specified that it does not - * support seeking, then the SEEKTABLE will be written verbatim. However - * by itself this is not very useful as the client will not know the stream - * offsets for the seekpoints ahead of time. In order to get a proper - * seektable the client must support seeking. See next note. - * - * \note - * SEEKTABLE blocks are handled specially. Since you will not know - * the values for the seek point stream offsets, you should pass in - * a SEEKTABLE 'template', that is, a SEEKTABLE object with the - * required sample numbers (or placeholder points), with \c 0 for the - * \a frame_samples and \a stream_offset fields for each point. If the - * client has specified that it supports seeking by providing a seek - * callback to FLAC__stream_encoder_init_stream() or both seek AND read - * callback to FLAC__stream_encoder_init_ogg_stream() (or by using - * FLAC__stream_encoder_init*_file() or FLAC__stream_encoder_init*_FILE()), - * then while it is encoding the encoder will fill the stream offsets in - * for you and when encoding is finished, it will seek back and write the - * real values into the SEEKTABLE block in the stream. There are helper - * routines for manipulating seektable template blocks; see metadata.h: - * FLAC__metadata_object_seektable_template_*(). If the client does - * not support seeking, the SEEKTABLE will have inaccurate offsets which - * will slow down or remove the ability to seek in the FLAC stream. - * - * \note - * The encoder instance \b will modify the first \c SEEKTABLE block - * as it transforms the template to a valid seektable while encoding, - * but it is still up to the caller to free all metadata blocks after - * encoding. - * - * \note - * A VORBIS_COMMENT block may be supplied. The vendor string in it - * will be ignored. libFLAC will use it's own vendor string. libFLAC - * will not modify the passed-in VORBIS_COMMENT's vendor string, it - * will simply write it's own into the stream. If no VORBIS_COMMENT - * block is present in the \a metadata array, libFLAC will write an - * empty one, containing only the vendor string. - * - * \note The Ogg FLAC mapping requires that the VORBIS_COMMENT block be - * the second metadata block of the stream. The encoder already supplies - * the STREAMINFO block automatically. If \a metadata does not contain a - * VORBIS_COMMENT block, the encoder will supply that too. Otherwise, if - * \a metadata does contain a VORBIS_COMMENT block and it is not the - * first, the init function will reorder \a metadata by moving the - * VORBIS_COMMENT block to the front; the relative ordering of the other - * blocks will remain as they were. - * - * \note The Ogg FLAC mapping limits the number of metadata blocks per - * stream to \c 65535. If \a num_blocks exceeds this the function will - * return \c false. - * - * \default \c NULL, 0 - * \param encoder An encoder instance to set. - * \param metadata See above. - * \param num_blocks See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - * \c false if the encoder is already initialized, or if - * \a num_blocks > 65535 if encoding to Ogg FLAC, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_metadata(FLAC__StreamEncoder *encoder, FLAC__StreamMetadata **metadata, uint32_t num_blocks); - -/** Get the current encoder state. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__StreamEncoderState - * The current encoder state. - */ -FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_get_state(const FLAC__StreamEncoder *encoder); - -/** Get the state of the verify stream decoder. - * Useful when the stream encoder state is - * \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__StreamDecoderState - * The verify stream decoder state. - */ -FLAC_API FLAC__StreamDecoderState FLAC__stream_encoder_get_verify_decoder_state(const FLAC__StreamEncoder *encoder); - -/** Get the current encoder state as a C string. - * This version automatically resolves - * \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR by getting the - * verify decoder's state. - * - * \param encoder A encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval const char * - * The encoder state as a C string. Do not modify the contents. - */ -FLAC_API const char *FLAC__stream_encoder_get_resolved_state_string(const FLAC__StreamEncoder *encoder); - -/** Get relevant values about the nature of a verify decoder error. - * Useful when the stream encoder state is - * \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR. The arguments should - * be addresses in which the stats will be returned, or NULL if value - * is not desired. - * - * \param encoder An encoder instance to query. - * \param absolute_sample The absolute sample number of the mismatch. - * \param frame_number The number of the frame in which the mismatch occurred. - * \param channel The channel in which the mismatch occurred. - * \param sample The number of the sample (relative to the frame) in - * which the mismatch occurred. - * \param expected The expected value for the sample in question. - * \param got The actual value returned by the decoder. - * \assert - * \code encoder != NULL \endcode - */ -FLAC_API void FLAC__stream_encoder_get_verify_decoder_error_stats(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_sample, uint32_t *frame_number, uint32_t *channel, uint32_t *sample, FLAC__int32 *expected, FLAC__int32 *got); - -/** Get the "verify" flag. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * See FLAC__stream_encoder_set_verify(). - */ -FLAC_API FLAC__bool FLAC__stream_encoder_get_verify(const FLAC__StreamEncoder *encoder); - -/** Get the frame header. - * - * \param encoder An initialized encoder instance in the OK state. - * \param buffer An array of pointers to each channel's signal. - * \param samples The number of samples in one channel. - * \assert - * \code encoder != NULL \endcode - * \code FLAC__stream_encoder_get_state(encoder) == FLAC__STREAM_ENCODER_OK \endcode - * \retval FLAC__bool - * \c true if successful, else \c false; in this case, check the - * encoder state with FLAC__stream_encoder_get_state() to see what - * went wrong. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC__int32 * const buffer[], uint32_t samples); - -/** Submit data for encoding. - * This version allows you to supply the input data where the channels - * are interleaved into a single array (i.e. channel0_sample0, - * channel1_sample0, ... , channelN_sample0, channel0_sample1, ...). - * The samples need not be block-aligned but they must be - * sample-aligned, i.e. the first value should be channel0_sample0 - * and the last value channelN_sampleM. Each sample should be a signed - * integer, right-justified to the resolution set by - * FLAC__stream_encoder_set_bits_per_sample(). For example, if the - * resolution is 16 bits per sample, the samples should all be in the - * range [-32768,32767]. - * - * For applications where channel order is important, channels must - * follow the order as described in the - * frame header. - * - * \param encoder An initialized encoder instance in the OK state. - * \param buffer An array of channel-interleaved data (see above). - * \param samples The number of samples in one channel, the same as for - * FLAC__stream_encoder_process(). For example, if - * encoding two channels, \c 1000 \a samples corresponds - * to a \a buffer of 2000 values. - * \assert - * \code encoder != NULL \endcode - * \code FLAC__stream_encoder_get_state(encoder) == FLAC__STREAM_ENCODER_OK \endcode - * \retval FLAC__bool - * \c true if successful, else \c false; in this case, check the - * encoder state with FLAC__stream_encoder_get_state() to see what - * went wrong. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder *encoder, const FLAC__int32 buffer[], uint32_t samples); - -/* \} */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/flac/src/bitmath.c b/lib/flac/src/bitmath.c deleted file mode 100644 index 32e31a7..0000000 --- a/lib/flac/src/bitmath.c +++ /dev/null @@ -1,73 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "private/bitmath.h" - -/* An example of what FLAC__bitmath_silog2() computes: - * - * silog2(-10) = 5 - * silog2(- 9) = 5 - * silog2(- 8) = 4 - * silog2(- 7) = 4 - * silog2(- 6) = 4 - * silog2(- 5) = 4 - * silog2(- 4) = 3 - * silog2(- 3) = 3 - * silog2(- 2) = 2 - * silog2(- 1) = 2 - * silog2( 0) = 0 - * silog2( 1) = 2 - * silog2( 2) = 3 - * silog2( 3) = 3 - * silog2( 4) = 4 - * silog2( 5) = 4 - * silog2( 6) = 4 - * silog2( 7) = 4 - * silog2( 8) = 5 - * silog2( 9) = 5 - * silog2( 10) = 5 - */ -uint32_t FLAC__bitmath_silog2(FLAC__int64 v) -{ - if(v == 0) - return 0; - - if(v == -1) - return 2; - - v = (v < 0) ? (-(v+1)) : v; - return FLAC__bitmath_ilog2_wide(v)+2; -} diff --git a/lib/flac/src/bitreader.c b/lib/flac/src/bitreader.c deleted file mode 100644 index 935208a..0000000 --- a/lib/flac/src/bitreader.c +++ /dev/null @@ -1,1092 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2018 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include "private/bitmath.h" -#include "private/bitreader.h" -#include "private/crc.h" -#include "private/macros.h" -#include "FLAC/assert.h" -#include "share/compat.h" -#include "share/endswap.h" - -/* Things should be fastest when this matches the machine word size */ -/* WATCHOUT: if you change this you must also change the following #defines down to COUNT_ZERO_MSBS2 below to match */ -/* WATCHOUT: there are a few places where the code will not work unless brword is >= 32 bits wide */ -/* also, some sections currently only have fast versions for 4 or 8 bytes per word */ - -#if (ENABLE_64_BIT_WORDS == 0) - -typedef FLAC__uint32 brword; -#define FLAC__BYTES_PER_WORD 4 /* sizeof brword */ -#define FLAC__BITS_PER_WORD 32 -#define FLAC__WORD_ALL_ONES ((FLAC__uint32)0xffffffff) -/* SWAP_BE_WORD_TO_HOST swaps bytes in a brword (which is always big-endian) if necessary to match host byte order */ -#if WORDS_BIGENDIAN -#define SWAP_BE_WORD_TO_HOST(x) (x) -#else -#define SWAP_BE_WORD_TO_HOST(x) ENDSWAP_32(x) -#endif -/* counts the # of zero MSBs in a word */ -#define COUNT_ZERO_MSBS(word) FLAC__clz_uint32(word) -#define COUNT_ZERO_MSBS2(word) FLAC__clz2_uint32(word) - -#else - -typedef FLAC__uint64 brword; -#define FLAC__BYTES_PER_WORD 8 /* sizeof brword */ -#define FLAC__BITS_PER_WORD 64 -#define FLAC__WORD_ALL_ONES ((FLAC__uint64)FLAC__U64L(0xffffffffffffffff)) -/* SWAP_BE_WORD_TO_HOST swaps bytes in a brword (which is always big-endian) if necessary to match host byte order */ -#if WORDS_BIGENDIAN -#define SWAP_BE_WORD_TO_HOST(x) (x) -#else -#define SWAP_BE_WORD_TO_HOST(x) ENDSWAP_64(x) -#endif -/* counts the # of zero MSBs in a word */ -#define COUNT_ZERO_MSBS(word) FLAC__clz_uint64(word) -#define COUNT_ZERO_MSBS2(word) FLAC__clz2_uint64(word) - -#endif - -/* - * This should be at least twice as large as the largest number of words - * required to represent any 'number' (in any encoding) you are going to - * read. With FLAC this is on the order of maybe a few hundred bits. - * If the buffer is smaller than that, the decoder won't be able to read - * in a whole number that is in a variable length encoding (e.g. Rice). - * But to be practical it should be at least 1K bytes. - * - * Increase this number to decrease the number of read callbacks, at the - * expense of using more memory. Or decrease for the reverse effect, - * keeping in mind the limit from the first paragraph. The optimal size - * also depends on the CPU cache size and other factors; some twiddling - * may be necessary to squeeze out the best performance. - */ -static const uint32_t FLAC__BITREADER_DEFAULT_CAPACITY = 65536u / FLAC__BITS_PER_WORD; /* in words */ - -struct FLAC__BitReader { - /* any partially-consumed word at the head will stay right-justified as bits are consumed from the left */ - /* any incomplete word at the tail will be left-justified, and bytes from the read callback are added on the right */ - brword *buffer; - uint32_t capacity; /* in words */ - uint32_t words; /* # of completed words in buffer */ - uint32_t bytes; /* # of bytes in incomplete word at buffer[words] */ - uint32_t consumed_words; /* #words ... */ - uint32_t consumed_bits; /* ... + (#bits of head word) already consumed from the front of buffer */ - uint32_t read_crc16; /* the running frame CRC */ - uint32_t crc16_offset; /* the number of words in the current buffer that should not be CRC'd */ - uint32_t crc16_align; /* the number of bits in the current consumed word that should not be CRC'd */ - FLAC__BitReaderReadCallback read_callback; - void *client_data; -}; - -static inline void crc16_update_word_(FLAC__BitReader *br, brword word) -{ - register uint32_t crc = br->read_crc16; - - for( ; br->crc16_align < FLAC__BITS_PER_WORD; br->crc16_align += 8) - crc = FLAC__CRC16_UPDATE((uint32_t)((word >> (FLAC__BITS_PER_WORD-8-br->crc16_align)) & 0xff), crc); - - br->read_crc16 = crc; - br->crc16_align = 0; -} - -static inline void crc16_update_block_(FLAC__BitReader *br) -{ - if(br->consumed_words > br->crc16_offset && br->crc16_align) - crc16_update_word_(br, br->buffer[br->crc16_offset++]); - -#if FLAC__BYTES_PER_WORD == 4 - br->read_crc16 = FLAC__crc16_update_words32(br->buffer + br->crc16_offset, br->consumed_words - br->crc16_offset, br->read_crc16); -#elif FLAC__BYTES_PER_WORD == 8 - br->read_crc16 = FLAC__crc16_update_words64(br->buffer + br->crc16_offset, br->consumed_words - br->crc16_offset, br->read_crc16); -#else - unsigned i; - - for(i = br->crc16_offset; i < br->consumed_words; i++) - crc16_update_word_(br, br->buffer[i]); -#endif - - br->crc16_offset = 0; -} - -static FLAC__bool bitreader_read_from_client_(FLAC__BitReader *br) -{ - uint32_t start, end; - size_t bytes; - FLAC__byte *target; - - /* first shift the unconsumed buffer data toward the front as much as possible */ - if(br->consumed_words > 0) { - crc16_update_block_(br); /* CRC consumed words */ - - start = br->consumed_words; - end = br->words + (br->bytes? 1:0); - memmove(br->buffer, br->buffer+start, FLAC__BYTES_PER_WORD * (end - start)); - - br->words -= start; - br->consumed_words = 0; - } - - /* - * set the target for reading, taking into account word alignment and endianness - */ - bytes = (br->capacity - br->words) * FLAC__BYTES_PER_WORD - br->bytes; - if(bytes == 0) - return false; /* no space left, buffer is too small; see note for FLAC__BITREADER_DEFAULT_CAPACITY */ - target = ((FLAC__byte*)(br->buffer+br->words)) + br->bytes; - - /* before reading, if the existing reader looks like this (say brword is 32 bits wide) - * bitstream : 11 22 33 44 55 br->words=1 br->bytes=1 (partial tail word is left-justified) - * buffer[BE]: 11 22 33 44 55 ?? ?? ?? (shown laid out as bytes sequentially in memory) - * buffer[LE]: 44 33 22 11 ?? ?? ?? 55 (?? being don't-care) - * ^^-------target, bytes=3 - * on LE machines, have to byteswap the odd tail word so nothing is - * overwritten: - */ -#if WORDS_BIGENDIAN -#else - if(br->bytes) - br->buffer[br->words] = SWAP_BE_WORD_TO_HOST(br->buffer[br->words]); -#endif - - /* now it looks like: - * bitstream : 11 22 33 44 55 br->words=1 br->bytes=1 - * buffer[BE]: 11 22 33 44 55 ?? ?? ?? - * buffer[LE]: 44 33 22 11 55 ?? ?? ?? - * ^^-------target, bytes=3 - */ - - /* read in the data; note that the callback may return a smaller number of bytes */ - if(!br->read_callback(target, &bytes, br->client_data)) - return false; - - /* after reading bytes 66 77 88 99 AA BB CC DD EE FF from the client: - * bitstream : 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF - * buffer[BE]: 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF ?? - * buffer[LE]: 44 33 22 11 55 66 77 88 99 AA BB CC DD EE FF ?? - * now have to byteswap on LE machines: - */ -#if WORDS_BIGENDIAN -#else - end = (br->words*FLAC__BYTES_PER_WORD + br->bytes + (uint32_t)bytes + (FLAC__BYTES_PER_WORD-1)) / FLAC__BYTES_PER_WORD; - for(start = br->words; start < end; start++) - br->buffer[start] = SWAP_BE_WORD_TO_HOST(br->buffer[start]); -#endif - - /* now it looks like: - * bitstream : 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF - * buffer[BE]: 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF ?? - * buffer[LE]: 44 33 22 11 88 77 66 55 CC BB AA 99 ?? FF EE DD - * finally we'll update the reader values: - */ - end = br->words*FLAC__BYTES_PER_WORD + br->bytes + (uint32_t)bytes; - br->words = end / FLAC__BYTES_PER_WORD; - br->bytes = end % FLAC__BYTES_PER_WORD; - - return true; -} - -/*********************************************************************** - * - * Class constructor/destructor - * - ***********************************************************************/ - -FLAC__BitReader *FLAC__bitreader_new(void) -{ - FLAC__BitReader *br = calloc(1, sizeof(FLAC__BitReader)); - - /* calloc() implies: - memset(br, 0, sizeof(FLAC__BitReader)); - br->buffer = 0; - br->capacity = 0; - br->words = br->bytes = 0; - br->consumed_words = br->consumed_bits = 0; - br->read_callback = 0; - br->client_data = 0; - */ - return br; -} - -void FLAC__bitreader_delete(FLAC__BitReader *br) -{ - FLAC__ASSERT(0 != br); - - FLAC__bitreader_free(br); - free(br); -} - -/*********************************************************************** - * - * Public class methods - * - ***********************************************************************/ - -FLAC__bool FLAC__bitreader_init(FLAC__BitReader *br, FLAC__BitReaderReadCallback rcb, void *cd) -{ - FLAC__ASSERT(0 != br); - - br->words = br->bytes = 0; - br->consumed_words = br->consumed_bits = 0; - br->capacity = FLAC__BITREADER_DEFAULT_CAPACITY; - br->buffer = malloc(sizeof(brword) * br->capacity); - if(br->buffer == 0) - return false; - br->read_callback = rcb; - br->client_data = cd; - - return true; -} - -void FLAC__bitreader_free(FLAC__BitReader *br) -{ - FLAC__ASSERT(0 != br); - - if(0 != br->buffer) - free(br->buffer); - br->buffer = 0; - br->capacity = 0; - br->words = br->bytes = 0; - br->consumed_words = br->consumed_bits = 0; - br->read_callback = 0; - br->client_data = 0; -} - -FLAC__bool FLAC__bitreader_clear(FLAC__BitReader *br) -{ - br->words = br->bytes = 0; - br->consumed_words = br->consumed_bits = 0; - return true; -} - -void FLAC__bitreader_dump(const FLAC__BitReader *br, FILE *out) -{ - uint32_t i, j; - if(br == 0) { - fprintf(out, "bitreader is NULL\n"); - } - else { - fprintf(out, "bitreader: capacity=%u words=%u bytes=%u consumed: words=%u, bits=%u\n", br->capacity, br->words, br->bytes, br->consumed_words, br->consumed_bits); - - for(i = 0; i < br->words; i++) { - fprintf(out, "%08X: ", i); - for(j = 0; j < FLAC__BITS_PER_WORD; j++) - if(i < br->consumed_words || (i == br->consumed_words && j < br->consumed_bits)) - fprintf(out, "."); - else - fprintf(out, "%01d", br->buffer[i] & ((brword)1 << (FLAC__BITS_PER_WORD-j-1)) ? 1:0); - fprintf(out, "\n"); - } - if(br->bytes > 0) { - fprintf(out, "%08X: ", i); - for(j = 0; j < br->bytes*8; j++) - if(i < br->consumed_words || (i == br->consumed_words && j < br->consumed_bits)) - fprintf(out, "."); - else - fprintf(out, "%01d", br->buffer[i] & ((brword)1 << (br->bytes*8-j-1)) ? 1:0); - fprintf(out, "\n"); - } - } -} - -void FLAC__bitreader_reset_read_crc16(FLAC__BitReader *br, FLAC__uint16 seed) -{ - FLAC__ASSERT(0 != br); - FLAC__ASSERT(0 != br->buffer); - FLAC__ASSERT((br->consumed_bits & 7) == 0); - - br->read_crc16 = (uint32_t)seed; - br->crc16_offset = br->consumed_words; - br->crc16_align = br->consumed_bits; -} - -FLAC__uint16 FLAC__bitreader_get_read_crc16(FLAC__BitReader *br) -{ - FLAC__ASSERT(0 != br); - FLAC__ASSERT(0 != br->buffer); - - /* CRC consumed words up to here */ - crc16_update_block_(br); - - FLAC__ASSERT((br->consumed_bits & 7) == 0); - FLAC__ASSERT(br->crc16_align <= br->consumed_bits); - - /* CRC any tail bytes in a partially-consumed word */ - if(br->consumed_bits) { - const brword tail = br->buffer[br->consumed_words]; - for( ; br->crc16_align < br->consumed_bits; br->crc16_align += 8) - br->read_crc16 = FLAC__CRC16_UPDATE((uint32_t)((tail >> (FLAC__BITS_PER_WORD-8-br->crc16_align)) & 0xff), br->read_crc16); - } - return br->read_crc16; -} - -inline FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br) -{ - return ((br->consumed_bits & 7) == 0); -} - -inline uint32_t FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br) -{ - return 8 - (br->consumed_bits & 7); -} - -inline uint32_t FLAC__bitreader_get_input_bits_unconsumed(const FLAC__BitReader *br) -{ - return (br->words-br->consumed_words)*FLAC__BITS_PER_WORD + br->bytes*8 - br->consumed_bits; -} - -FLAC__bool FLAC__bitreader_read_raw_uint32(FLAC__BitReader *br, FLAC__uint32 *val, uint32_t bits) -{ - FLAC__ASSERT(0 != br); - FLAC__ASSERT(0 != br->buffer); - - FLAC__ASSERT(bits <= 32); - FLAC__ASSERT((br->capacity*FLAC__BITS_PER_WORD) * 2 >= bits); - FLAC__ASSERT(br->consumed_words <= br->words); - - /* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */ - FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32); - - if(bits == 0) { /* OPT: investigate if this can ever happen, maybe change to assertion */ - *val = 0; - return true; - } - - while((br->words-br->consumed_words)*FLAC__BITS_PER_WORD + br->bytes*8 - br->consumed_bits < bits) { - if(!bitreader_read_from_client_(br)) - return false; - } - if(br->consumed_words < br->words) { /* if we've not consumed up to a partial tail word... */ - /* OPT: taking out the consumed_bits==0 "else" case below might make things faster if less code allows the compiler to inline this function */ - if(br->consumed_bits) { - /* this also works when consumed_bits==0, it's just a little slower than necessary for that case */ - const uint32_t n = FLAC__BITS_PER_WORD - br->consumed_bits; - const brword word = br->buffer[br->consumed_words]; - if(bits < n) { - *val = (FLAC__uint32)((word & (FLAC__WORD_ALL_ONES >> br->consumed_bits)) >> (n-bits)); /* The result has <= 32 non-zero bits */ - br->consumed_bits += bits; - return true; - } - /* (FLAC__BITS_PER_WORD - br->consumed_bits <= bits) ==> (FLAC__WORD_ALL_ONES >> br->consumed_bits) has no more than 'bits' non-zero bits */ - *val = (FLAC__uint32)(word & (FLAC__WORD_ALL_ONES >> br->consumed_bits)); - bits -= n; - br->consumed_words++; - br->consumed_bits = 0; - if(bits) { /* if there are still bits left to read, there have to be less than 32 so they will all be in the next word */ - *val <<= bits; - *val |= (FLAC__uint32)(br->buffer[br->consumed_words] >> (FLAC__BITS_PER_WORD-bits)); - br->consumed_bits = bits; - } - return true; - } - else { /* br->consumed_bits == 0 */ - const brword word = br->buffer[br->consumed_words]; - if(bits < FLAC__BITS_PER_WORD) { - *val = (FLAC__uint32)(word >> (FLAC__BITS_PER_WORD-bits)); - br->consumed_bits = bits; - return true; - } - /* at this point bits == FLAC__BITS_PER_WORD == 32; because of previous assertions, it can't be larger */ - *val = (FLAC__uint32)word; - br->consumed_words++; - return true; - } - } - else { - /* in this case we're starting our read at a partial tail word; - * the reader has guaranteed that we have at least 'bits' bits - * available to read, which makes this case simpler. - */ - /* OPT: taking out the consumed_bits==0 "else" case below might make things faster if less code allows the compiler to inline this function */ - if(br->consumed_bits) { - /* this also works when consumed_bits==0, it's just a little slower than necessary for that case */ - FLAC__ASSERT(br->consumed_bits + bits <= br->bytes*8); - *val = (FLAC__uint32)((br->buffer[br->consumed_words] & (FLAC__WORD_ALL_ONES >> br->consumed_bits)) >> (FLAC__BITS_PER_WORD-br->consumed_bits-bits)); - br->consumed_bits += bits; - return true; - } - else { - *val = (FLAC__uint32)(br->buffer[br->consumed_words] >> (FLAC__BITS_PER_WORD-bits)); - br->consumed_bits += bits; - return true; - } - } -} - -FLAC__bool FLAC__bitreader_read_raw_int32(FLAC__BitReader *br, FLAC__int32 *val, uint32_t bits) -{ - FLAC__uint32 uval, mask; - /* OPT: inline raw uint32 code here, or make into a macro if possible in the .h file */ - if(!FLAC__bitreader_read_raw_uint32(br, &uval, bits)) - return false; - /* sign-extend *val assuming it is currently bits wide. */ - /* From: https://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend */ - mask = 1u << (bits - 1); - *val = (uval ^ mask) - mask; - return true; -} - -FLAC__bool FLAC__bitreader_read_raw_uint64(FLAC__BitReader *br, FLAC__uint64 *val, uint32_t bits) -{ - FLAC__uint32 hi, lo; - - if(bits > 32) { - if(!FLAC__bitreader_read_raw_uint32(br, &hi, bits-32)) - return false; - if(!FLAC__bitreader_read_raw_uint32(br, &lo, 32)) - return false; - *val = hi; - *val <<= 32; - *val |= lo; - } - else { - if(!FLAC__bitreader_read_raw_uint32(br, &lo, bits)) - return false; - *val = lo; - } - return true; -} - -inline FLAC__bool FLAC__bitreader_read_uint32_little_endian(FLAC__BitReader *br, FLAC__uint32 *val) -{ - FLAC__uint32 x8, x32 = 0; - - /* this doesn't need to be that fast as currently it is only used for vorbis comments */ - - if(!FLAC__bitreader_read_raw_uint32(br, &x32, 8)) - return false; - - if(!FLAC__bitreader_read_raw_uint32(br, &x8, 8)) - return false; - x32 |= (x8 << 8); - - if(!FLAC__bitreader_read_raw_uint32(br, &x8, 8)) - return false; - x32 |= (x8 << 16); - - if(!FLAC__bitreader_read_raw_uint32(br, &x8, 8)) - return false; - x32 |= (x8 << 24); - - *val = x32; - return true; -} - -FLAC__bool FLAC__bitreader_skip_bits_no_crc(FLAC__BitReader *br, uint32_t bits) -{ - /* - * OPT: a faster implementation is possible but probably not that useful - * since this is only called a couple of times in the metadata readers. - */ - FLAC__ASSERT(0 != br); - FLAC__ASSERT(0 != br->buffer); - - if(bits > 0) { - const uint32_t n = br->consumed_bits & 7; - uint32_t m; - FLAC__uint32 x; - - if(n != 0) { - m = flac_min(8-n, bits); - if(!FLAC__bitreader_read_raw_uint32(br, &x, m)) - return false; - bits -= m; - } - m = bits / 8; - if(m > 0) { - if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(br, m)) - return false; - bits %= 8; - } - if(bits > 0) { - if(!FLAC__bitreader_read_raw_uint32(br, &x, bits)) - return false; - } - } - - return true; -} - -FLAC__bool FLAC__bitreader_skip_byte_block_aligned_no_crc(FLAC__BitReader *br, uint32_t nvals) -{ - FLAC__uint32 x; - - FLAC__ASSERT(0 != br); - FLAC__ASSERT(0 != br->buffer); - FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(br)); - - /* step 1: skip over partial head word to get word aligned */ - while(nvals && br->consumed_bits) { /* i.e. run until we read 'nvals' bytes or we hit the end of the head word */ - if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) - return false; - nvals--; - } - if(0 == nvals) - return true; - /* step 2: skip whole words in chunks */ - while(nvals >= FLAC__BYTES_PER_WORD) { - if(br->consumed_words < br->words) { - br->consumed_words++; - nvals -= FLAC__BYTES_PER_WORD; - } - else if(!bitreader_read_from_client_(br)) - return false; - } - /* step 3: skip any remainder from partial tail bytes */ - while(nvals) { - if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) - return false; - nvals--; - } - - return true; -} - -FLAC__bool FLAC__bitreader_read_byte_block_aligned_no_crc(FLAC__BitReader *br, FLAC__byte *val, uint32_t nvals) -{ - FLAC__uint32 x; - - FLAC__ASSERT(0 != br); - FLAC__ASSERT(0 != br->buffer); - FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(br)); - - /* step 1: read from partial head word to get word aligned */ - while(nvals && br->consumed_bits) { /* i.e. run until we read 'nvals' bytes or we hit the end of the head word */ - if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) - return false; - *val++ = (FLAC__byte)x; - nvals--; - } - if(0 == nvals) - return true; - /* step 2: read whole words in chunks */ - while(nvals >= FLAC__BYTES_PER_WORD) { - if(br->consumed_words < br->words) { - const brword word = br->buffer[br->consumed_words++]; -#if FLAC__BYTES_PER_WORD == 4 - val[0] = (FLAC__byte)(word >> 24); - val[1] = (FLAC__byte)(word >> 16); - val[2] = (FLAC__byte)(word >> 8); - val[3] = (FLAC__byte)word; -#elif FLAC__BYTES_PER_WORD == 8 - val[0] = (FLAC__byte)(word >> 56); - val[1] = (FLAC__byte)(word >> 48); - val[2] = (FLAC__byte)(word >> 40); - val[3] = (FLAC__byte)(word >> 32); - val[4] = (FLAC__byte)(word >> 24); - val[5] = (FLAC__byte)(word >> 16); - val[6] = (FLAC__byte)(word >> 8); - val[7] = (FLAC__byte)word; -#else - for(x = 0; x < FLAC__BYTES_PER_WORD; x++) - val[x] = (FLAC__byte)(word >> (8*(FLAC__BYTES_PER_WORD-x-1))); -#endif - val += FLAC__BYTES_PER_WORD; - nvals -= FLAC__BYTES_PER_WORD; - } - else if(!bitreader_read_from_client_(br)) - return false; - } - /* step 3: read any remainder from partial tail bytes */ - while(nvals) { - if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) - return false; - *val++ = (FLAC__byte)x; - nvals--; - } - - return true; -} - -FLAC__bool FLAC__bitreader_read_unary_unsigned(FLAC__BitReader *br, uint32_t *val) -#if 0 /* slow but readable version */ -{ - uint32_t bit; - - FLAC__ASSERT(0 != br); - FLAC__ASSERT(0 != br->buffer); - - *val = 0; - while(1) { - if(!FLAC__bitreader_read_bit(br, &bit)) - return false; - if(bit) - break; - else - *val++; - } - return true; -} -#else -{ - uint32_t i; - - FLAC__ASSERT(0 != br); - FLAC__ASSERT(0 != br->buffer); - - *val = 0; - while(1) { - while(br->consumed_words < br->words) { /* if we've not consumed up to a partial tail word... */ - brword b = br->buffer[br->consumed_words] << br->consumed_bits; - if(b) { - i = COUNT_ZERO_MSBS(b); - *val += i; - i++; - br->consumed_bits += i; - if(br->consumed_bits >= FLAC__BITS_PER_WORD) { /* faster way of testing if(br->consumed_bits == FLAC__BITS_PER_WORD) */ - br->consumed_words++; - br->consumed_bits = 0; - } - return true; - } - else { - *val += FLAC__BITS_PER_WORD - br->consumed_bits; - br->consumed_words++; - br->consumed_bits = 0; - /* didn't find stop bit yet, have to keep going... */ - } - } - /* at this point we've eaten up all the whole words; have to try - * reading through any tail bytes before calling the read callback. - * this is a repeat of the above logic adjusted for the fact we - * don't have a whole word. note though if the client is feeding - * us data a byte at a time (unlikely), br->consumed_bits may not - * be zero. - */ - if(br->bytes*8 > br->consumed_bits) { - const uint32_t end = br->bytes * 8; - brword b = (br->buffer[br->consumed_words] & (FLAC__WORD_ALL_ONES << (FLAC__BITS_PER_WORD-end))) << br->consumed_bits; - if(b) { - i = COUNT_ZERO_MSBS(b); - *val += i; - i++; - br->consumed_bits += i; - FLAC__ASSERT(br->consumed_bits < FLAC__BITS_PER_WORD); - return true; - } - else { - *val += end - br->consumed_bits; - br->consumed_bits = end; - FLAC__ASSERT(br->consumed_bits < FLAC__BITS_PER_WORD); - /* didn't find stop bit yet, have to keep going... */ - } - } - if(!bitreader_read_from_client_(br)) - return false; - } -} -#endif - -FLAC__bool FLAC__bitreader_read_rice_signed(FLAC__BitReader *br, int *val, uint32_t parameter) -{ - FLAC__uint32 lsbs = 0, msbs = 0; - uint32_t uval; - - FLAC__ASSERT(0 != br); - FLAC__ASSERT(0 != br->buffer); - FLAC__ASSERT(parameter <= 31); - - /* read the unary MSBs and end bit */ - if(!FLAC__bitreader_read_unary_unsigned(br, &msbs)) - return false; - - /* read the binary LSBs */ - if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, parameter)) - return false; - - /* compose the value */ - uval = (msbs << parameter) | lsbs; - if(uval & 1) - *val = -((int)(uval >> 1)) - 1; - else - *val = (int)(uval >> 1); - - return true; -} - -/* this is by far the most heavily used reader call. it ain't pretty but it's fast */ -FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], uint32_t nvals, uint32_t parameter) -{ - /* try and get br->consumed_words and br->consumed_bits into register; - * must remember to flush them back to *br before calling other - * bitreader functions that use them, and before returning */ - uint32_t cwords, words, lsbs, msbs, x, y; - uint32_t ucbits; /* keep track of the number of unconsumed bits in word */ - brword b; - int *val, *end; - - FLAC__ASSERT(0 != br); - FLAC__ASSERT(0 != br->buffer); - /* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */ - FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32); - FLAC__ASSERT(parameter < 32); - /* the above two asserts also guarantee that the binary part never straddles more than 2 words, so we don't have to loop to read it */ - - val = vals; - end = vals + nvals; - - if(parameter == 0) { - while(val < end) { - /* read the unary MSBs and end bit */ - if(!FLAC__bitreader_read_unary_unsigned(br, &msbs)) - return false; - - *val++ = (int)(msbs >> 1) ^ -(int)(msbs & 1); - } - - return true; - } - - FLAC__ASSERT(parameter > 0); - - cwords = br->consumed_words; - words = br->words; - - /* if we've not consumed up to a partial tail word... */ - if(cwords >= words) { - x = 0; - goto process_tail; - } - - ucbits = FLAC__BITS_PER_WORD - br->consumed_bits; - b = br->buffer[cwords] << br->consumed_bits; /* keep unconsumed bits aligned to left */ - - while(val < end) { - /* read the unary MSBs and end bit */ - x = y = COUNT_ZERO_MSBS2(b); - if(x == FLAC__BITS_PER_WORD) { - x = ucbits; - do { - /* didn't find stop bit yet, have to keep going... */ - cwords++; - if (cwords >= words) - goto incomplete_msbs; - b = br->buffer[cwords]; - y = COUNT_ZERO_MSBS2(b); - x += y; - } while(y == FLAC__BITS_PER_WORD); - } - b <<= y; - b <<= 1; /* account for stop bit */ - ucbits = (ucbits - x - 1) % FLAC__BITS_PER_WORD; - msbs = x; - - /* read the binary LSBs */ - x = (FLAC__uint32)(b >> (FLAC__BITS_PER_WORD - parameter)); /* parameter < 32, so we can cast to 32-bit uint32_t */ - if(parameter <= ucbits) { - ucbits -= parameter; - b <<= parameter; - } else { - /* there are still bits left to read, they will all be in the next word */ - cwords++; - if (cwords >= words) - goto incomplete_lsbs; - b = br->buffer[cwords]; - ucbits += FLAC__BITS_PER_WORD - parameter; - x |= (FLAC__uint32)(b >> ucbits); - b <<= FLAC__BITS_PER_WORD - ucbits; - } - lsbs = x; - - /* compose the value */ - x = (msbs << parameter) | lsbs; - *val++ = (int)(x >> 1) ^ -(int)(x & 1); - - continue; - - /* at this point we've eaten up all the whole words */ -process_tail: - do { - if(0) { -incomplete_msbs: - br->consumed_bits = 0; - br->consumed_words = cwords; - } - - /* read the unary MSBs and end bit */ - if(!FLAC__bitreader_read_unary_unsigned(br, &msbs)) - return false; - msbs += x; - x = ucbits = 0; - - if(0) { -incomplete_lsbs: - br->consumed_bits = 0; - br->consumed_words = cwords; - } - - /* read the binary LSBs */ - if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, parameter - ucbits)) - return false; - lsbs = x | lsbs; - - /* compose the value */ - x = (msbs << parameter) | lsbs; - *val++ = (int)(x >> 1) ^ -(int)(x & 1); - x = 0; - - cwords = br->consumed_words; - words = br->words; - ucbits = FLAC__BITS_PER_WORD - br->consumed_bits; - b = br->buffer[cwords] << br->consumed_bits; - } while(cwords >= words && val < end); - } - - if(ucbits == 0 && cwords < words) { - /* don't leave the head word with no unconsumed bits */ - cwords++; - ucbits = FLAC__BITS_PER_WORD; - } - - br->consumed_bits = FLAC__BITS_PER_WORD - ucbits; - br->consumed_words = cwords; - - return true; -} - -#if 0 /* UNUSED */ -FLAC__bool FLAC__bitreader_read_golomb_signed(FLAC__BitReader *br, int *val, uint32_t parameter) -{ - FLAC__uint32 lsbs = 0, msbs = 0; - uint32_t bit, uval, k; - - FLAC__ASSERT(0 != br); - FLAC__ASSERT(0 != br->buffer); - - k = FLAC__bitmath_ilog2(parameter); - - /* read the unary MSBs and end bit */ - if(!FLAC__bitreader_read_unary_unsigned(br, &msbs)) - return false; - - /* read the binary LSBs */ - if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, k)) - return false; - - if(parameter == 1u<= d) { - if(!FLAC__bitreader_read_bit(br, &bit)) - return false; - lsbs <<= 1; - lsbs |= bit; - lsbs -= d; - } - /* compose the value */ - uval = msbs * parameter + lsbs; - } - - /* unfold uint32_t to signed */ - if(uval & 1) - *val = -((int)(uval >> 1)) - 1; - else - *val = (int)(uval >> 1); - - return true; -} - -FLAC__bool FLAC__bitreader_read_golomb_unsigned(FLAC__BitReader *br, uint32_t *val, uint32_t parameter) -{ - FLAC__uint32 lsbs, msbs = 0; - uint32_t bit, k; - - FLAC__ASSERT(0 != br); - FLAC__ASSERT(0 != br->buffer); - - k = FLAC__bitmath_ilog2(parameter); - - /* read the unary MSBs and end bit */ - if(!FLAC__bitreader_read_unary_unsigned(br, &msbs)) - return false; - - /* read the binary LSBs */ - if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, k)) - return false; - - if(parameter == 1u<= d) { - if(!FLAC__bitreader_read_bit(br, &bit)) - return false; - lsbs <<= 1; - lsbs |= bit; - lsbs -= d; - } - /* compose the value */ - *val = msbs * parameter + lsbs; - } - - return true; -} -#endif /* UNUSED */ - -/* on return, if *val == 0xffffffff then the utf-8 sequence was invalid, but the return value will be true */ -FLAC__bool FLAC__bitreader_read_utf8_uint32(FLAC__BitReader *br, FLAC__uint32 *val, FLAC__byte *raw, uint32_t *rawlen) -{ - FLAC__uint32 v = 0; - FLAC__uint32 x; - uint32_t i; - - if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) - return false; - if(raw) - raw[(*rawlen)++] = (FLAC__byte)x; - if(!(x & 0x80)) { /* 0xxxxxxx */ - v = x; - i = 0; - } - else if(x & 0xC0 && !(x & 0x20)) { /* 110xxxxx */ - v = x & 0x1F; - i = 1; - } - else if(x & 0xE0 && !(x & 0x10)) { /* 1110xxxx */ - v = x & 0x0F; - i = 2; - } - else if(x & 0xF0 && !(x & 0x08)) { /* 11110xxx */ - v = x & 0x07; - i = 3; - } - else if(x & 0xF8 && !(x & 0x04)) { /* 111110xx */ - v = x & 0x03; - i = 4; - } - else if(x & 0xFC && !(x & 0x02)) { /* 1111110x */ - v = x & 0x01; - i = 5; - } - else { - *val = 0xffffffff; - return true; - } - for( ; i; i--) { - if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) - return false; - if(raw) - raw[(*rawlen)++] = (FLAC__byte)x; - if(!(x & 0x80) || (x & 0x40)) { /* 10xxxxxx */ - *val = 0xffffffff; - return true; - } - v <<= 6; - v |= (x & 0x3F); - } - *val = v; - return true; -} - -/* on return, if *val == 0xffffffffffffffff then the utf-8 sequence was invalid, but the return value will be true */ -FLAC__bool FLAC__bitreader_read_utf8_uint64(FLAC__BitReader *br, FLAC__uint64 *val, FLAC__byte *raw, uint32_t *rawlen) -{ - FLAC__uint64 v = 0; - FLAC__uint32 x; - uint32_t i; - - if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) - return false; - if(raw) - raw[(*rawlen)++] = (FLAC__byte)x; - if(!(x & 0x80)) { /* 0xxxxxxx */ - v = x; - i = 0; - } - else if(x & 0xC0 && !(x & 0x20)) { /* 110xxxxx */ - v = x & 0x1F; - i = 1; - } - else if(x & 0xE0 && !(x & 0x10)) { /* 1110xxxx */ - v = x & 0x0F; - i = 2; - } - else if(x & 0xF0 && !(x & 0x08)) { /* 11110xxx */ - v = x & 0x07; - i = 3; - } - else if(x & 0xF8 && !(x & 0x04)) { /* 111110xx */ - v = x & 0x03; - i = 4; - } - else if(x & 0xFC && !(x & 0x02)) { /* 1111110x */ - v = x & 0x01; - i = 5; - } - else if(x & 0xFE && !(x & 0x01)) { /* 11111110 */ - v = 0; - i = 6; - } - else { - *val = FLAC__U64L(0xffffffffffffffff); - return true; - } - for( ; i; i--) { - if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) - return false; - if(raw) - raw[(*rawlen)++] = (FLAC__byte)x; - if(!(x & 0x80) || (x & 0x40)) { /* 10xxxxxx */ - *val = FLAC__U64L(0xffffffffffffffff); - return true; - } - v <<= 6; - v |= (x & 0x3F); - } - *val = v; - return true; -} - -/* These functions are declared inline in this file but are also callable as - * externs from elsewhere. - * According to the C99 spec, section 6.7.4, simply providing a function - * prototype in a header file without 'inline' and making the function inline - * in this file should be sufficient. - * Unfortunately, the Microsoft VS compiler doesn't pick them up externally. To - * fix that we add extern declarations here. - */ -extern FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br); -extern uint32_t FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br); -extern uint32_t FLAC__bitreader_get_input_bits_unconsumed(const FLAC__BitReader *br); -extern FLAC__bool FLAC__bitreader_read_uint32_little_endian(FLAC__BitReader *br, FLAC__uint32 *val); diff --git a/lib/flac/src/bitwriter.c b/lib/flac/src/bitwriter.c deleted file mode 100644 index 6e86585..0000000 --- a/lib/flac/src/bitwriter.c +++ /dev/null @@ -1,885 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include "private/bitwriter.h" -#include "private/crc.h" -#include "private/macros.h" -#include "FLAC/assert.h" -#include "share/alloc.h" -#include "share/compat.h" -#include "share/endswap.h" - -/* Things should be fastest when this matches the machine word size */ -/* WATCHOUT: if you change this you must also change the following #defines down to SWAP_BE_WORD_TO_HOST below to match */ -/* WATCHOUT: there are a few places where the code will not work unless bwword is >= 32 bits wide */ - -#if (ENABLE_64_BIT_WORDS == 0) - -typedef FLAC__uint32 bwword; -#define FLAC__BYTES_PER_WORD 4 /* sizeof bwword */ -#define FLAC__BITS_PER_WORD 32 -/* SWAP_BE_WORD_TO_HOST swaps bytes in a bwword (which is always big-endian) if necessary to match host byte order */ -#if WORDS_BIGENDIAN -#define SWAP_BE_WORD_TO_HOST(x) (x) -#else -#define SWAP_BE_WORD_TO_HOST(x) ENDSWAP_32(x) -#endif - -#else - -typedef FLAC__uint64 bwword; -#define FLAC__BYTES_PER_WORD 8 /* sizeof bwword */ -#define FLAC__BITS_PER_WORD 64 -/* SWAP_BE_WORD_TO_HOST swaps bytes in a bwword (which is always big-endian) if necessary to match host byte order */ -#if WORDS_BIGENDIAN -#define SWAP_BE_WORD_TO_HOST(x) (x) -#else -#define SWAP_BE_WORD_TO_HOST(x) ENDSWAP_64(x) -#endif - -#endif - -/* - * The default capacity here doesn't matter too much. The buffer always grows - * to hold whatever is written to it. Usually the encoder will stop adding at - * a frame or metadata block, then write that out and clear the buffer for the - * next one. - */ -static const uint32_t FLAC__BITWRITER_DEFAULT_CAPACITY = 32768u / sizeof(bwword); /* size in words */ -/* When growing, increment 4K at a time */ -static const uint32_t FLAC__BITWRITER_DEFAULT_INCREMENT = 4096u / sizeof(bwword); /* size in words */ - -#define FLAC__WORDS_TO_BITS(words) ((words) * FLAC__BITS_PER_WORD) -#define FLAC__TOTAL_BITS(bw) (FLAC__WORDS_TO_BITS((bw)->words) + (bw)->bits) - -struct FLAC__BitWriter { - bwword *buffer; - bwword accum; /* accumulator; bits are right-justified; when full, accum is appended to buffer */ - uint32_t capacity; /* capacity of buffer in words */ - uint32_t words; /* # of complete words in buffer */ - uint32_t bits; /* # of used bits in accum */ -}; - -/* * WATCHOUT: The current implementation only grows the buffer. */ -#ifndef __SUNPRO_C -static -#endif -FLAC__bool bitwriter_grow_(FLAC__BitWriter *bw, uint32_t bits_to_add) -{ - uint32_t new_capacity; - bwword *new_buffer; - - FLAC__ASSERT(0 != bw); - FLAC__ASSERT(0 != bw->buffer); - - /* calculate total words needed to store 'bits_to_add' additional bits */ - new_capacity = bw->words + ((bw->bits + bits_to_add + FLAC__BITS_PER_WORD - 1) / FLAC__BITS_PER_WORD); - - /* it's possible (due to pessimism in the growth estimation that - * leads to this call) that we don't actually need to grow - */ - if(bw->capacity >= new_capacity) - return true; - - /* round up capacity increase to the nearest FLAC__BITWRITER_DEFAULT_INCREMENT */ - if((new_capacity - bw->capacity) % FLAC__BITWRITER_DEFAULT_INCREMENT) - new_capacity += FLAC__BITWRITER_DEFAULT_INCREMENT - ((new_capacity - bw->capacity) % FLAC__BITWRITER_DEFAULT_INCREMENT); - /* make sure we got everything right */ - FLAC__ASSERT(0 == (new_capacity - bw->capacity) % FLAC__BITWRITER_DEFAULT_INCREMENT); - FLAC__ASSERT(new_capacity > bw->capacity); - FLAC__ASSERT(new_capacity >= bw->words + ((bw->bits + bits_to_add + FLAC__BITS_PER_WORD - 1) / FLAC__BITS_PER_WORD)); - - new_buffer = safe_realloc_mul_2op_(bw->buffer, sizeof(bwword), /*times*/new_capacity); - if(new_buffer == 0) - return false; - bw->buffer = new_buffer; - bw->capacity = new_capacity; - return true; -} - - -/*********************************************************************** - * - * Class constructor/destructor - * - ***********************************************************************/ - -FLAC__BitWriter *FLAC__bitwriter_new(void) -{ - FLAC__BitWriter *bw = calloc(1, sizeof(FLAC__BitWriter)); - /* note that calloc() sets all members to 0 for us */ - return bw; -} - -void FLAC__bitwriter_delete(FLAC__BitWriter *bw) -{ - FLAC__ASSERT(0 != bw); - - FLAC__bitwriter_free(bw); - free(bw); -} - -/*********************************************************************** - * - * Public class methods - * - ***********************************************************************/ - -FLAC__bool FLAC__bitwriter_init(FLAC__BitWriter *bw) -{ - FLAC__ASSERT(0 != bw); - - bw->words = bw->bits = 0; - bw->capacity = FLAC__BITWRITER_DEFAULT_CAPACITY; - bw->buffer = malloc(sizeof(bwword) * bw->capacity); - if(bw->buffer == 0) - return false; - - return true; -} - -void FLAC__bitwriter_free(FLAC__BitWriter *bw) -{ - FLAC__ASSERT(0 != bw); - - if(0 != bw->buffer) - free(bw->buffer); - bw->buffer = 0; - bw->capacity = 0; - bw->words = bw->bits = 0; -} - -void FLAC__bitwriter_clear(FLAC__BitWriter *bw) -{ - bw->words = bw->bits = 0; -} - -void FLAC__bitwriter_dump(const FLAC__BitWriter *bw, FILE *out) -{ - uint32_t i, j; - if(bw == 0) { - fprintf(out, "bitwriter is NULL\n"); - } - else { - fprintf(out, "bitwriter: capacity=%u words=%u bits=%u total_bits=%u\n", bw->capacity, bw->words, bw->bits, FLAC__TOTAL_BITS(bw)); - - for(i = 0; i < bw->words; i++) { - fprintf(out, "%08X: ", i); - for(j = 0; j < FLAC__BITS_PER_WORD; j++) - fprintf(out, "%01d", bw->buffer[i] & ((bwword)1 << (FLAC__BITS_PER_WORD-j-1)) ? 1:0); - fprintf(out, "\n"); - } - if(bw->bits > 0) { - fprintf(out, "%08X: ", i); - for(j = 0; j < bw->bits; j++) - fprintf(out, "%01d", bw->accum & ((bwword)1 << (bw->bits-j-1)) ? 1:0); - fprintf(out, "\n"); - } - } -} - -FLAC__bool FLAC__bitwriter_get_write_crc16(FLAC__BitWriter *bw, FLAC__uint16 *crc) -{ - const FLAC__byte *buffer; - size_t bytes; - - FLAC__ASSERT((bw->bits & 7) == 0); /* assert that we're byte-aligned */ - - if(!FLAC__bitwriter_get_buffer(bw, &buffer, &bytes)) - return false; - - *crc = (FLAC__uint16)FLAC__crc16(buffer, bytes); - FLAC__bitwriter_release_buffer(bw); - return true; -} - -FLAC__bool FLAC__bitwriter_get_write_crc8(FLAC__BitWriter *bw, FLAC__byte *crc) -{ - const FLAC__byte *buffer; - size_t bytes; - - FLAC__ASSERT((bw->bits & 7) == 0); /* assert that we're byte-aligned */ - - if(!FLAC__bitwriter_get_buffer(bw, &buffer, &bytes)) - return false; - - *crc = FLAC__crc8(buffer, bytes); - FLAC__bitwriter_release_buffer(bw); - return true; -} - -FLAC__bool FLAC__bitwriter_is_byte_aligned(const FLAC__BitWriter *bw) -{ - return ((bw->bits & 7) == 0); -} - -uint32_t FLAC__bitwriter_get_input_bits_unconsumed(const FLAC__BitWriter *bw) -{ - return FLAC__TOTAL_BITS(bw); -} - -FLAC__bool FLAC__bitwriter_get_buffer(FLAC__BitWriter *bw, const FLAC__byte **buffer, size_t *bytes) -{ - FLAC__ASSERT((bw->bits & 7) == 0); - /* double protection */ - if(bw->bits & 7) - return false; - /* if we have bits in the accumulator we have to flush those to the buffer first */ - if(bw->bits) { - FLAC__ASSERT(bw->words <= bw->capacity); - if(bw->words == bw->capacity && !bitwriter_grow_(bw, FLAC__BITS_PER_WORD)) - return false; - /* append bits as complete word to buffer, but don't change bw->accum or bw->bits */ - bw->buffer[bw->words] = SWAP_BE_WORD_TO_HOST(bw->accum << (FLAC__BITS_PER_WORD-bw->bits)); - } - /* now we can just return what we have */ - *buffer = (FLAC__byte*)bw->buffer; - *bytes = (FLAC__BYTES_PER_WORD * bw->words) + (bw->bits >> 3); - return true; -} - -void FLAC__bitwriter_release_buffer(FLAC__BitWriter *bw) -{ - /* nothing to do. in the future, strict checking of a 'writer-is-in- - * get-mode' flag could be added everywhere and then cleared here - */ - (void)bw; -} - -inline FLAC__bool FLAC__bitwriter_write_zeroes(FLAC__BitWriter *bw, uint32_t bits) -{ - uint32_t n; - - FLAC__ASSERT(0 != bw); - FLAC__ASSERT(0 != bw->buffer); - - if(bits == 0) - return true; - /* slightly pessimistic size check but faster than "<= bw->words + (bw->bits+bits+FLAC__BITS_PER_WORD-1)/FLAC__BITS_PER_WORD" */ - if(bw->capacity <= bw->words + bits && !bitwriter_grow_(bw, bits)) - return false; - /* first part gets to word alignment */ - if(bw->bits) { - n = flac_min(FLAC__BITS_PER_WORD - bw->bits, bits); - bw->accum <<= n; - bits -= n; - bw->bits += n; - if(bw->bits == FLAC__BITS_PER_WORD) { - bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum); - bw->bits = 0; - } - else - return true; - } - /* do whole words */ - while(bits >= FLAC__BITS_PER_WORD) { - bw->buffer[bw->words++] = 0; - bits -= FLAC__BITS_PER_WORD; - } - /* do any leftovers */ - if(bits > 0) { - bw->accum = 0; - bw->bits = bits; - } - return true; -} - -static inline FLAC__bool FLAC__bitwriter_write_raw_uint32_nocheck(FLAC__BitWriter *bw, FLAC__uint32 val, uint32_t bits) -{ - register uint32_t left; - - /* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */ - FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32); - - if(bw == 0 || bw->buffer == 0) - return false; - - if (bits > 32) - return false; - - if(bits == 0) - return true; - - FLAC__ASSERT((bits == 32) || (val>>bits == 0)); - - /* slightly pessimistic size check but faster than "<= bw->words + (bw->bits+bits+FLAC__BITS_PER_WORD-1)/FLAC__BITS_PER_WORD" */ - if(bw->capacity <= bw->words + bits && !bitwriter_grow_(bw, bits)) - return false; - - left = FLAC__BITS_PER_WORD - bw->bits; - if(bits < left) { - bw->accum <<= bits; - bw->accum |= val; - bw->bits += bits; - } - else if(bw->bits) { /* WATCHOUT: if bw->bits == 0, left==FLAC__BITS_PER_WORD and bw->accum<<=left is a NOP instead of setting to 0 */ - bw->accum <<= left; - bw->accum |= val >> (bw->bits = bits - left); - bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum); - bw->accum = val; /* unused top bits can contain garbage */ - } - else { /* at this point bits == FLAC__BITS_PER_WORD == 32 and bw->bits == 0 */ - bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST((bwword)val); - } - - return true; -} - -inline FLAC__bool FLAC__bitwriter_write_raw_uint32(FLAC__BitWriter *bw, FLAC__uint32 val, uint32_t bits) -{ - /* check that unused bits are unset */ - if((bits < 32) && (val>>bits != 0)) - return false; - - return FLAC__bitwriter_write_raw_uint32_nocheck(bw, val, bits); -} - -inline FLAC__bool FLAC__bitwriter_write_raw_int32(FLAC__BitWriter *bw, FLAC__int32 val, uint32_t bits) -{ - /* zero-out unused bits */ - if(bits < 32) - val &= (~(0xffffffff << bits)); - - return FLAC__bitwriter_write_raw_uint32_nocheck(bw, (FLAC__uint32)val, bits); -} - -inline FLAC__bool FLAC__bitwriter_write_raw_uint64(FLAC__BitWriter *bw, FLAC__uint64 val, uint32_t bits) -{ - /* this could be a little faster but it's not used for much */ - if(bits > 32) { - return - FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)(val>>32), bits-32) && - FLAC__bitwriter_write_raw_uint32_nocheck(bw, (FLAC__uint32)val, 32); - } - else - return FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)val, bits); -} - -inline FLAC__bool FLAC__bitwriter_write_raw_uint32_little_endian(FLAC__BitWriter *bw, FLAC__uint32 val) -{ - /* this doesn't need to be that fast as currently it is only used for vorbis comments */ - - if(!FLAC__bitwriter_write_raw_uint32_nocheck(bw, val & 0xff, 8)) - return false; - if(!FLAC__bitwriter_write_raw_uint32_nocheck(bw, (val>>8) & 0xff, 8)) - return false; - if(!FLAC__bitwriter_write_raw_uint32_nocheck(bw, (val>>16) & 0xff, 8)) - return false; - if(!FLAC__bitwriter_write_raw_uint32_nocheck(bw, val>>24, 8)) - return false; - - return true; -} - -inline FLAC__bool FLAC__bitwriter_write_byte_block(FLAC__BitWriter *bw, const FLAC__byte vals[], uint32_t nvals) -{ - uint32_t i; - - /* grow capacity upfront to prevent constant reallocation during writes */ - if(bw->capacity <= bw->words + nvals / (FLAC__BITS_PER_WORD / 8) + 1 && !bitwriter_grow_(bw, nvals * 8)) - return false; - - /* this could be faster but currently we don't need it to be since it's only used for writing metadata */ - for(i = 0; i < nvals; i++) { - if(!FLAC__bitwriter_write_raw_uint32_nocheck(bw, (FLAC__uint32)(vals[i]), 8)) - return false; - } - - return true; -} - -FLAC__bool FLAC__bitwriter_write_unary_unsigned(FLAC__BitWriter *bw, uint32_t val) -{ - if(val < 32) - return FLAC__bitwriter_write_raw_uint32_nocheck(bw, 1, ++val); - else - return - FLAC__bitwriter_write_zeroes(bw, val) && - FLAC__bitwriter_write_raw_uint32_nocheck(bw, 1, 1); -} - -uint32_t FLAC__bitwriter_rice_bits(FLAC__int32 val, uint32_t parameter) -{ - FLAC__uint32 uval; - - FLAC__ASSERT(parameter < 32); - - /* fold signed to uint32_t; actual formula is: negative(v)? -2v-1 : 2v */ - uval = val; - uval <<= 1; - uval ^= (val>>31); - - return 1 + parameter + (uval >> parameter); -} - -#if 0 /* UNUSED */ -uint32_t FLAC__bitwriter_golomb_bits_signed(int val, uint32_t parameter) -{ - uint32_t bits, msbs, uval; - uint32_t k; - - FLAC__ASSERT(parameter > 0); - - /* fold signed to uint32_t */ - if(val < 0) - uval = (uint32_t)(((-(++val)) << 1) + 1); - else - uval = (uint32_t)(val << 1); - - k = FLAC__bitmath_ilog2(parameter); - if(parameter == 1u<> k; - bits = 1 + k + msbs; - } - else { - uint32_t q, r, d; - - d = (1 << (k+1)) - parameter; - q = uval / parameter; - r = uval - (q * parameter); - - bits = 1 + q + k; - if(r >= d) - bits++; - } - return bits; -} - -uint32_t FLAC__bitwriter_golomb_bits_unsigned(uint32_t uval, uint32_t parameter) -{ - uint32_t bits, msbs; - uint32_t k; - - FLAC__ASSERT(parameter > 0); - - k = FLAC__bitmath_ilog2(parameter); - if(parameter == 1u<> k; - bits = 1 + k + msbs; - } - else { - uint32_t q, r, d; - - d = (1 << (k+1)) - parameter; - q = uval / parameter; - r = uval - (q * parameter); - - bits = 1 + q + k; - if(r >= d) - bits++; - } - return bits; -} -#endif /* UNUSED */ - -FLAC__bool FLAC__bitwriter_write_rice_signed(FLAC__BitWriter *bw, FLAC__int32 val, uint32_t parameter) -{ - uint32_t total_bits, interesting_bits, msbs; - FLAC__uint32 uval, pattern; - - FLAC__ASSERT(0 != bw); - FLAC__ASSERT(0 != bw->buffer); - FLAC__ASSERT(parameter < 32); - - /* fold signed to uint32_t; actual formula is: negative(v)? -2v-1 : 2v */ - uval = val; - uval <<= 1; - uval ^= (val>>31); - - msbs = uval >> parameter; - interesting_bits = 1 + parameter; - total_bits = interesting_bits + msbs; - pattern = 1 << parameter; /* the unary end bit */ - pattern |= (uval & ((1<> (31-parameter); /* ...then mask off the bits above the stop bit with val&=mask2 */ - FLAC__uint32 uval; - uint32_t left; - const uint32_t lsbits = 1 + parameter; - uint32_t msbits, total_bits; - - FLAC__ASSERT(0 != bw); - FLAC__ASSERT(0 != bw->buffer); - FLAC__ASSERT(parameter < 31); - /* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */ - FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32); - - while(nvals) { - /* fold signed to uint32_t; actual formula is: negative(v)? -2v-1 : 2v */ - uval = *vals; - uval <<= 1; - uval ^= (*vals>>31); - - msbits = uval >> parameter; - total_bits = lsbits + msbits; - - if(bw->bits && bw->bits + total_bits < FLAC__BITS_PER_WORD) { /* i.e. if the whole thing fits in the current bwword */ - /* ^^^ if bw->bits is 0 then we may have filled the buffer and have no free bwword to work in */ - bw->bits += total_bits; - uval |= mask1; /* set stop bit */ - uval &= mask2; /* mask off unused top bits */ - bw->accum <<= total_bits; - bw->accum |= uval; - } - else { - /* slightly pessimistic size check but faster than "<= bw->words + (bw->bits+msbits+lsbits+FLAC__BITS_PER_WORD-1)/FLAC__BITS_PER_WORD" */ - /* OPT: pessimism may cause flurry of false calls to grow_ which eat up all savings before it */ - if(bw->capacity <= bw->words + bw->bits + msbits + 1 /* lsbits always fit in 1 bwword */ && !bitwriter_grow_(bw, total_bits)) - return false; - - if(msbits) { - /* first part gets to word alignment */ - if(bw->bits) { - left = FLAC__BITS_PER_WORD - bw->bits; - if(msbits < left) { - bw->accum <<= msbits; - bw->bits += msbits; - goto break1; - } - else { - bw->accum <<= left; - msbits -= left; - bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum); - bw->bits = 0; - } - } - /* do whole words */ - while(msbits >= FLAC__BITS_PER_WORD) { - bw->buffer[bw->words++] = 0; - msbits -= FLAC__BITS_PER_WORD; - } - /* do any leftovers */ - if(msbits > 0) { - bw->accum = 0; - bw->bits = msbits; - } - } -break1: - uval |= mask1; /* set stop bit */ - uval &= mask2; /* mask off unused top bits */ - - left = FLAC__BITS_PER_WORD - bw->bits; - if(lsbits < left) { - bw->accum <<= lsbits; - bw->accum |= uval; - bw->bits += lsbits; - } - else { - /* if bw->bits == 0, left==FLAC__BITS_PER_WORD which will always - * be > lsbits (because of previous assertions) so it would have - * triggered the (lsbitsbits); - FLAC__ASSERT(left < FLAC__BITS_PER_WORD); - bw->accum <<= left; - bw->accum |= uval >> (bw->bits = lsbits - left); - bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum); - bw->accum = uval; /* unused top bits can contain garbage */ - } - } - vals++; - nvals--; - } - return true; -} - -#if 0 /* UNUSED */ -FLAC__bool FLAC__bitwriter_write_golomb_signed(FLAC__BitWriter *bw, int val, uint32_t parameter) -{ - uint32_t total_bits, msbs, uval; - uint32_t k; - - FLAC__ASSERT(0 != bw); - FLAC__ASSERT(0 != bw->buffer); - FLAC__ASSERT(parameter > 0); - - /* fold signed to uint32_t */ - if(val < 0) - uval = (uint32_t)(((-(++val)) << 1) + 1); - else - uval = (uint32_t)(val << 1); - - k = FLAC__bitmath_ilog2(parameter); - if(parameter == 1u<> k; - total_bits = 1 + k + msbs; - pattern = 1 << k; /* the unary end bit */ - pattern |= (uval & ((1u<= d) { - if(!FLAC__bitwriter_write_raw_uint32(bw, r+d, k+1)) - return false; - } - else { - if(!FLAC__bitwriter_write_raw_uint32(bw, r, k)) - return false; - } - } - return true; -} - -FLAC__bool FLAC__bitwriter_write_golomb_unsigned(FLAC__BitWriter *bw, uint32_t uval, uint32_t parameter) -{ - uint32_t total_bits, msbs; - uint32_t k; - - FLAC__ASSERT(0 != bw); - FLAC__ASSERT(0 != bw->buffer); - FLAC__ASSERT(parameter > 0); - - k = FLAC__bitmath_ilog2(parameter); - if(parameter == 1u<> k; - total_bits = 1 + k + msbs; - pattern = 1 << k; /* the unary end bit */ - pattern |= (uval & ((1u<= d) { - if(!FLAC__bitwriter_write_raw_uint32(bw, r+d, k+1)) - return false; - } - else { - if(!FLAC__bitwriter_write_raw_uint32(bw, r, k)) - return false; - } - } - return true; -} -#endif /* UNUSED */ - -FLAC__bool FLAC__bitwriter_write_utf8_uint32(FLAC__BitWriter *bw, FLAC__uint32 val) -{ - FLAC__bool ok = 1; - - FLAC__ASSERT(0 != bw); - FLAC__ASSERT(0 != bw->buffer); - - if((val & 0x80000000) != 0) /* this version only handles 31 bits */ - return false; - - if(val < 0x80) { - return FLAC__bitwriter_write_raw_uint32_nocheck(bw, val, 8); - } - else if(val < 0x800) { - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xC0 | (val>>6), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (val&0x3F), 8); - } - else if(val < 0x10000) { - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xE0 | (val>>12), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>6)&0x3F), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (val&0x3F), 8); - } - else if(val < 0x200000) { - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xF0 | (val>>18), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>12)&0x3F), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>6)&0x3F), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (val&0x3F), 8); - } - else if(val < 0x4000000) { - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xF8 | (val>>24), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>18)&0x3F), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>12)&0x3F), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>6)&0x3F), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (val&0x3F), 8); - } - else { - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xFC | (val>>30), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>24)&0x3F), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>18)&0x3F), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>12)&0x3F), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | ((val>>6)&0x3F), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (val&0x3F), 8); - } - - return ok; -} - -FLAC__bool FLAC__bitwriter_write_utf8_uint64(FLAC__BitWriter *bw, FLAC__uint64 val) -{ - FLAC__bool ok = 1; - - FLAC__ASSERT(0 != bw); - FLAC__ASSERT(0 != bw->buffer); - - if((val & FLAC__U64L(0xFFFFFFF000000000)) != 0) /* this version only handles 36 bits */ - return false; - - if(val < 0x80) { - return FLAC__bitwriter_write_raw_uint32_nocheck(bw, (FLAC__uint32)val, 8); - } - else if(val < 0x800) { - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xC0 | (FLAC__uint32)(val>>6), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8); - } - else if(val < 0x10000) { - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xE0 | (FLAC__uint32)(val>>12), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8); - } - else if(val < 0x200000) { - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xF0 | (FLAC__uint32)(val>>18), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8); - } - else if(val < 0x4000000) { - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xF8 | (FLAC__uint32)(val>>24), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8); - } - else if(val < 0x80000000) { - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xFC | (FLAC__uint32)(val>>30), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>24)&0x3F), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8); - } - else { - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0xFE, 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>30)&0x3F), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>24)&0x3F), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8); - ok &= FLAC__bitwriter_write_raw_uint32_nocheck(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8); - } - - return ok; -} - -FLAC__bool FLAC__bitwriter_zero_pad_to_byte_boundary(FLAC__BitWriter *bw) -{ - /* 0-pad to byte boundary */ - if(bw->bits & 7u) - return FLAC__bitwriter_write_zeroes(bw, 8 - (bw->bits & 7u)); - else - return true; -} - -/* These functions are declared inline in this file but are also callable as - * externs from elsewhere. - * According to the C99 spec, section 6.7.4, simply providing a function - * prototype in a header file without 'inline' and making the function inline - * in this file should be sufficient. - * Unfortunately, the Microsoft VS compiler doesn't pick them up externally. To - * fix that we add extern declarations here. - */ -extern FLAC__bool FLAC__bitwriter_write_zeroes(FLAC__BitWriter *bw, uint32_t bits); -extern FLAC__bool FLAC__bitwriter_write_raw_uint32(FLAC__BitWriter *bw, FLAC__uint32 val, uint32_t bits); -extern FLAC__bool FLAC__bitwriter_write_raw_int32(FLAC__BitWriter *bw, FLAC__int32 val, uint32_t bits); -extern FLAC__bool FLAC__bitwriter_write_raw_uint64(FLAC__BitWriter *bw, FLAC__uint64 val, uint32_t bits); -extern FLAC__bool FLAC__bitwriter_write_raw_uint32_little_endian(FLAC__BitWriter *bw, FLAC__uint32 val); -extern FLAC__bool FLAC__bitwriter_write_byte_block(FLAC__BitWriter *bw, const FLAC__byte vals[], uint32_t nvals); diff --git a/lib/flac/src/cpu.c b/lib/flac/src/cpu.c deleted file mode 100644 index 64da9cb..0000000 --- a/lib/flac/src/cpu.c +++ /dev/null @@ -1,285 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "private/cpu.h" -#include "share/compat.h" -#include -#include - -#if defined _MSC_VER -#include /* for __cpuid() and _xgetbv() */ -#elif defined __GNUC__ && defined HAVE_CPUID_H -#include /* for __get_cpuid() and __get_cpuid_max() */ -#endif - -#ifndef NDEBUG -#include -#define dfprintf fprintf -#else -/* This is bad practice, it should be a static void empty function */ -#define dfprintf(file, format, ...) -#endif - -#if defined FLAC__CPU_PPC -#include -#endif - -#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && (defined FLAC__HAS_NASM || FLAC__HAS_X86INTRIN) && !defined FLAC__NO_ASM - -/* these are flags in EDX of CPUID AX=00000001 */ -static const uint32_t FLAC__CPUINFO_X86_CPUID_CMOV = 0x00008000; -static const uint32_t FLAC__CPUINFO_X86_CPUID_MMX = 0x00800000; -static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE = 0x02000000; -static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE2 = 0x04000000; - -/* these are flags in ECX of CPUID AX=00000001 */ -static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE3 = 0x00000001; -static const uint32_t FLAC__CPUINFO_X86_CPUID_SSSE3 = 0x00000200; -static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE41 = 0x00080000; -static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE42 = 0x00100000; -static const uint32_t FLAC__CPUINFO_X86_CPUID_OSXSAVE = 0x08000000; -static const uint32_t FLAC__CPUINFO_X86_CPUID_AVX = 0x10000000; -static const uint32_t FLAC__CPUINFO_X86_CPUID_FMA = 0x00001000; - -/* these are flags in EBX of CPUID AX=00000007 */ -static const uint32_t FLAC__CPUINFO_X86_CPUID_AVX2 = 0x00000020; - -static uint32_t -cpu_xgetbv_x86(void) -{ -#if (defined _MSC_VER || defined __INTEL_COMPILER) && FLAC__AVX_SUPPORTED - return (uint32_t)_xgetbv(0); -#elif defined __GNUC__ - uint32_t lo, hi; - __asm__ volatile (".byte 0x0f, 0x01, 0xd0" : "=a"(lo), "=d"(hi) : "c" (0)); - return lo; -#else - return 0; -#endif -} - -static uint32_t -cpu_have_cpuid(void) -{ -#if defined FLAC__CPU_X86_64 || defined __i686__ || defined __SSE__ || (defined _M_IX86_FP && _M_IX86_FP > 0) - /* target CPU does have CPUID instruction */ - return 1; -#elif defined FLAC__HAS_NASM - return FLAC__cpu_have_cpuid_asm_ia32(); -#elif defined __GNUC__ && defined HAVE_CPUID_H - if (__get_cpuid_max(0, 0) != 0) - return 1; - else - return 0; -#elif defined _MSC_VER - FLAC__uint32 flags1, flags2; - __asm { - pushfd - pushfd - pop eax - mov flags1, eax - xor eax, 0x200000 - push eax - popfd - pushfd - pop eax - mov flags2, eax - popfd - } - if (((flags1^flags2) & 0x200000) != 0) - return 1; - else - return 0; -#else - return 0; -#endif -} - -static void -cpuinfo_x86(FLAC__uint32 level, FLAC__uint32 *eax, FLAC__uint32 *ebx, FLAC__uint32 *ecx, FLAC__uint32 *edx) -{ -#if defined _MSC_VER - int cpuinfo[4]; - int ext = level & 0x80000000; - __cpuid(cpuinfo, ext); - if ((uint32_t)cpuinfo[0] >= level) { -#if FLAC__AVX_SUPPORTED - __cpuidex(cpuinfo, level, 0); /* for AVX2 detection */ -#else - __cpuid(cpuinfo, level); /* some old compilers don't support __cpuidex */ -#endif - *eax = cpuinfo[0]; *ebx = cpuinfo[1]; *ecx = cpuinfo[2]; *edx = cpuinfo[3]; - return; - } -#elif defined __GNUC__ && defined HAVE_CPUID_H - FLAC__uint32 ext = level & 0x80000000; - __cpuid(ext, *eax, *ebx, *ecx, *edx); - if (*eax >= level) { - __cpuid_count(level, 0, *eax, *ebx, *ecx, *edx); - return; - } -#elif defined FLAC__HAS_NASM && defined FLAC__CPU_IA32 - FLAC__cpu_info_asm_ia32(level, eax, ebx, ecx, edx); - return; -#endif - *eax = *ebx = *ecx = *edx = 0; -} - -#endif - -static void -x86_cpu_info (FLAC__CPUInfo *info) -{ -#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && (defined FLAC__HAS_NASM || FLAC__HAS_X86INTRIN) && !defined FLAC__NO_ASM - FLAC__bool x86_osxsave = false; - FLAC__bool os_avx = false; - FLAC__uint32 flags_eax, flags_ebx, flags_ecx, flags_edx; - - info->use_asm = true; /* we assume a minimum of 80386 */ - if (!cpu_have_cpuid()) - return; - - cpuinfo_x86(0, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx); - info->x86.intel = (flags_ebx == 0x756E6547 && flags_edx == 0x49656E69 && flags_ecx == 0x6C65746E) ? true : false; /* GenuineIntel */ - cpuinfo_x86(1, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx); - - info->x86.cmov = (flags_edx & FLAC__CPUINFO_X86_CPUID_CMOV ) ? true : false; - info->x86.mmx = (flags_edx & FLAC__CPUINFO_X86_CPUID_MMX ) ? true : false; - info->x86.sse = (flags_edx & FLAC__CPUINFO_X86_CPUID_SSE ) ? true : false; - info->x86.sse2 = (flags_edx & FLAC__CPUINFO_X86_CPUID_SSE2 ) ? true : false; - info->x86.sse3 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSE3 ) ? true : false; - info->x86.ssse3 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSSE3) ? true : false; - info->x86.sse41 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSE41) ? true : false; - info->x86.sse42 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSE42) ? true : false; - - if (FLAC__AVX_SUPPORTED) { - x86_osxsave = (flags_ecx & FLAC__CPUINFO_X86_CPUID_OSXSAVE) ? true : false; - info->x86.avx = (flags_ecx & FLAC__CPUINFO_X86_CPUID_AVX ) ? true : false; - info->x86.fma = (flags_ecx & FLAC__CPUINFO_X86_CPUID_FMA ) ? true : false; - cpuinfo_x86(7, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx); - info->x86.avx2 = (flags_ebx & FLAC__CPUINFO_X86_CPUID_AVX2 ) ? true : false; - } - -#if defined FLAC__CPU_IA32 - dfprintf(stderr, "CPU info (IA-32):\n"); -#else - dfprintf(stderr, "CPU info (x86-64):\n"); -#endif - dfprintf(stderr, " CMOV ....... %c\n", info->x86.cmov ? 'Y' : 'n'); - dfprintf(stderr, " MMX ........ %c\n", info->x86.mmx ? 'Y' : 'n'); - dfprintf(stderr, " SSE ........ %c\n", info->x86.sse ? 'Y' : 'n'); - dfprintf(stderr, " SSE2 ....... %c\n", info->x86.sse2 ? 'Y' : 'n'); - dfprintf(stderr, " SSE3 ....... %c\n", info->x86.sse3 ? 'Y' : 'n'); - dfprintf(stderr, " SSSE3 ...... %c\n", info->x86.ssse3 ? 'Y' : 'n'); - dfprintf(stderr, " SSE41 ...... %c\n", info->x86.sse41 ? 'Y' : 'n'); - dfprintf(stderr, " SSE42 ...... %c\n", info->x86.sse42 ? 'Y' : 'n'); - - if (FLAC__AVX_SUPPORTED) { - dfprintf(stderr, " AVX ........ %c\n", info->x86.avx ? 'Y' : 'n'); - dfprintf(stderr, " FMA ........ %c\n", info->x86.fma ? 'Y' : 'n'); - dfprintf(stderr, " AVX2 ....... %c\n", info->x86.avx2 ? 'Y' : 'n'); - } - - /* - * now have to check for OS support of AVX instructions - */ - if (FLAC__AVX_SUPPORTED && info->x86.avx && x86_osxsave && (cpu_xgetbv_x86() & 0x6) == 0x6) { - os_avx = true; - } - if (os_avx) { - dfprintf(stderr, " AVX OS sup . %c\n", info->x86.avx ? 'Y' : 'n'); - } - if (!os_avx) { - /* no OS AVX support */ - info->x86.avx = false; - info->x86.avx2 = false; - info->x86.fma = false; - } -#else - info->use_asm = false; -#endif -} - -static void -ppc_cpu_info (FLAC__CPUInfo *info) -{ -#if defined FLAC__CPU_PPC -#ifndef PPC_FEATURE2_ARCH_3_00 -#define PPC_FEATURE2_ARCH_3_00 0x00800000 -#endif - -#ifndef PPC_FEATURE2_ARCH_2_07 -#define PPC_FEATURE2_ARCH_2_07 0x80000000 -#endif - - if (getauxval(AT_HWCAP2) & PPC_FEATURE2_ARCH_3_00) { - info->ppc.arch_3_00 = true; - } else if (getauxval(AT_HWCAP2) & PPC_FEATURE2_ARCH_2_07) { - info->ppc.arch_2_07 = true; - } -#else - info->ppc.arch_2_07 = false; - info->ppc.arch_3_00 = false; -#endif -} - -void FLAC__cpu_info (FLAC__CPUInfo *info) -{ - memset(info, 0, sizeof(*info)); - -#ifdef FLAC__CPU_IA32 - info->type = FLAC__CPUINFO_TYPE_IA32; -#elif defined FLAC__CPU_X86_64 - info->type = FLAC__CPUINFO_TYPE_X86_64; -#elif defined FLAC__CPU_PPC - info->type = FLAC__CPUINFO_TYPE_PPC; -#else - info->type = FLAC__CPUINFO_TYPE_UNKNOWN; -#endif - - switch (info->type) { - case FLAC__CPUINFO_TYPE_IA32: /* fallthrough */ - case FLAC__CPUINFO_TYPE_X86_64: - x86_cpu_info (info); - break; - case FLAC__CPUINFO_TYPE_PPC: - ppc_cpu_info (info); - break; - default: - info->use_asm = false; - break; - } -} diff --git a/lib/flac/src/crc.c b/lib/flac/src/crc.c deleted file mode 100644 index faa3496..0000000 --- a/lib/flac/src/crc.c +++ /dev/null @@ -1,436 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2018 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "private/crc.h" - -/* CRC-8, poly = x^8 + x^2 + x^1 + x^0, init = 0 */ - -FLAC__uint8 const FLAC__crc8_table[256] = { - 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, - 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, - 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, - 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, - 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, - 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, - 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, - 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, - 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, - 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, - 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, - 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, - 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, - 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, - 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, - 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, - 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, - 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, - 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, - 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, - 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, - 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, - 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, - 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, - 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, - 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, - 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, - 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, - 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, - 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, - 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, - 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 -}; - -/* CRC-16, poly = x^16 + x^15 + x^2 + x^0, init = 0 */ - -FLAC__uint16 const FLAC__crc16_table[8][256] = { - { 0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011, - 0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022, - 0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072, - 0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041, - 0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2, - 0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1, - 0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1, - 0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082, - 0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192, - 0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1, - 0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1, - 0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2, - 0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151, - 0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162, - 0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132, - 0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101, - 0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312, - 0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321, - 0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371, - 0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342, - 0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1, - 0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2, - 0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2, - 0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381, - 0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291, - 0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2, - 0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2, - 0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1, - 0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252, - 0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261, - 0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231, - 0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202 }, - - { 0x0000, 0x8603, 0x8c03, 0x0a00, 0x9803, 0x1e00, 0x1400, 0x9203, - 0xb003, 0x3600, 0x3c00, 0xba03, 0x2800, 0xae03, 0xa403, 0x2200, - 0xe003, 0x6600, 0x6c00, 0xea03, 0x7800, 0xfe03, 0xf403, 0x7200, - 0x5000, 0xd603, 0xdc03, 0x5a00, 0xc803, 0x4e00, 0x4400, 0xc203, - 0x4003, 0xc600, 0xcc00, 0x4a03, 0xd800, 0x5e03, 0x5403, 0xd200, - 0xf000, 0x7603, 0x7c03, 0xfa00, 0x6803, 0xee00, 0xe400, 0x6203, - 0xa000, 0x2603, 0x2c03, 0xaa00, 0x3803, 0xbe00, 0xb400, 0x3203, - 0x1003, 0x9600, 0x9c00, 0x1a03, 0x8800, 0x0e03, 0x0403, 0x8200, - 0x8006, 0x0605, 0x0c05, 0x8a06, 0x1805, 0x9e06, 0x9406, 0x1205, - 0x3005, 0xb606, 0xbc06, 0x3a05, 0xa806, 0x2e05, 0x2405, 0xa206, - 0x6005, 0xe606, 0xec06, 0x6a05, 0xf806, 0x7e05, 0x7405, 0xf206, - 0xd006, 0x5605, 0x5c05, 0xda06, 0x4805, 0xce06, 0xc406, 0x4205, - 0xc005, 0x4606, 0x4c06, 0xca05, 0x5806, 0xde05, 0xd405, 0x5206, - 0x7006, 0xf605, 0xfc05, 0x7a06, 0xe805, 0x6e06, 0x6406, 0xe205, - 0x2006, 0xa605, 0xac05, 0x2a06, 0xb805, 0x3e06, 0x3406, 0xb205, - 0x9005, 0x1606, 0x1c06, 0x9a05, 0x0806, 0x8e05, 0x8405, 0x0206, - 0x8009, 0x060a, 0x0c0a, 0x8a09, 0x180a, 0x9e09, 0x9409, 0x120a, - 0x300a, 0xb609, 0xbc09, 0x3a0a, 0xa809, 0x2e0a, 0x240a, 0xa209, - 0x600a, 0xe609, 0xec09, 0x6a0a, 0xf809, 0x7e0a, 0x740a, 0xf209, - 0xd009, 0x560a, 0x5c0a, 0xda09, 0x480a, 0xce09, 0xc409, 0x420a, - 0xc00a, 0x4609, 0x4c09, 0xca0a, 0x5809, 0xde0a, 0xd40a, 0x5209, - 0x7009, 0xf60a, 0xfc0a, 0x7a09, 0xe80a, 0x6e09, 0x6409, 0xe20a, - 0x2009, 0xa60a, 0xac0a, 0x2a09, 0xb80a, 0x3e09, 0x3409, 0xb20a, - 0x900a, 0x1609, 0x1c09, 0x9a0a, 0x0809, 0x8e0a, 0x840a, 0x0209, - 0x000f, 0x860c, 0x8c0c, 0x0a0f, 0x980c, 0x1e0f, 0x140f, 0x920c, - 0xb00c, 0x360f, 0x3c0f, 0xba0c, 0x280f, 0xae0c, 0xa40c, 0x220f, - 0xe00c, 0x660f, 0x6c0f, 0xea0c, 0x780f, 0xfe0c, 0xf40c, 0x720f, - 0x500f, 0xd60c, 0xdc0c, 0x5a0f, 0xc80c, 0x4e0f, 0x440f, 0xc20c, - 0x400c, 0xc60f, 0xcc0f, 0x4a0c, 0xd80f, 0x5e0c, 0x540c, 0xd20f, - 0xf00f, 0x760c, 0x7c0c, 0xfa0f, 0x680c, 0xee0f, 0xe40f, 0x620c, - 0xa00f, 0x260c, 0x2c0c, 0xaa0f, 0x380c, 0xbe0f, 0xb40f, 0x320c, - 0x100c, 0x960f, 0x9c0f, 0x1a0c, 0x880f, 0x0e0c, 0x040c, 0x820f }, - - { 0x0000, 0x8017, 0x802b, 0x003c, 0x8053, 0x0044, 0x0078, 0x806f, - 0x80a3, 0x00b4, 0x0088, 0x809f, 0x00f0, 0x80e7, 0x80db, 0x00cc, - 0x8143, 0x0154, 0x0168, 0x817f, 0x0110, 0x8107, 0x813b, 0x012c, - 0x01e0, 0x81f7, 0x81cb, 0x01dc, 0x81b3, 0x01a4, 0x0198, 0x818f, - 0x8283, 0x0294, 0x02a8, 0x82bf, 0x02d0, 0x82c7, 0x82fb, 0x02ec, - 0x0220, 0x8237, 0x820b, 0x021c, 0x8273, 0x0264, 0x0258, 0x824f, - 0x03c0, 0x83d7, 0x83eb, 0x03fc, 0x8393, 0x0384, 0x03b8, 0x83af, - 0x8363, 0x0374, 0x0348, 0x835f, 0x0330, 0x8327, 0x831b, 0x030c, - 0x8503, 0x0514, 0x0528, 0x853f, 0x0550, 0x8547, 0x857b, 0x056c, - 0x05a0, 0x85b7, 0x858b, 0x059c, 0x85f3, 0x05e4, 0x05d8, 0x85cf, - 0x0440, 0x8457, 0x846b, 0x047c, 0x8413, 0x0404, 0x0438, 0x842f, - 0x84e3, 0x04f4, 0x04c8, 0x84df, 0x04b0, 0x84a7, 0x849b, 0x048c, - 0x0780, 0x8797, 0x87ab, 0x07bc, 0x87d3, 0x07c4, 0x07f8, 0x87ef, - 0x8723, 0x0734, 0x0708, 0x871f, 0x0770, 0x8767, 0x875b, 0x074c, - 0x86c3, 0x06d4, 0x06e8, 0x86ff, 0x0690, 0x8687, 0x86bb, 0x06ac, - 0x0660, 0x8677, 0x864b, 0x065c, 0x8633, 0x0624, 0x0618, 0x860f, - 0x8a03, 0x0a14, 0x0a28, 0x8a3f, 0x0a50, 0x8a47, 0x8a7b, 0x0a6c, - 0x0aa0, 0x8ab7, 0x8a8b, 0x0a9c, 0x8af3, 0x0ae4, 0x0ad8, 0x8acf, - 0x0b40, 0x8b57, 0x8b6b, 0x0b7c, 0x8b13, 0x0b04, 0x0b38, 0x8b2f, - 0x8be3, 0x0bf4, 0x0bc8, 0x8bdf, 0x0bb0, 0x8ba7, 0x8b9b, 0x0b8c, - 0x0880, 0x8897, 0x88ab, 0x08bc, 0x88d3, 0x08c4, 0x08f8, 0x88ef, - 0x8823, 0x0834, 0x0808, 0x881f, 0x0870, 0x8867, 0x885b, 0x084c, - 0x89c3, 0x09d4, 0x09e8, 0x89ff, 0x0990, 0x8987, 0x89bb, 0x09ac, - 0x0960, 0x8977, 0x894b, 0x095c, 0x8933, 0x0924, 0x0918, 0x890f, - 0x0f00, 0x8f17, 0x8f2b, 0x0f3c, 0x8f53, 0x0f44, 0x0f78, 0x8f6f, - 0x8fa3, 0x0fb4, 0x0f88, 0x8f9f, 0x0ff0, 0x8fe7, 0x8fdb, 0x0fcc, - 0x8e43, 0x0e54, 0x0e68, 0x8e7f, 0x0e10, 0x8e07, 0x8e3b, 0x0e2c, - 0x0ee0, 0x8ef7, 0x8ecb, 0x0edc, 0x8eb3, 0x0ea4, 0x0e98, 0x8e8f, - 0x8d83, 0x0d94, 0x0da8, 0x8dbf, 0x0dd0, 0x8dc7, 0x8dfb, 0x0dec, - 0x0d20, 0x8d37, 0x8d0b, 0x0d1c, 0x8d73, 0x0d64, 0x0d58, 0x8d4f, - 0x0cc0, 0x8cd7, 0x8ceb, 0x0cfc, 0x8c93, 0x0c84, 0x0cb8, 0x8caf, - 0x8c63, 0x0c74, 0x0c48, 0x8c5f, 0x0c30, 0x8c27, 0x8c1b, 0x0c0c }, - - { 0x0000, 0x9403, 0xa803, 0x3c00, 0xd003, 0x4400, 0x7800, 0xec03, - 0x2003, 0xb400, 0x8800, 0x1c03, 0xf000, 0x6403, 0x5803, 0xcc00, - 0x4006, 0xd405, 0xe805, 0x7c06, 0x9005, 0x0406, 0x3806, 0xac05, - 0x6005, 0xf406, 0xc806, 0x5c05, 0xb006, 0x2405, 0x1805, 0x8c06, - 0x800c, 0x140f, 0x280f, 0xbc0c, 0x500f, 0xc40c, 0xf80c, 0x6c0f, - 0xa00f, 0x340c, 0x080c, 0x9c0f, 0x700c, 0xe40f, 0xd80f, 0x4c0c, - 0xc00a, 0x5409, 0x6809, 0xfc0a, 0x1009, 0x840a, 0xb80a, 0x2c09, - 0xe009, 0x740a, 0x480a, 0xdc09, 0x300a, 0xa409, 0x9809, 0x0c0a, - 0x801d, 0x141e, 0x281e, 0xbc1d, 0x501e, 0xc41d, 0xf81d, 0x6c1e, - 0xa01e, 0x341d, 0x081d, 0x9c1e, 0x701d, 0xe41e, 0xd81e, 0x4c1d, - 0xc01b, 0x5418, 0x6818, 0xfc1b, 0x1018, 0x841b, 0xb81b, 0x2c18, - 0xe018, 0x741b, 0x481b, 0xdc18, 0x301b, 0xa418, 0x9818, 0x0c1b, - 0x0011, 0x9412, 0xa812, 0x3c11, 0xd012, 0x4411, 0x7811, 0xec12, - 0x2012, 0xb411, 0x8811, 0x1c12, 0xf011, 0x6412, 0x5812, 0xcc11, - 0x4017, 0xd414, 0xe814, 0x7c17, 0x9014, 0x0417, 0x3817, 0xac14, - 0x6014, 0xf417, 0xc817, 0x5c14, 0xb017, 0x2414, 0x1814, 0x8c17, - 0x803f, 0x143c, 0x283c, 0xbc3f, 0x503c, 0xc43f, 0xf83f, 0x6c3c, - 0xa03c, 0x343f, 0x083f, 0x9c3c, 0x703f, 0xe43c, 0xd83c, 0x4c3f, - 0xc039, 0x543a, 0x683a, 0xfc39, 0x103a, 0x8439, 0xb839, 0x2c3a, - 0xe03a, 0x7439, 0x4839, 0xdc3a, 0x3039, 0xa43a, 0x983a, 0x0c39, - 0x0033, 0x9430, 0xa830, 0x3c33, 0xd030, 0x4433, 0x7833, 0xec30, - 0x2030, 0xb433, 0x8833, 0x1c30, 0xf033, 0x6430, 0x5830, 0xcc33, - 0x4035, 0xd436, 0xe836, 0x7c35, 0x9036, 0x0435, 0x3835, 0xac36, - 0x6036, 0xf435, 0xc835, 0x5c36, 0xb035, 0x2436, 0x1836, 0x8c35, - 0x0022, 0x9421, 0xa821, 0x3c22, 0xd021, 0x4422, 0x7822, 0xec21, - 0x2021, 0xb422, 0x8822, 0x1c21, 0xf022, 0x6421, 0x5821, 0xcc22, - 0x4024, 0xd427, 0xe827, 0x7c24, 0x9027, 0x0424, 0x3824, 0xac27, - 0x6027, 0xf424, 0xc824, 0x5c27, 0xb024, 0x2427, 0x1827, 0x8c24, - 0x802e, 0x142d, 0x282d, 0xbc2e, 0x502d, 0xc42e, 0xf82e, 0x6c2d, - 0xa02d, 0x342e, 0x082e, 0x9c2d, 0x702e, 0xe42d, 0xd82d, 0x4c2e, - 0xc028, 0x542b, 0x682b, 0xfc28, 0x102b, 0x8428, 0xb828, 0x2c2b, - 0xe02b, 0x7428, 0x4828, 0xdc2b, 0x3028, 0xa42b, 0x982b, 0x0c28 }, - - { 0x0000, 0x807b, 0x80f3, 0x0088, 0x81e3, 0x0198, 0x0110, 0x816b, - 0x83c3, 0x03b8, 0x0330, 0x834b, 0x0220, 0x825b, 0x82d3, 0x02a8, - 0x8783, 0x07f8, 0x0770, 0x870b, 0x0660, 0x861b, 0x8693, 0x06e8, - 0x0440, 0x843b, 0x84b3, 0x04c8, 0x85a3, 0x05d8, 0x0550, 0x852b, - 0x8f03, 0x0f78, 0x0ff0, 0x8f8b, 0x0ee0, 0x8e9b, 0x8e13, 0x0e68, - 0x0cc0, 0x8cbb, 0x8c33, 0x0c48, 0x8d23, 0x0d58, 0x0dd0, 0x8dab, - 0x0880, 0x88fb, 0x8873, 0x0808, 0x8963, 0x0918, 0x0990, 0x89eb, - 0x8b43, 0x0b38, 0x0bb0, 0x8bcb, 0x0aa0, 0x8adb, 0x8a53, 0x0a28, - 0x9e03, 0x1e78, 0x1ef0, 0x9e8b, 0x1fe0, 0x9f9b, 0x9f13, 0x1f68, - 0x1dc0, 0x9dbb, 0x9d33, 0x1d48, 0x9c23, 0x1c58, 0x1cd0, 0x9cab, - 0x1980, 0x99fb, 0x9973, 0x1908, 0x9863, 0x1818, 0x1890, 0x98eb, - 0x9a43, 0x1a38, 0x1ab0, 0x9acb, 0x1ba0, 0x9bdb, 0x9b53, 0x1b28, - 0x1100, 0x917b, 0x91f3, 0x1188, 0x90e3, 0x1098, 0x1010, 0x906b, - 0x92c3, 0x12b8, 0x1230, 0x924b, 0x1320, 0x935b, 0x93d3, 0x13a8, - 0x9683, 0x16f8, 0x1670, 0x960b, 0x1760, 0x971b, 0x9793, 0x17e8, - 0x1540, 0x953b, 0x95b3, 0x15c8, 0x94a3, 0x14d8, 0x1450, 0x942b, - 0xbc03, 0x3c78, 0x3cf0, 0xbc8b, 0x3de0, 0xbd9b, 0xbd13, 0x3d68, - 0x3fc0, 0xbfbb, 0xbf33, 0x3f48, 0xbe23, 0x3e58, 0x3ed0, 0xbeab, - 0x3b80, 0xbbfb, 0xbb73, 0x3b08, 0xba63, 0x3a18, 0x3a90, 0xbaeb, - 0xb843, 0x3838, 0x38b0, 0xb8cb, 0x39a0, 0xb9db, 0xb953, 0x3928, - 0x3300, 0xb37b, 0xb3f3, 0x3388, 0xb2e3, 0x3298, 0x3210, 0xb26b, - 0xb0c3, 0x30b8, 0x3030, 0xb04b, 0x3120, 0xb15b, 0xb1d3, 0x31a8, - 0xb483, 0x34f8, 0x3470, 0xb40b, 0x3560, 0xb51b, 0xb593, 0x35e8, - 0x3740, 0xb73b, 0xb7b3, 0x37c8, 0xb6a3, 0x36d8, 0x3650, 0xb62b, - 0x2200, 0xa27b, 0xa2f3, 0x2288, 0xa3e3, 0x2398, 0x2310, 0xa36b, - 0xa1c3, 0x21b8, 0x2130, 0xa14b, 0x2020, 0xa05b, 0xa0d3, 0x20a8, - 0xa583, 0x25f8, 0x2570, 0xa50b, 0x2460, 0xa41b, 0xa493, 0x24e8, - 0x2640, 0xa63b, 0xa6b3, 0x26c8, 0xa7a3, 0x27d8, 0x2750, 0xa72b, - 0xad03, 0x2d78, 0x2df0, 0xad8b, 0x2ce0, 0xac9b, 0xac13, 0x2c68, - 0x2ec0, 0xaebb, 0xae33, 0x2e48, 0xaf23, 0x2f58, 0x2fd0, 0xafab, - 0x2a80, 0xaafb, 0xaa73, 0x2a08, 0xab63, 0x2b18, 0x2b90, 0xabeb, - 0xa943, 0x2938, 0x29b0, 0xa9cb, 0x28a0, 0xa8db, 0xa853, 0x2828 }, - - { 0x0000, 0xf803, 0x7003, 0x8800, 0xe006, 0x1805, 0x9005, 0x6806, - 0x4009, 0xb80a, 0x300a, 0xc809, 0xa00f, 0x580c, 0xd00c, 0x280f, - 0x8012, 0x7811, 0xf011, 0x0812, 0x6014, 0x9817, 0x1017, 0xe814, - 0xc01b, 0x3818, 0xb018, 0x481b, 0x201d, 0xd81e, 0x501e, 0xa81d, - 0x8021, 0x7822, 0xf022, 0x0821, 0x6027, 0x9824, 0x1024, 0xe827, - 0xc028, 0x382b, 0xb02b, 0x4828, 0x202e, 0xd82d, 0x502d, 0xa82e, - 0x0033, 0xf830, 0x7030, 0x8833, 0xe035, 0x1836, 0x9036, 0x6835, - 0x403a, 0xb839, 0x3039, 0xc83a, 0xa03c, 0x583f, 0xd03f, 0x283c, - 0x8047, 0x7844, 0xf044, 0x0847, 0x6041, 0x9842, 0x1042, 0xe841, - 0xc04e, 0x384d, 0xb04d, 0x484e, 0x2048, 0xd84b, 0x504b, 0xa848, - 0x0055, 0xf856, 0x7056, 0x8855, 0xe053, 0x1850, 0x9050, 0x6853, - 0x405c, 0xb85f, 0x305f, 0xc85c, 0xa05a, 0x5859, 0xd059, 0x285a, - 0x0066, 0xf865, 0x7065, 0x8866, 0xe060, 0x1863, 0x9063, 0x6860, - 0x406f, 0xb86c, 0x306c, 0xc86f, 0xa069, 0x586a, 0xd06a, 0x2869, - 0x8074, 0x7877, 0xf077, 0x0874, 0x6072, 0x9871, 0x1071, 0xe872, - 0xc07d, 0x387e, 0xb07e, 0x487d, 0x207b, 0xd878, 0x5078, 0xa87b, - 0x808b, 0x7888, 0xf088, 0x088b, 0x608d, 0x988e, 0x108e, 0xe88d, - 0xc082, 0x3881, 0xb081, 0x4882, 0x2084, 0xd887, 0x5087, 0xa884, - 0x0099, 0xf89a, 0x709a, 0x8899, 0xe09f, 0x189c, 0x909c, 0x689f, - 0x4090, 0xb893, 0x3093, 0xc890, 0xa096, 0x5895, 0xd095, 0x2896, - 0x00aa, 0xf8a9, 0x70a9, 0x88aa, 0xe0ac, 0x18af, 0x90af, 0x68ac, - 0x40a3, 0xb8a0, 0x30a0, 0xc8a3, 0xa0a5, 0x58a6, 0xd0a6, 0x28a5, - 0x80b8, 0x78bb, 0xf0bb, 0x08b8, 0x60be, 0x98bd, 0x10bd, 0xe8be, - 0xc0b1, 0x38b2, 0xb0b2, 0x48b1, 0x20b7, 0xd8b4, 0x50b4, 0xa8b7, - 0x00cc, 0xf8cf, 0x70cf, 0x88cc, 0xe0ca, 0x18c9, 0x90c9, 0x68ca, - 0x40c5, 0xb8c6, 0x30c6, 0xc8c5, 0xa0c3, 0x58c0, 0xd0c0, 0x28c3, - 0x80de, 0x78dd, 0xf0dd, 0x08de, 0x60d8, 0x98db, 0x10db, 0xe8d8, - 0xc0d7, 0x38d4, 0xb0d4, 0x48d7, 0x20d1, 0xd8d2, 0x50d2, 0xa8d1, - 0x80ed, 0x78ee, 0xf0ee, 0x08ed, 0x60eb, 0x98e8, 0x10e8, 0xe8eb, - 0xc0e4, 0x38e7, 0xb0e7, 0x48e4, 0x20e2, 0xd8e1, 0x50e1, 0xa8e2, - 0x00ff, 0xf8fc, 0x70fc, 0x88ff, 0xe0f9, 0x18fa, 0x90fa, 0x68f9, - 0x40f6, 0xb8f5, 0x30f5, 0xc8f6, 0xa0f0, 0x58f3, 0xd0f3, 0x28f0 }, - - { 0x0000, 0x8113, 0x8223, 0x0330, 0x8443, 0x0550, 0x0660, 0x8773, - 0x8883, 0x0990, 0x0aa0, 0x8bb3, 0x0cc0, 0x8dd3, 0x8ee3, 0x0ff0, - 0x9103, 0x1010, 0x1320, 0x9233, 0x1540, 0x9453, 0x9763, 0x1670, - 0x1980, 0x9893, 0x9ba3, 0x1ab0, 0x9dc3, 0x1cd0, 0x1fe0, 0x9ef3, - 0xa203, 0x2310, 0x2020, 0xa133, 0x2640, 0xa753, 0xa463, 0x2570, - 0x2a80, 0xab93, 0xa8a3, 0x29b0, 0xaec3, 0x2fd0, 0x2ce0, 0xadf3, - 0x3300, 0xb213, 0xb123, 0x3030, 0xb743, 0x3650, 0x3560, 0xb473, - 0xbb83, 0x3a90, 0x39a0, 0xb8b3, 0x3fc0, 0xbed3, 0xbde3, 0x3cf0, - 0xc403, 0x4510, 0x4620, 0xc733, 0x4040, 0xc153, 0xc263, 0x4370, - 0x4c80, 0xcd93, 0xcea3, 0x4fb0, 0xc8c3, 0x49d0, 0x4ae0, 0xcbf3, - 0x5500, 0xd413, 0xd723, 0x5630, 0xd143, 0x5050, 0x5360, 0xd273, - 0xdd83, 0x5c90, 0x5fa0, 0xdeb3, 0x59c0, 0xd8d3, 0xdbe3, 0x5af0, - 0x6600, 0xe713, 0xe423, 0x6530, 0xe243, 0x6350, 0x6060, 0xe173, - 0xee83, 0x6f90, 0x6ca0, 0xedb3, 0x6ac0, 0xebd3, 0xe8e3, 0x69f0, - 0xf703, 0x7610, 0x7520, 0xf433, 0x7340, 0xf253, 0xf163, 0x7070, - 0x7f80, 0xfe93, 0xfda3, 0x7cb0, 0xfbc3, 0x7ad0, 0x79e0, 0xf8f3, - 0x0803, 0x8910, 0x8a20, 0x0b33, 0x8c40, 0x0d53, 0x0e63, 0x8f70, - 0x8080, 0x0193, 0x02a3, 0x83b0, 0x04c3, 0x85d0, 0x86e0, 0x07f3, - 0x9900, 0x1813, 0x1b23, 0x9a30, 0x1d43, 0x9c50, 0x9f60, 0x1e73, - 0x1183, 0x9090, 0x93a0, 0x12b3, 0x95c0, 0x14d3, 0x17e3, 0x96f0, - 0xaa00, 0x2b13, 0x2823, 0xa930, 0x2e43, 0xaf50, 0xac60, 0x2d73, - 0x2283, 0xa390, 0xa0a0, 0x21b3, 0xa6c0, 0x27d3, 0x24e3, 0xa5f0, - 0x3b03, 0xba10, 0xb920, 0x3833, 0xbf40, 0x3e53, 0x3d63, 0xbc70, - 0xb380, 0x3293, 0x31a3, 0xb0b0, 0x37c3, 0xb6d0, 0xb5e0, 0x34f3, - 0xcc00, 0x4d13, 0x4e23, 0xcf30, 0x4843, 0xc950, 0xca60, 0x4b73, - 0x4483, 0xc590, 0xc6a0, 0x47b3, 0xc0c0, 0x41d3, 0x42e3, 0xc3f0, - 0x5d03, 0xdc10, 0xdf20, 0x5e33, 0xd940, 0x5853, 0x5b63, 0xda70, - 0xd580, 0x5493, 0x57a3, 0xd6b0, 0x51c3, 0xd0d0, 0xd3e0, 0x52f3, - 0x6e03, 0xef10, 0xec20, 0x6d33, 0xea40, 0x6b53, 0x6863, 0xe970, - 0xe680, 0x6793, 0x64a3, 0xe5b0, 0x62c3, 0xe3d0, 0xe0e0, 0x61f3, - 0xff00, 0x7e13, 0x7d23, 0xfc30, 0x7b43, 0xfa50, 0xf960, 0x7873, - 0x7783, 0xf690, 0xf5a0, 0x74b3, 0xf3c0, 0x72d3, 0x71e3, 0xf0f0 }, - - { 0x0000, 0x1006, 0x200c, 0x300a, 0x4018, 0x501e, 0x6014, 0x7012, - 0x8030, 0x9036, 0xa03c, 0xb03a, 0xc028, 0xd02e, 0xe024, 0xf022, - 0x8065, 0x9063, 0xa069, 0xb06f, 0xc07d, 0xd07b, 0xe071, 0xf077, - 0x0055, 0x1053, 0x2059, 0x305f, 0x404d, 0x504b, 0x6041, 0x7047, - 0x80cf, 0x90c9, 0xa0c3, 0xb0c5, 0xc0d7, 0xd0d1, 0xe0db, 0xf0dd, - 0x00ff, 0x10f9, 0x20f3, 0x30f5, 0x40e7, 0x50e1, 0x60eb, 0x70ed, - 0x00aa, 0x10ac, 0x20a6, 0x30a0, 0x40b2, 0x50b4, 0x60be, 0x70b8, - 0x809a, 0x909c, 0xa096, 0xb090, 0xc082, 0xd084, 0xe08e, 0xf088, - 0x819b, 0x919d, 0xa197, 0xb191, 0xc183, 0xd185, 0xe18f, 0xf189, - 0x01ab, 0x11ad, 0x21a7, 0x31a1, 0x41b3, 0x51b5, 0x61bf, 0x71b9, - 0x01fe, 0x11f8, 0x21f2, 0x31f4, 0x41e6, 0x51e0, 0x61ea, 0x71ec, - 0x81ce, 0x91c8, 0xa1c2, 0xb1c4, 0xc1d6, 0xd1d0, 0xe1da, 0xf1dc, - 0x0154, 0x1152, 0x2158, 0x315e, 0x414c, 0x514a, 0x6140, 0x7146, - 0x8164, 0x9162, 0xa168, 0xb16e, 0xc17c, 0xd17a, 0xe170, 0xf176, - 0x8131, 0x9137, 0xa13d, 0xb13b, 0xc129, 0xd12f, 0xe125, 0xf123, - 0x0101, 0x1107, 0x210d, 0x310b, 0x4119, 0x511f, 0x6115, 0x7113, - 0x8333, 0x9335, 0xa33f, 0xb339, 0xc32b, 0xd32d, 0xe327, 0xf321, - 0x0303, 0x1305, 0x230f, 0x3309, 0x431b, 0x531d, 0x6317, 0x7311, - 0x0356, 0x1350, 0x235a, 0x335c, 0x434e, 0x5348, 0x6342, 0x7344, - 0x8366, 0x9360, 0xa36a, 0xb36c, 0xc37e, 0xd378, 0xe372, 0xf374, - 0x03fc, 0x13fa, 0x23f0, 0x33f6, 0x43e4, 0x53e2, 0x63e8, 0x73ee, - 0x83cc, 0x93ca, 0xa3c0, 0xb3c6, 0xc3d4, 0xd3d2, 0xe3d8, 0xf3de, - 0x8399, 0x939f, 0xa395, 0xb393, 0xc381, 0xd387, 0xe38d, 0xf38b, - 0x03a9, 0x13af, 0x23a5, 0x33a3, 0x43b1, 0x53b7, 0x63bd, 0x73bb, - 0x02a8, 0x12ae, 0x22a4, 0x32a2, 0x42b0, 0x52b6, 0x62bc, 0x72ba, - 0x8298, 0x929e, 0xa294, 0xb292, 0xc280, 0xd286, 0xe28c, 0xf28a, - 0x82cd, 0x92cb, 0xa2c1, 0xb2c7, 0xc2d5, 0xd2d3, 0xe2d9, 0xf2df, - 0x02fd, 0x12fb, 0x22f1, 0x32f7, 0x42e5, 0x52e3, 0x62e9, 0x72ef, - 0x8267, 0x9261, 0xa26b, 0xb26d, 0xc27f, 0xd279, 0xe273, 0xf275, - 0x0257, 0x1251, 0x225b, 0x325d, 0x424f, 0x5249, 0x6243, 0x7245, - 0x0202, 0x1204, 0x220e, 0x3208, 0x421a, 0x521c, 0x6216, 0x7210, - 0x8232, 0x9234, 0xa23e, 0xb238, 0xc22a, 0xd22c, 0xe226, 0xf220 } -}; - -#if 0 -void FLAC__crc16_init_table(void) -{ - int i, j; - FLAC__uint16 polynomial, crc; - polynomial = 0x8005; - - for(i = 0; i <= 0xFF; i++){ - crc = i << 8; - - for(j = 0; j < 8; j++) - crc = (crc << 1) ^ (crc & (1 << 15) ? polynomial : 0); - - FLAC__crc16_table[0][i] = crc; - } - - for(i = 0; i <= 0xFF; i++) - for(j = 1; j < 8; j++) - FLAC__crc16_table[j][i] = FLAC__crc16_table[0][FLAC__crc16_table[j - 1][i] >> 8] ^ (FLAC__crc16_table[j - 1][i] << 8); -} -#endif - -FLAC__uint8 FLAC__crc8(const FLAC__byte *data, uint32_t len) -{ - FLAC__uint8 crc = 0; - - while(len--) - crc = FLAC__crc8_table[crc ^ *data++]; - - return crc; -} - -FLAC__uint16 FLAC__crc16(const FLAC__byte *data, uint32_t len) -{ - FLAC__uint16 crc = 0; - - while(len >= 8){ - crc ^= data[0] << 8 | data[1]; - - crc = FLAC__crc16_table[7][crc >> 8] ^ FLAC__crc16_table[6][crc & 0xFF] ^ - FLAC__crc16_table[5][data[2] ] ^ FLAC__crc16_table[4][data[3] ] ^ - FLAC__crc16_table[3][data[4] ] ^ FLAC__crc16_table[2][data[5] ] ^ - FLAC__crc16_table[1][data[6] ] ^ FLAC__crc16_table[0][data[7] ]; - - data += 8; - len -= 8; - } - - while(len--) - crc = (crc<<8) ^ FLAC__crc16_table[0][(crc>>8) ^ *data++]; - - return crc; -} - -FLAC__uint16 FLAC__crc16_update_words32(const FLAC__uint32 *words, uint32_t len, FLAC__uint16 crc) -{ - while (len >= 2) { - crc ^= words[0] >> 16; - - crc = FLAC__crc16_table[7][crc >> 8 ] ^ FLAC__crc16_table[6][crc & 0xFF ] ^ - FLAC__crc16_table[5][(words[0] >> 8) & 0xFF] ^ FLAC__crc16_table[4][ words[0] & 0xFF] ^ - FLAC__crc16_table[3][ words[1] >> 24 ] ^ FLAC__crc16_table[2][(words[1] >> 16) & 0xFF] ^ - FLAC__crc16_table[1][(words[1] >> 8) & 0xFF] ^ FLAC__crc16_table[0][ words[1] & 0xFF]; - - words += 2; - len -= 2; - } - - if (len) { - crc ^= words[0] >> 16; - - crc = FLAC__crc16_table[3][crc >> 8 ] ^ FLAC__crc16_table[2][crc & 0xFF ] ^ - FLAC__crc16_table[1][(words[0] >> 8) & 0xFF] ^ FLAC__crc16_table[0][words[0] & 0xFF]; - } - - return crc; -} - -FLAC__uint16 FLAC__crc16_update_words64(const FLAC__uint64 *words, uint32_t len, FLAC__uint16 crc) -{ - while (len--) { - crc ^= words[0] >> 48; - - crc = FLAC__crc16_table[7][crc >> 8 ] ^ FLAC__crc16_table[6][crc & 0xFF ] ^ - FLAC__crc16_table[5][(words[0] >> 40) & 0xFF] ^ FLAC__crc16_table[4][(words[0] >> 32) & 0xFF] ^ - FLAC__crc16_table[3][(words[0] >> 24) & 0xFF] ^ FLAC__crc16_table[2][(words[0] >> 16) & 0xFF] ^ - FLAC__crc16_table[1][(words[0] >> 8) & 0xFF] ^ FLAC__crc16_table[0][ words[0] & 0xFF]; - - words++; - } - - return crc; -} diff --git a/lib/flac/src/fixed.c b/lib/flac/src/fixed.c deleted file mode 100644 index 98f42a2..0000000 --- a/lib/flac/src/fixed.c +++ /dev/null @@ -1,395 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include "share/compat.h" -#include "private/bitmath.h" -#include "private/fixed.h" -#include "private/macros.h" -#include "FLAC/assert.h" - -#ifdef local_abs -#undef local_abs -#endif -#define local_abs(x) ((uint32_t)((x)<0? -(x) : (x))) - -#ifdef FLAC__INTEGER_ONLY_LIBRARY -/* rbps stands for residual bits per sample - * - * (ln(2) * err) - * rbps = log (-----------) - * 2 ( n ) - */ -static FLAC__fixedpoint local__compute_rbps_integerized(FLAC__uint32 err, FLAC__uint32 n) -{ - FLAC__uint32 rbps; - uint32_t bits; /* the number of bits required to represent a number */ - int fracbits; /* the number of bits of rbps that comprise the fractional part */ - - FLAC__ASSERT(sizeof(rbps) == sizeof(FLAC__fixedpoint)); - FLAC__ASSERT(err > 0); - FLAC__ASSERT(n > 0); - - FLAC__ASSERT(n <= FLAC__MAX_BLOCK_SIZE); - if(err <= n) - return 0; - /* - * The above two things tell us 1) n fits in 16 bits; 2) err/n > 1. - * These allow us later to know we won't lose too much precision in the - * fixed-point division (err< 0); - bits = FLAC__bitmath_ilog2(err)+1; - if(bits > 16) { - err >>= (bits-16); - fracbits -= (bits-16); - } - rbps = (FLAC__uint32)err; - - /* Multiply by fixed-point version of ln(2), with 16 fractional bits */ - rbps *= FLAC__FP_LN2; - fracbits += 16; - FLAC__ASSERT(fracbits >= 0); - - /* FLAC__fixedpoint_log2 requires fracbits%4 to be 0 */ - { - const int f = fracbits & 3; - if(f) { - rbps >>= f; - fracbits -= f; - } - } - - rbps = FLAC__fixedpoint_log2(rbps, fracbits, (uint32_t)(-1)); - - if(rbps == 0) - return 0; - - /* - * The return value must have 16 fractional bits. Since the whole part - * of the base-2 log of a 32 bit number must fit in 5 bits, and fracbits - * must be >= -3, these assertion allows us to be able to shift rbps - * left if necessary to get 16 fracbits without losing any bits of the - * whole part of rbps. - * - * There is a slight chance due to accumulated error that the whole part - * will require 6 bits, so we use 6 in the assertion. Really though as - * long as it fits in 13 bits (32 - (16 - (-3))) we are fine. - */ - FLAC__ASSERT((int)FLAC__bitmath_ilog2(rbps)+1 <= fracbits + 6); - FLAC__ASSERT(fracbits >= -3); - - /* now shift the decimal point into place */ - if(fracbits < 16) - return rbps << (16-fracbits); - else if(fracbits > 16) - return rbps >> (fracbits-16); - else - return rbps; -} - -static FLAC__fixedpoint local__compute_rbps_wide_integerized(FLAC__uint64 err, FLAC__uint32 n) -{ - FLAC__uint32 rbps; - uint32_t bits; /* the number of bits required to represent a number */ - int fracbits; /* the number of bits of rbps that comprise the fractional part */ - - FLAC__ASSERT(sizeof(rbps) == sizeof(FLAC__fixedpoint)); - FLAC__ASSERT(err > 0); - FLAC__ASSERT(n > 0); - - FLAC__ASSERT(n <= FLAC__MAX_BLOCK_SIZE); - if(err <= n) - return 0; - /* - * The above two things tell us 1) n fits in 16 bits; 2) err/n > 1. - * These allow us later to know we won't lose too much precision in the - * fixed-point division (err< 0); - bits = FLAC__bitmath_ilog2_wide(err)+1; - if(bits > 16) { - err >>= (bits-16); - fracbits -= (bits-16); - } - rbps = (FLAC__uint32)err; - - /* Multiply by fixed-point version of ln(2), with 16 fractional bits */ - rbps *= FLAC__FP_LN2; - fracbits += 16; - FLAC__ASSERT(fracbits >= 0); - - /* FLAC__fixedpoint_log2 requires fracbits%4 to be 0 */ - { - const int f = fracbits & 3; - if(f) { - rbps >>= f; - fracbits -= f; - } - } - - rbps = FLAC__fixedpoint_log2(rbps, fracbits, (uint32_t)(-1)); - - if(rbps == 0) - return 0; - - /* - * The return value must have 16 fractional bits. Since the whole part - * of the base-2 log of a 32 bit number must fit in 5 bits, and fracbits - * must be >= -3, these assertion allows us to be able to shift rbps - * left if necessary to get 16 fracbits without losing any bits of the - * whole part of rbps. - * - * There is a slight chance due to accumulated error that the whole part - * will require 6 bits, so we use 6 in the assertion. Really though as - * long as it fits in 13 bits (32 - (16 - (-3))) we are fine. - */ - FLAC__ASSERT((int)FLAC__bitmath_ilog2(rbps)+1 <= fracbits + 6); - FLAC__ASSERT(fracbits >= -3); - - /* now shift the decimal point into place */ - if(fracbits < 16) - return rbps << (16-fracbits); - else if(fracbits > 16) - return rbps >> (fracbits-16); - else - return rbps; -} -#endif - -#ifndef FLAC__INTEGER_ONLY_LIBRARY -uint32_t FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) -#else -uint32_t FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) -#endif -{ - FLAC__int32 last_error_0 = data[-1]; - FLAC__int32 last_error_1 = data[-1] - data[-2]; - FLAC__int32 last_error_2 = last_error_1 - (data[-2] - data[-3]); - FLAC__int32 last_error_3 = last_error_2 - (data[-2] - 2*data[-3] + data[-4]); - FLAC__int32 error, save; - FLAC__uint32 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0; - uint32_t i, order; - - for(i = 0; i < data_len; i++) { - error = data[i] ; total_error_0 += local_abs(error); save = error; - error -= last_error_0; total_error_1 += local_abs(error); last_error_0 = save; save = error; - error -= last_error_1; total_error_2 += local_abs(error); last_error_1 = save; save = error; - error -= last_error_2; total_error_3 += local_abs(error); last_error_2 = save; save = error; - error -= last_error_3; total_error_4 += local_abs(error); last_error_3 = save; - } - - if(total_error_0 < flac_min(flac_min(flac_min(total_error_1, total_error_2), total_error_3), total_error_4)) - order = 0; - else if(total_error_1 < flac_min(flac_min(total_error_2, total_error_3), total_error_4)) - order = 1; - else if(total_error_2 < flac_min(total_error_3, total_error_4)) - order = 2; - else if(total_error_3 < total_error_4) - order = 3; - else - order = 4; - - /* Estimate the expected number of bits per residual signal sample. */ - /* 'total_error*' is linearly related to the variance of the residual */ - /* signal, so we use it directly to compute E(|x|) */ - FLAC__ASSERT(data_len > 0 || total_error_0 == 0); - FLAC__ASSERT(data_len > 0 || total_error_1 == 0); - FLAC__ASSERT(data_len > 0 || total_error_2 == 0); - FLAC__ASSERT(data_len > 0 || total_error_3 == 0); - FLAC__ASSERT(data_len > 0 || total_error_4 == 0); -#ifndef FLAC__INTEGER_ONLY_LIBRARY - residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0); - residual_bits_per_sample[1] = (float)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0); - residual_bits_per_sample[2] = (float)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0); - residual_bits_per_sample[3] = (float)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0); - residual_bits_per_sample[4] = (float)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0); -#else - residual_bits_per_sample[0] = (total_error_0 > 0) ? local__compute_rbps_integerized(total_error_0, data_len) : 0; - residual_bits_per_sample[1] = (total_error_1 > 0) ? local__compute_rbps_integerized(total_error_1, data_len) : 0; - residual_bits_per_sample[2] = (total_error_2 > 0) ? local__compute_rbps_integerized(total_error_2, data_len) : 0; - residual_bits_per_sample[3] = (total_error_3 > 0) ? local__compute_rbps_integerized(total_error_3, data_len) : 0; - residual_bits_per_sample[4] = (total_error_4 > 0) ? local__compute_rbps_integerized(total_error_4, data_len) : 0; -#endif - - return order; -} - -#ifndef FLAC__INTEGER_ONLY_LIBRARY -uint32_t FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) -#else -uint32_t FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) -#endif -{ - FLAC__int32 last_error_0 = data[-1]; - FLAC__int32 last_error_1 = data[-1] - data[-2]; - FLAC__int32 last_error_2 = last_error_1 - (data[-2] - data[-3]); - FLAC__int32 last_error_3 = last_error_2 - (data[-2] - 2*data[-3] + data[-4]); - FLAC__int32 error, save; - /* total_error_* are 64-bits to avoid overflow when encoding - * erratic signals when the bits-per-sample and blocksize are - * large. - */ - FLAC__uint64 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0; - uint32_t i, order; - - for(i = 0; i < data_len; i++) { - error = data[i] ; total_error_0 += local_abs(error); save = error; - error -= last_error_0; total_error_1 += local_abs(error); last_error_0 = save; save = error; - error -= last_error_1; total_error_2 += local_abs(error); last_error_1 = save; save = error; - error -= last_error_2; total_error_3 += local_abs(error); last_error_2 = save; save = error; - error -= last_error_3; total_error_4 += local_abs(error); last_error_3 = save; - } - - if(total_error_0 < flac_min(flac_min(flac_min(total_error_1, total_error_2), total_error_3), total_error_4)) - order = 0; - else if(total_error_1 < flac_min(flac_min(total_error_2, total_error_3), total_error_4)) - order = 1; - else if(total_error_2 < flac_min(total_error_3, total_error_4)) - order = 2; - else if(total_error_3 < total_error_4) - order = 3; - else - order = 4; - - /* Estimate the expected number of bits per residual signal sample. */ - /* 'total_error*' is linearly related to the variance of the residual */ - /* signal, so we use it directly to compute E(|x|) */ - FLAC__ASSERT(data_len > 0 || total_error_0 == 0); - FLAC__ASSERT(data_len > 0 || total_error_1 == 0); - FLAC__ASSERT(data_len > 0 || total_error_2 == 0); - FLAC__ASSERT(data_len > 0 || total_error_3 == 0); - FLAC__ASSERT(data_len > 0 || total_error_4 == 0); -#ifndef FLAC__INTEGER_ONLY_LIBRARY - residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0); - residual_bits_per_sample[1] = (float)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0); - residual_bits_per_sample[2] = (float)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0); - residual_bits_per_sample[3] = (float)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0); - residual_bits_per_sample[4] = (float)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0); -#else - residual_bits_per_sample[0] = (total_error_0 > 0) ? local__compute_rbps_wide_integerized(total_error_0, data_len) : 0; - residual_bits_per_sample[1] = (total_error_1 > 0) ? local__compute_rbps_wide_integerized(total_error_1, data_len) : 0; - residual_bits_per_sample[2] = (total_error_2 > 0) ? local__compute_rbps_wide_integerized(total_error_2, data_len) : 0; - residual_bits_per_sample[3] = (total_error_3 > 0) ? local__compute_rbps_wide_integerized(total_error_3, data_len) : 0; - residual_bits_per_sample[4] = (total_error_4 > 0) ? local__compute_rbps_wide_integerized(total_error_4, data_len) : 0; -#endif - - return order; -} - -void FLAC__fixed_compute_residual(const FLAC__int32 data[], uint32_t data_len, uint32_t order, FLAC__int32 residual[]) -{ - const int idata_len = (int)data_len; - int i; - - switch(order) { - case 0: - FLAC__ASSERT(sizeof(residual[0]) == sizeof(data[0])); - memcpy(residual, data, sizeof(residual[0])*data_len); - break; - case 1: - for(i = 0; i < idata_len; i++) - residual[i] = data[i] - data[i-1]; - break; - case 2: - for(i = 0; i < idata_len; i++) - residual[i] = data[i] - 2*data[i-1] + data[i-2]; - break; - case 3: - for(i = 0; i < idata_len; i++) - residual[i] = data[i] - 3*data[i-1] + 3*data[i-2] - data[i-3]; - break; - case 4: - for(i = 0; i < idata_len; i++) - residual[i] = data[i] - 4*data[i-1] + 6*data[i-2] - 4*data[i-3] + data[i-4]; - break; - default: - FLAC__ASSERT(0); - } -} - -void FLAC__fixed_restore_signal(const FLAC__int32 residual[], uint32_t data_len, uint32_t order, FLAC__int32 data[]) -{ - int i, idata_len = (int)data_len; - - switch(order) { - case 0: - FLAC__ASSERT(sizeof(residual[0]) == sizeof(data[0])); - memcpy(data, residual, sizeof(residual[0])*data_len); - break; - case 1: - for(i = 0; i < idata_len; i++) - data[i] = residual[i] + data[i-1]; - break; - case 2: - for(i = 0; i < idata_len; i++) - data[i] = residual[i] + 2*data[i-1] - data[i-2]; - break; - case 3: - for(i = 0; i < idata_len; i++) - data[i] = residual[i] + 3*data[i-1] - 3*data[i-2] + data[i-3]; - break; - case 4: - for(i = 0; i < idata_len; i++) - data[i] = residual[i] + 4*data[i-1] - 6*data[i-2] + 4*data[i-3] - data[i-4]; - break; - default: - FLAC__ASSERT(0); - } -} diff --git a/lib/flac/src/flac.pc.in b/lib/flac/src/flac.pc.in deleted file mode 100644 index 56e8594..0000000 --- a/lib/flac/src/flac.pc.in +++ /dev/null @@ -1,12 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: FLAC -Description: Free Lossless Audio Codec Library -Version: @VERSION@ -Requires.private: @OGG_PACKAGE@ -Libs: -L${libdir} -lFLAC -Libs.private: -lm -Cflags: -I${includedir} diff --git a/lib/flac/src/float.c b/lib/flac/src/float.c deleted file mode 100644 index a49a083..0000000 --- a/lib/flac/src/float.c +++ /dev/null @@ -1,302 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2004-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "FLAC/assert.h" -#include "share/compat.h" -#include "private/float.h" - -#ifdef FLAC__INTEGER_ONLY_LIBRARY - -const FLAC__fixedpoint FLAC__FP_ZERO = 0; -const FLAC__fixedpoint FLAC__FP_ONE_HALF = 0x00008000; -const FLAC__fixedpoint FLAC__FP_ONE = 0x00010000; -const FLAC__fixedpoint FLAC__FP_LN2 = 45426; -const FLAC__fixedpoint FLAC__FP_E = 178145; - -/* Lookup tables for Knuth's logarithm algorithm */ -#define LOG2_LOOKUP_PRECISION 16 -static const FLAC__uint32 log2_lookup[][LOG2_LOOKUP_PRECISION] = { - { - /* - * 0 fraction bits - */ - /* undefined */ 0x00000000, - /* lg(2/1) = */ 0x00000001, - /* lg(4/3) = */ 0x00000000, - /* lg(8/7) = */ 0x00000000, - /* lg(16/15) = */ 0x00000000, - /* lg(32/31) = */ 0x00000000, - /* lg(64/63) = */ 0x00000000, - /* lg(128/127) = */ 0x00000000, - /* lg(256/255) = */ 0x00000000, - /* lg(512/511) = */ 0x00000000, - /* lg(1024/1023) = */ 0x00000000, - /* lg(2048/2047) = */ 0x00000000, - /* lg(4096/4095) = */ 0x00000000, - /* lg(8192/8191) = */ 0x00000000, - /* lg(16384/16383) = */ 0x00000000, - /* lg(32768/32767) = */ 0x00000000 - }, - { - /* - * 4 fraction bits - */ - /* undefined */ 0x00000000, - /* lg(2/1) = */ 0x00000010, - /* lg(4/3) = */ 0x00000007, - /* lg(8/7) = */ 0x00000003, - /* lg(16/15) = */ 0x00000001, - /* lg(32/31) = */ 0x00000001, - /* lg(64/63) = */ 0x00000000, - /* lg(128/127) = */ 0x00000000, - /* lg(256/255) = */ 0x00000000, - /* lg(512/511) = */ 0x00000000, - /* lg(1024/1023) = */ 0x00000000, - /* lg(2048/2047) = */ 0x00000000, - /* lg(4096/4095) = */ 0x00000000, - /* lg(8192/8191) = */ 0x00000000, - /* lg(16384/16383) = */ 0x00000000, - /* lg(32768/32767) = */ 0x00000000 - }, - { - /* - * 8 fraction bits - */ - /* undefined */ 0x00000000, - /* lg(2/1) = */ 0x00000100, - /* lg(4/3) = */ 0x0000006a, - /* lg(8/7) = */ 0x00000031, - /* lg(16/15) = */ 0x00000018, - /* lg(32/31) = */ 0x0000000c, - /* lg(64/63) = */ 0x00000006, - /* lg(128/127) = */ 0x00000003, - /* lg(256/255) = */ 0x00000001, - /* lg(512/511) = */ 0x00000001, - /* lg(1024/1023) = */ 0x00000000, - /* lg(2048/2047) = */ 0x00000000, - /* lg(4096/4095) = */ 0x00000000, - /* lg(8192/8191) = */ 0x00000000, - /* lg(16384/16383) = */ 0x00000000, - /* lg(32768/32767) = */ 0x00000000 - }, - { - /* - * 12 fraction bits - */ - /* undefined */ 0x00000000, - /* lg(2/1) = */ 0x00001000, - /* lg(4/3) = */ 0x000006a4, - /* lg(8/7) = */ 0x00000315, - /* lg(16/15) = */ 0x0000017d, - /* lg(32/31) = */ 0x000000bc, - /* lg(64/63) = */ 0x0000005d, - /* lg(128/127) = */ 0x0000002e, - /* lg(256/255) = */ 0x00000017, - /* lg(512/511) = */ 0x0000000c, - /* lg(1024/1023) = */ 0x00000006, - /* lg(2048/2047) = */ 0x00000003, - /* lg(4096/4095) = */ 0x00000001, - /* lg(8192/8191) = */ 0x00000001, - /* lg(16384/16383) = */ 0x00000000, - /* lg(32768/32767) = */ 0x00000000 - }, - { - /* - * 16 fraction bits - */ - /* undefined */ 0x00000000, - /* lg(2/1) = */ 0x00010000, - /* lg(4/3) = */ 0x00006a40, - /* lg(8/7) = */ 0x00003151, - /* lg(16/15) = */ 0x000017d6, - /* lg(32/31) = */ 0x00000bba, - /* lg(64/63) = */ 0x000005d1, - /* lg(128/127) = */ 0x000002e6, - /* lg(256/255) = */ 0x00000172, - /* lg(512/511) = */ 0x000000b9, - /* lg(1024/1023) = */ 0x0000005c, - /* lg(2048/2047) = */ 0x0000002e, - /* lg(4096/4095) = */ 0x00000017, - /* lg(8192/8191) = */ 0x0000000c, - /* lg(16384/16383) = */ 0x00000006, - /* lg(32768/32767) = */ 0x00000003 - }, - { - /* - * 20 fraction bits - */ - /* undefined */ 0x00000000, - /* lg(2/1) = */ 0x00100000, - /* lg(4/3) = */ 0x0006a3fe, - /* lg(8/7) = */ 0x00031513, - /* lg(16/15) = */ 0x00017d60, - /* lg(32/31) = */ 0x0000bb9d, - /* lg(64/63) = */ 0x00005d10, - /* lg(128/127) = */ 0x00002e59, - /* lg(256/255) = */ 0x00001721, - /* lg(512/511) = */ 0x00000b8e, - /* lg(1024/1023) = */ 0x000005c6, - /* lg(2048/2047) = */ 0x000002e3, - /* lg(4096/4095) = */ 0x00000171, - /* lg(8192/8191) = */ 0x000000b9, - /* lg(16384/16383) = */ 0x0000005c, - /* lg(32768/32767) = */ 0x0000002e - }, - { - /* - * 24 fraction bits - */ - /* undefined */ 0x00000000, - /* lg(2/1) = */ 0x01000000, - /* lg(4/3) = */ 0x006a3fe6, - /* lg(8/7) = */ 0x00315130, - /* lg(16/15) = */ 0x0017d605, - /* lg(32/31) = */ 0x000bb9ca, - /* lg(64/63) = */ 0x0005d0fc, - /* lg(128/127) = */ 0x0002e58f, - /* lg(256/255) = */ 0x0001720e, - /* lg(512/511) = */ 0x0000b8d8, - /* lg(1024/1023) = */ 0x00005c61, - /* lg(2048/2047) = */ 0x00002e2d, - /* lg(4096/4095) = */ 0x00001716, - /* lg(8192/8191) = */ 0x00000b8b, - /* lg(16384/16383) = */ 0x000005c5, - /* lg(32768/32767) = */ 0x000002e3 - }, - { - /* - * 28 fraction bits - */ - /* undefined */ 0x00000000, - /* lg(2/1) = */ 0x10000000, - /* lg(4/3) = */ 0x06a3fe5c, - /* lg(8/7) = */ 0x03151301, - /* lg(16/15) = */ 0x017d6049, - /* lg(32/31) = */ 0x00bb9ca6, - /* lg(64/63) = */ 0x005d0fba, - /* lg(128/127) = */ 0x002e58f7, - /* lg(256/255) = */ 0x001720da, - /* lg(512/511) = */ 0x000b8d87, - /* lg(1024/1023) = */ 0x0005c60b, - /* lg(2048/2047) = */ 0x0002e2d7, - /* lg(4096/4095) = */ 0x00017160, - /* lg(8192/8191) = */ 0x0000b8ad, - /* lg(16384/16383) = */ 0x00005c56, - /* lg(32768/32767) = */ 0x00002e2b - } -}; - -#if 0 -static const FLAC__uint64 log2_lookup_wide[] = { - { - /* - * 32 fraction bits - */ - /* undefined */ 0x00000000, - /* lg(2/1) = */ FLAC__U64L(0x100000000), - /* lg(4/3) = */ FLAC__U64L(0x6a3fe5c6), - /* lg(8/7) = */ FLAC__U64L(0x31513015), - /* lg(16/15) = */ FLAC__U64L(0x17d60497), - /* lg(32/31) = */ FLAC__U64L(0x0bb9ca65), - /* lg(64/63) = */ FLAC__U64L(0x05d0fba2), - /* lg(128/127) = */ FLAC__U64L(0x02e58f74), - /* lg(256/255) = */ FLAC__U64L(0x01720d9c), - /* lg(512/511) = */ FLAC__U64L(0x00b8d875), - /* lg(1024/1023) = */ FLAC__U64L(0x005c60aa), - /* lg(2048/2047) = */ FLAC__U64L(0x002e2d72), - /* lg(4096/4095) = */ FLAC__U64L(0x00171600), - /* lg(8192/8191) = */ FLAC__U64L(0x000b8ad2), - /* lg(16384/16383) = */ FLAC__U64L(0x0005c55d), - /* lg(32768/32767) = */ FLAC__U64L(0x0002e2ac) - }, - { - /* - * 48 fraction bits - */ - /* undefined */ 0x00000000, - /* lg(2/1) = */ FLAC__U64L(0x1000000000000), - /* lg(4/3) = */ FLAC__U64L(0x6a3fe5c60429), - /* lg(8/7) = */ FLAC__U64L(0x315130157f7a), - /* lg(16/15) = */ FLAC__U64L(0x17d60496cfbb), - /* lg(32/31) = */ FLAC__U64L(0xbb9ca64ecac), - /* lg(64/63) = */ FLAC__U64L(0x5d0fba187cd), - /* lg(128/127) = */ FLAC__U64L(0x2e58f7441ee), - /* lg(256/255) = */ FLAC__U64L(0x1720d9c06a8), - /* lg(512/511) = */ FLAC__U64L(0xb8d8752173), - /* lg(1024/1023) = */ FLAC__U64L(0x5c60aa252e), - /* lg(2048/2047) = */ FLAC__U64L(0x2e2d71b0d8), - /* lg(4096/4095) = */ FLAC__U64L(0x1716001719), - /* lg(8192/8191) = */ FLAC__U64L(0xb8ad1de1b), - /* lg(16384/16383) = */ FLAC__U64L(0x5c55d640d), - /* lg(32768/32767) = */ FLAC__U64L(0x2e2abcf52) - } -}; -#endif - -FLAC__uint32 FLAC__fixedpoint_log2(FLAC__uint32 x, uint32_t fracbits, uint32_t precision) -{ - const FLAC__uint32 ONE = (1u << fracbits); - const FLAC__uint32 *table = log2_lookup[fracbits >> 2]; - - FLAC__ASSERT(fracbits < 32); - FLAC__ASSERT((fracbits & 0x3) == 0); - - if(x < ONE) - return 0; - - if(precision > LOG2_LOOKUP_PRECISION) - precision = LOG2_LOOKUP_PRECISION; - - /* Knuth's algorithm for computing logarithms, optimized for base-2 with lookup tables */ - { - FLAC__uint32 y = 0; - FLAC__uint32 z = x >> 1, k = 1; - while (x > ONE && k < precision) { - if (x - z >= ONE) { - x -= z; - z = x >> k; - y += table[k]; - } - else { - z >>= 1; - k++; - } - } - return y; - } -} - -#endif /* defined FLAC__INTEGER_ONLY_LIBRARY */ diff --git a/lib/flac/src/format.c b/lib/flac/src/format.c deleted file mode 100644 index a62219f..0000000 --- a/lib/flac/src/format.c +++ /dev/null @@ -1,589 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include /* for qsort() */ -#include /* for memset() */ -#include "FLAC/assert.h" -#include "FLAC/format.h" -#include "share/alloc.h" -#include "share/compat.h" -#include "private/format.h" -#include "private/macros.h" - -/* PACKAGE_VERSION should come from configure */ -FLAC_API const char *FLAC__VERSION_STRING = PACKAGE_VERSION; - -FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC " PACKAGE_VERSION " 20190804"; - -FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4] = { 'f','L','a','C' }; -FLAC_API const uint32_t FLAC__STREAM_SYNC = 0x664C6143; -FLAC_API const uint32_t FLAC__STREAM_SYNC_LEN = 32; /* bits */ - -FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN = 16; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN = 16; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN = 24; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN = 24; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN = 20; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN = 3; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN = 5; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN = 36; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN = 128; /* bits */ - -FLAC_API const uint32_t FLAC__STREAM_METADATA_APPLICATION_ID_LEN = 32; /* bits */ - -FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN = 64; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN = 64; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN = 16; /* bits */ - -FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER = FLAC__U64L(0xffffffffffffffff); - -FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN = 32; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN = 32; /* bits */ - -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN = 64; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN = 8; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN = 3*8; /* bits */ - -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN = 64; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN = 8; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN = 12*8; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN = 1; /* bit */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN = 1; /* bit */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN = 6+13*8; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN = 8; /* bits */ - -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN = 128*8; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN = 64; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN = 1; /* bit */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN = 7+258*8; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN = 8; /* bits */ - -FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_TYPE_LEN = 32; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN = 32; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN = 32; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN = 32; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN = 32; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN = 32; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_COLORS_LEN = 32; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN = 32; /* bits */ - -FLAC_API const uint32_t FLAC__STREAM_METADATA_IS_LAST_LEN = 1; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_TYPE_LEN = 7; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_LENGTH_LEN = 24; /* bits */ - -FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC = 0x3ffe; -FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC_LEN = 14; /* bits */ -FLAC_API const uint32_t FLAC__FRAME_HEADER_RESERVED_LEN = 1; /* bits */ -FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN = 1; /* bits */ -FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCK_SIZE_LEN = 4; /* bits */ -FLAC_API const uint32_t FLAC__FRAME_HEADER_SAMPLE_RATE_LEN = 4; /* bits */ -FLAC_API const uint32_t FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN = 4; /* bits */ -FLAC_API const uint32_t FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN = 3; /* bits */ -FLAC_API const uint32_t FLAC__FRAME_HEADER_ZERO_PAD_LEN = 1; /* bits */ -FLAC_API const uint32_t FLAC__FRAME_HEADER_CRC_LEN = 8; /* bits */ - -FLAC_API const uint32_t FLAC__FRAME_FOOTER_CRC_LEN = 16; /* bits */ - -FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_TYPE_LEN = 2; /* bits */ -FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN = 4; /* bits */ -FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN = 4; /* bits */ -FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN = 5; /* bits */ -FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN = 5; /* bits */ - -FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER = 15; /* == (1< FLAC__MAX_SAMPLE_RATE) { - return false; - } - else - return true; -} - -FLAC_API FLAC__bool FLAC__format_blocksize_is_subset(uint32_t blocksize, uint32_t sample_rate) -{ - if(blocksize > 16384) - return false; - else if(sample_rate <= 48000 && blocksize > 4608) - return false; - else - return true; -} - -FLAC_API FLAC__bool FLAC__format_sample_rate_is_subset(uint32_t sample_rate) -{ - if( - !FLAC__format_sample_rate_is_valid(sample_rate) || - ( - sample_rate >= (1u << 16) && - !(sample_rate % 1000 == 0 || sample_rate % 10 == 0) - ) - ) { - return false; - } - else - return true; -} - -/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */ -FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_SeekTable *seek_table) -{ - uint32_t i; - FLAC__uint64 prev_sample_number = 0; - FLAC__bool got_prev = false; - - FLAC__ASSERT(0 != seek_table); - - for(i = 0; i < seek_table->num_points; i++) { - if(got_prev) { - if( - seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER && - seek_table->points[i].sample_number <= prev_sample_number - ) - return false; - } - prev_sample_number = seek_table->points[i].sample_number; - got_prev = true; - } - - return true; -} - -/* used as the sort predicate for qsort() */ -static int seekpoint_compare_(const FLAC__StreamMetadata_SeekPoint *l, const FLAC__StreamMetadata_SeekPoint *r) -{ - /* we don't just 'return l->sample_number - r->sample_number' since the result (FLAC__int64) might overflow an 'int' */ - if(l->sample_number == r->sample_number) - return 0; - else if(l->sample_number < r->sample_number) - return -1; - else - return 1; -} - -/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */ -FLAC_API uint32_t FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table) -{ - uint32_t i, j; - FLAC__bool first; - - FLAC__ASSERT(0 != seek_table); - - if (seek_table->num_points == 0) - return 0; - - /* sort the seekpoints */ - qsort(seek_table->points, seek_table->num_points, sizeof(FLAC__StreamMetadata_SeekPoint), (int (*)(const void *, const void *))seekpoint_compare_); - - /* uniquify the seekpoints */ - first = true; - for(i = j = 0; i < seek_table->num_points; i++) { - if(seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER) { - if(!first) { - if(seek_table->points[i].sample_number == seek_table->points[j-1].sample_number) - continue; - } - } - first = false; - seek_table->points[j++] = seek_table->points[i]; - } - - for(i = j; i < seek_table->num_points; i++) { - seek_table->points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER; - seek_table->points[i].stream_offset = 0; - seek_table->points[i].frame_samples = 0; - } - - return j; -} - -/* - * also disallows non-shortest-form encodings, c.f. - * http://www.unicode.org/versions/corrigendum1.html - * and a more clear explanation at the end of this section: - * http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - */ -static uint32_t utf8len_(const FLAC__byte *utf8) -{ - FLAC__ASSERT(0 != utf8); - if ((utf8[0] & 0x80) == 0) { - return 1; - } - else if ((utf8[0] & 0xE0) == 0xC0 && (utf8[1] & 0xC0) == 0x80) { - if ((utf8[0] & 0xFE) == 0xC0) /* overlong sequence check */ - return 0; - return 2; - } - else if ((utf8[0] & 0xF0) == 0xE0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80) { - if (utf8[0] == 0xE0 && (utf8[1] & 0xE0) == 0x80) /* overlong sequence check */ - return 0; - /* illegal surrogates check (U+D800...U+DFFF and U+FFFE...U+FFFF) */ - if (utf8[0] == 0xED && (utf8[1] & 0xE0) == 0xA0) /* D800-DFFF */ - return 0; - if (utf8[0] == 0xEF && utf8[1] == 0xBF && (utf8[2] & 0xFE) == 0xBE) /* FFFE-FFFF */ - return 0; - return 3; - } - else if ((utf8[0] & 0xF8) == 0xF0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80) { - if (utf8[0] == 0xF0 && (utf8[1] & 0xF0) == 0x80) /* overlong sequence check */ - return 0; - return 4; - } - else if ((utf8[0] & 0xFC) == 0xF8 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80 && (utf8[4] & 0xC0) == 0x80) { - if (utf8[0] == 0xF8 && (utf8[1] & 0xF8) == 0x80) /* overlong sequence check */ - return 0; - return 5; - } - else if ((utf8[0] & 0xFE) == 0xFC && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80 && (utf8[4] & 0xC0) == 0x80 && (utf8[5] & 0xC0) == 0x80) { - if (utf8[0] == 0xFC && (utf8[1] & 0xFC) == 0x80) /* overlong sequence check */ - return 0; - return 6; - } - else { - return 0; - } -} - -FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_name_is_legal(const char *name) -{ - char c; - for(c = *name; c; c = *(++name)) - if(c < 0x20 || c == 0x3d || c > 0x7d) - return false; - return true; -} - -FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, uint32_t length) -{ - if(length == (uint32_t)(-1)) { - while(*value) { - uint32_t n = utf8len_(value); - if(n == 0) - return false; - value += n; - } - } - else { - const FLAC__byte *end = value + length; - while(value < end) { - uint32_t n = utf8len_(value); - if(n == 0) - return false; - value += n; - } - if(value != end) - return false; - } - return true; -} - -FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, uint32_t length) -{ - const FLAC__byte *s, *end; - - for(s = entry, end = s + length; s < end && *s != '='; s++) { - if(*s < 0x20 || *s > 0x7D) - return false; - } - if(s == end) - return false; - - s++; /* skip '=' */ - - while(s < end) { - uint32_t n = utf8len_(s); - if(n == 0) - return false; - s += n; - } - if(s != end) - return false; - - return true; -} - -/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */ -FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation) -{ - uint32_t i, j; - - if(check_cd_da_subset) { - if(cue_sheet->lead_in < 2 * 44100) { - if(violation) *violation = "CD-DA cue sheet must have a lead-in length of at least 2 seconds"; - return false; - } - if(cue_sheet->lead_in % 588 != 0) { - if(violation) *violation = "CD-DA cue sheet lead-in length must be evenly divisible by 588 samples"; - return false; - } - } - - if(cue_sheet->num_tracks == 0) { - if(violation) *violation = "cue sheet must have at least one track (the lead-out)"; - return false; - } - - if(check_cd_da_subset && cue_sheet->tracks[cue_sheet->num_tracks-1].number != 170) { - if(violation) *violation = "CD-DA cue sheet must have a lead-out track number 170 (0xAA)"; - return false; - } - - for(i = 0; i < cue_sheet->num_tracks; i++) { - if(cue_sheet->tracks[i].number == 0) { - if(violation) *violation = "cue sheet may not have a track number 0"; - return false; - } - - if(check_cd_da_subset) { - if(!((cue_sheet->tracks[i].number >= 1 && cue_sheet->tracks[i].number <= 99) || cue_sheet->tracks[i].number == 170)) { - if(violation) *violation = "CD-DA cue sheet track number must be 1-99 or 170"; - return false; - } - } - - if(check_cd_da_subset && cue_sheet->tracks[i].offset % 588 != 0) { - if(violation) { - if(i == cue_sheet->num_tracks-1) /* the lead-out track... */ - *violation = "CD-DA cue sheet lead-out offset must be evenly divisible by 588 samples"; - else - *violation = "CD-DA cue sheet track offset must be evenly divisible by 588 samples"; - } - return false; - } - - if(i < cue_sheet->num_tracks - 1) { - if(cue_sheet->tracks[i].num_indices == 0) { - if(violation) *violation = "cue sheet track must have at least one index point"; - return false; - } - - if(cue_sheet->tracks[i].indices[0].number > 1) { - if(violation) *violation = "cue sheet track's first index number must be 0 or 1"; - return false; - } - } - - for(j = 0; j < cue_sheet->tracks[i].num_indices; j++) { - if(check_cd_da_subset && cue_sheet->tracks[i].indices[j].offset % 588 != 0) { - if(violation) *violation = "CD-DA cue sheet track index offset must be evenly divisible by 588 samples"; - return false; - } - - if(j > 0) { - if(cue_sheet->tracks[i].indices[j].number != cue_sheet->tracks[i].indices[j-1].number + 1) { - if(violation) *violation = "cue sheet track index numbers must increase by 1"; - return false; - } - } - } - } - - return true; -} - -/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */ -FLAC_API FLAC__bool FLAC__format_picture_is_legal(const FLAC__StreamMetadata_Picture *picture, const char **violation) -{ - char *p; - FLAC__byte *b; - - for(p = picture->mime_type; *p; p++) { - if(*p < 0x20 || *p > 0x7e) { - if(violation) *violation = "MIME type string must contain only printable ASCII characters (0x20-0x7e)"; - return false; - } - } - - for(b = picture->description; *b; ) { - uint32_t n = utf8len_(b); - if(n == 0) { - if(violation) *violation = "description string must be valid UTF-8"; - return false; - } - b += n; - } - - return true; -} - -/* - * These routines are private to libFLAC - */ -uint32_t FLAC__format_get_max_rice_partition_order(uint32_t blocksize, uint32_t predictor_order) -{ - return - FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order( - FLAC__format_get_max_rice_partition_order_from_blocksize(blocksize), - blocksize, - predictor_order - ); -} - -uint32_t FLAC__format_get_max_rice_partition_order_from_blocksize(uint32_t blocksize) -{ - uint32_t max_rice_partition_order = 0; - while(!(blocksize & 1)) { - max_rice_partition_order++; - blocksize >>= 1; - } - return flac_min(FLAC__MAX_RICE_PARTITION_ORDER, max_rice_partition_order); -} - -uint32_t FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(uint32_t limit, uint32_t blocksize, uint32_t predictor_order) -{ - uint32_t max_rice_partition_order = limit; - - while(max_rice_partition_order > 0 && (blocksize >> max_rice_partition_order) <= predictor_order) - max_rice_partition_order--; - - FLAC__ASSERT( - (max_rice_partition_order == 0 && blocksize >= predictor_order) || - (max_rice_partition_order > 0 && blocksize >> max_rice_partition_order > predictor_order) - ); - - return max_rice_partition_order; -} - -void FLAC__format_entropy_coding_method_partitioned_rice_contents_init(FLAC__EntropyCodingMethod_PartitionedRiceContents *object) -{ - FLAC__ASSERT(0 != object); - - object->parameters = 0; - object->raw_bits = 0; - object->capacity_by_order = 0; -} - -void FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(FLAC__EntropyCodingMethod_PartitionedRiceContents *object) -{ - FLAC__ASSERT(0 != object); - - if(0 != object->parameters) - free(object->parameters); - if(0 != object->raw_bits) - free(object->raw_bits); - FLAC__format_entropy_coding_method_partitioned_rice_contents_init(object); -} - -FLAC__bool FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(FLAC__EntropyCodingMethod_PartitionedRiceContents *object, uint32_t max_partition_order) -{ - FLAC__ASSERT(0 != object); - - FLAC__ASSERT(object->capacity_by_order > 0 || (0 == object->parameters && 0 == object->raw_bits)); - - if(object->capacity_by_order < max_partition_order) { - if(0 == (object->parameters = safe_realloc_(object->parameters, sizeof(uint32_t)*(1 << max_partition_order)))) - return false; - if(0 == (object->raw_bits = safe_realloc_(object->raw_bits, sizeof(uint32_t)*(1 << max_partition_order)))) - return false; - memset(object->raw_bits, 0, sizeof(uint32_t)*(1 << max_partition_order)); - object->capacity_by_order = max_partition_order; - } - - return true; -} diff --git a/lib/flac/src/include/private/Makefile.am b/lib/flac/src/include/private/Makefile.am deleted file mode 100644 index 49bcda7..0000000 --- a/lib/flac/src/include/private/Makefile.am +++ /dev/null @@ -1,53 +0,0 @@ -# libFLAC - Free Lossless Audio Codec library -# Copyright (C) 2001-2009 Josh Coalson -# Copyright (C) 2011-2016 Xiph.Org Foundation -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# - Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# - Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# - Neither the name of the Xiph.org Foundation nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -noinst_HEADERS = \ - all.h \ - bitmath.h \ - bitreader.h \ - bitwriter.h \ - cpu.h \ - crc.h \ - fixed.h \ - float.h \ - format.h \ - lpc.h \ - macros.h \ - md5.h \ - memory.h \ - metadata.h \ - ogg_decoder_aspect.h \ - ogg_encoder_aspect.h \ - ogg_helper.h \ - ogg_mapping.h \ - stream_encoder.h \ - stream_encoder_framing.h \ - window.h diff --git a/lib/flac/src/include/private/Makefile.in b/lib/flac/src/include/private/Makefile.in deleted file mode 100644 index dc062e1..0000000 --- a/lib/flac/src/include/private/Makefile.in +++ /dev/null @@ -1,607 +0,0 @@ -# Makefile.in generated by automake 1.16.1 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994-2018 Free Software Foundation, Inc. - -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - -# libFLAC - Free Lossless Audio Codec library -# Copyright (C) 2001-2009 Josh Coalson -# Copyright (C) 2011-2016 Xiph.Org Foundation -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# - Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# - Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# - Neither the name of the Xiph.org Foundation nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -VPATH = @srcdir@ -am__is_gnu_make = { \ - if test -z '$(MAKELEVEL)'; then \ - false; \ - elif test -n '$(MAKE_HOST)'; then \ - true; \ - elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ - true; \ - else \ - false; \ - fi; \ -} -am__make_running_with_option = \ - case $${target_option-} in \ - ?) ;; \ - *) echo "am__make_running_with_option: internal error: invalid" \ - "target option '$${target_option-}' specified" >&2; \ - exit 1;; \ - esac; \ - has_opt=no; \ - sane_makeflags=$$MAKEFLAGS; \ - if $(am__is_gnu_make); then \ - sane_makeflags=$$MFLAGS; \ - else \ - case $$MAKEFLAGS in \ - *\\[\ \ ]*) \ - bs=\\; \ - sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ - | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ - esac; \ - fi; \ - skip_next=no; \ - strip_trailopt () \ - { \ - flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ - }; \ - for flg in $$sane_makeflags; do \ - test $$skip_next = yes && { skip_next=no; continue; }; \ - case $$flg in \ - *=*|--*) continue;; \ - -*I) strip_trailopt 'I'; skip_next=yes;; \ - -*I?*) strip_trailopt 'I';; \ - -*O) strip_trailopt 'O'; skip_next=yes;; \ - -*O?*) strip_trailopt 'O';; \ - -*l) strip_trailopt 'l'; skip_next=yes;; \ - -*l?*) strip_trailopt 'l';; \ - -[dEDm]) skip_next=yes;; \ - -[JT]) skip_next=yes;; \ - esac; \ - case $$flg in \ - *$$target_option*) has_opt=yes; break;; \ - esac; \ - done; \ - test $$has_opt = yes -am__make_dryrun = (target_option=n; $(am__make_running_with_option)) -am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -subdir = src/libFLAC/include/private -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/add_cflags.m4 \ - $(top_srcdir)/m4/add_cxxflags.m4 \ - $(top_srcdir)/m4/ax_add_fortify_source.m4 \ - $(top_srcdir)/m4/ax_check_enable_debug.m4 \ - $(top_srcdir)/m4/bswap.m4 $(top_srcdir)/m4/c_attribute.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)/m4/xmms.m4 \ - $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ - $(am__DIST_COMMON) -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = $(top_builddir)/config.h -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -AM_V_P = $(am__v_P_@AM_V@) -am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) -am__v_P_0 = false -am__v_P_1 = : -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = -SOURCES = -DIST_SOURCES = -am__can_run_installinfo = \ - case $$AM_UPDATE_INFO_DIR in \ - n|no|NO) false;; \ - *) (install-info --version) >/dev/null 2>&1;; \ - esac -HEADERS = $(noinst_HEADERS) -am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) -# Read a list of newline-separated strings from the standard input, -# and print each of them once, without duplicates. Input order is -# *not* preserved. -am__uniquify_input = $(AWK) '\ - BEGIN { nonempty = 0; } \ - { items[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in items) print i; }; } \ -' -# Make sure the list of sources is unique. This is necessary because, -# e.g., the same source file might be shared among _SOURCES variables -# for different programs/libraries. -am__define_uniq_tagged_files = \ - list='$(am__tagged_files)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | $(am__uniquify_input)` -ETAGS = etags -CTAGS = ctags -am__DIST_COMMON = $(srcdir)/Makefile.in -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = @ACLOCAL@ -AMTAR = @AMTAR@ -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ -AR = @AR@ -AS = @AS@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -CC = @CC@ -CCAS = @CCAS@ -CCASDEPMODE = @CCASDEPMODE@ -CCASFLAGS = @CCASFLAGS@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ -CXX = @CXX@ -CXXCPP = @CXXCPP@ -CXXDEPMODE = @CXXDEPMODE@ -CXXFLAGS = @CXXFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -DLLTOOL = @DLLTOOL@ -DOCBOOK_TO_MAN = @DOCBOOK_TO_MAN@ -DOXYGEN = @DOXYGEN@ -DSYMUTIL = @DSYMUTIL@ -DUMPBIN = @DUMPBIN@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -ENABLE_64_BIT_WORDS = @ENABLE_64_BIT_WORDS@ -EXEEXT = @EXEEXT@ -FGREP = @FGREP@ -FLAC__HAS_OGG = @FLAC__HAS_OGG@ -FLAC__TEST_LEVEL = @FLAC__TEST_LEVEL@ -FLAC__TEST_WITH_VALGRIND = @FLAC__TEST_WITH_VALGRIND@ -GCC_MAJOR_VERSION = @GCC_MAJOR_VERSION@ -GCC_MINOR_VERSION = @GCC_MINOR_VERSION@ -GCC_VERSION = @GCC_VERSION@ -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@ -LIPO = @LIPO@ -LN_S = @LN_S@ -LTLIBICONV = @LTLIBICONV@ -LTLIBOBJS = @LTLIBOBJS@ -LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ -MAKEINFO = @MAKEINFO@ -MANIFEST_TOOL = @MANIFEST_TOOL@ -MKDIR_P = @MKDIR_P@ -NASM = @NASM@ -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@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -RANLIB = @RANLIB@ -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_DUMPBIN = @ac_ct_DUMPBIN@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localedir = @localedir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -runstatedir = @runstatedir@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -srcdir = @srcdir@ -sysconfdir = @sysconfdir@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -noinst_HEADERS = \ - all.h \ - bitmath.h \ - bitreader.h \ - bitwriter.h \ - cpu.h \ - crc.h \ - fixed.h \ - float.h \ - format.h \ - lpc.h \ - macros.h \ - md5.h \ - memory.h \ - metadata.h \ - ogg_decoder_aspect.h \ - ogg_encoder_aspect.h \ - ogg_helper.h \ - ogg_mapping.h \ - stream_encoder.h \ - stream_encoder_framing.h \ - window.h - -all: all-am - -.SUFFIXES: -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ - && { if test -f $@; then exit 0; else break; fi; }; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/libFLAC/include/private/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign src/libFLAC/include/private/Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(am__aclocal_m4_deps): - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs - -ID: $(am__tagged_files) - $(am__define_uniq_tagged_files); mkid -fID $$unique -tags: tags-am -TAGS: tags - -tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - set x; \ - here=`pwd`; \ - $(am__define_uniq_tagged_files); \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: ctags-am - -CTAGS: ctags -ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - $(am__define_uniq_tagged_files); \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" -cscopelist: cscopelist-am - -cscopelist-am: $(am__tagged_files) - list='$(am__tagged_files)'; \ - case "$(srcdir)" in \ - [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ - *) sdir=$(subdir)/$(srcdir) ;; \ - esac; \ - for i in $$list; do \ - if test -f "$$i"; then \ - echo "$(subdir)/$$i"; \ - else \ - echo "$$sdir/$$i"; \ - fi; \ - done >> $(top_builddir)/cscope.files - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -distdir: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) distdir-am - -distdir-am: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: check-am -all-am: Makefile $(HEADERS) -installdirs: -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - if test -z '$(STRIP)'; then \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - install; \ - else \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ - fi -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-am - -clean-am: clean-generic clean-libtool mostlyclean-am - -distclean: distclean-am - -rm -f Makefile -distclean-am: clean-am distclean-generic distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -html-am: - -info: info-am - -info-am: - -install-data-am: - -install-dvi: install-dvi-am - -install-dvi-am: - -install-exec-am: - -install-html: install-html-am - -install-html-am: - -install-info: install-info-am - -install-info-am: - -install-man: - -install-pdf: install-pdf-am - -install-pdf-am: - -install-ps: install-ps-am - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-generic mostlyclean-libtool - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: - -.MAKE: install-am install-strip - -.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ - clean-libtool cscopelist-am ctags ctags-am distclean \ - distclean-generic distclean-libtool distclean-tags distdir dvi \ - dvi-am html html-am info info-am install install-am \ - install-data install-data-am install-dvi install-dvi-am \ - install-exec install-exec-am install-html install-html-am \ - install-info install-info-am install-man install-pdf \ - install-pdf-am install-ps install-ps-am install-strip \ - installcheck installcheck-am installdirs maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-generic \ - mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ - uninstall-am - -.PRECIOUS: Makefile - - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/lib/flac/src/include/private/all.h b/lib/flac/src/include/private/all.h deleted file mode 100644 index 7715962..0000000 --- a/lib/flac/src/include/private/all.h +++ /dev/null @@ -1,50 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PRIVATE__ALL_H -#define FLAC__PRIVATE__ALL_H - -#include "bitmath.h" -#include "bitreader.h" -#include "bitwriter.h" -#include "cpu.h" -#include "crc.h" -#include "fixed.h" -#include "float.h" -#include "format.h" -#include "lpc.h" -#include "md5.h" -#include "memory.h" -#include "metadata.h" -#include "stream_encoder_framing.h" - -#endif diff --git a/lib/flac/src/include/private/bitmath.h b/lib/flac/src/include/private/bitmath.h deleted file mode 100644 index 12a3fb9..0000000 --- a/lib/flac/src/include/private/bitmath.h +++ /dev/null @@ -1,210 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PRIVATE__BITMATH_H -#define FLAC__PRIVATE__BITMATH_H - -#include "FLAC/ordinals.h" -#include "FLAC/assert.h" - -#include "share/compat.h" - -#if defined(_MSC_VER) -#include /* for _BitScanReverse* */ -#endif - -/* Will never be emitted for MSVC, GCC, Intel compilers */ -static inline uint32_t FLAC__clz_soft_uint32(FLAC__uint32 word) -{ - static const uint8_t byte_to_unary_table[] = { - 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - }; - - return word > 0xffffff ? byte_to_unary_table[word >> 24] : - word > 0xffff ? byte_to_unary_table[word >> 16] + 8 : - word > 0xff ? byte_to_unary_table[word >> 8] + 16 : - byte_to_unary_table[word] + 24; -} - -static inline uint32_t FLAC__clz_uint32(FLAC__uint32 v) -{ -/* Never used with input 0 */ - FLAC__ASSERT(v > 0); -#if defined(__INTEL_COMPILER) - return _bit_scan_reverse(v) ^ 31U; -#elif defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) -/* This will translate either to (bsr ^ 31U), clz , ctlz, cntlz, lzcnt depending on - * -march= setting or to a software routine in exotic machines. */ - return __builtin_clz(v); -#elif defined(_MSC_VER) - { - uint32_t idx; - _BitScanReverse(&idx, v); - return idx ^ 31U; - } -#else - return FLAC__clz_soft_uint32(v); -#endif -} - -/* Used when 64-bit bsr/clz is unavailable; can use 32-bit bsr/clz when possible */ -static inline uint32_t FLAC__clz_soft_uint64(FLAC__uint64 word) -{ - return (FLAC__uint32)(word>>32) ? FLAC__clz_uint32((FLAC__uint32)(word>>32)) : - FLAC__clz_uint32((FLAC__uint32)word) + 32; -} - -static inline uint32_t FLAC__clz_uint64(FLAC__uint64 v) -{ - /* Never used with input 0 */ - FLAC__ASSERT(v > 0); -#if defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) - return __builtin_clzll(v); -#elif (defined(__INTEL_COMPILER) || defined(_MSC_VER)) && (defined(_M_IA64) || defined(_M_X64)) - { - uint32_t idx; - _BitScanReverse64(&idx, v); - return idx ^ 63U; - } -#else - return FLAC__clz_soft_uint64(v); -#endif -} - -/* These two functions work with input 0 */ -static inline uint32_t FLAC__clz2_uint32(FLAC__uint32 v) -{ - if (!v) - return 32; - return FLAC__clz_uint32(v); -} - -static inline uint32_t FLAC__clz2_uint64(FLAC__uint64 v) -{ - if (!v) - return 64; - return FLAC__clz_uint64(v); -} - -/* An example of what FLAC__bitmath_ilog2() computes: - * - * ilog2( 0) = assertion failure - * ilog2( 1) = 0 - * ilog2( 2) = 1 - * ilog2( 3) = 1 - * ilog2( 4) = 2 - * ilog2( 5) = 2 - * ilog2( 6) = 2 - * ilog2( 7) = 2 - * ilog2( 8) = 3 - * ilog2( 9) = 3 - * ilog2(10) = 3 - * ilog2(11) = 3 - * ilog2(12) = 3 - * ilog2(13) = 3 - * ilog2(14) = 3 - * ilog2(15) = 3 - * ilog2(16) = 4 - * ilog2(17) = 4 - * ilog2(18) = 4 - */ - -static inline uint32_t FLAC__bitmath_ilog2(FLAC__uint32 v) -{ - FLAC__ASSERT(v > 0); -#if defined(__INTEL_COMPILER) - return _bit_scan_reverse(v); -#elif defined(_MSC_VER) - { - uint32_t idx; - _BitScanReverse(&idx, v); - return idx; - } -#else - return FLAC__clz_uint32(v) ^ 31U; -#endif -} - -static inline uint32_t FLAC__bitmath_ilog2_wide(FLAC__uint64 v) -{ - FLAC__ASSERT(v > 0); -#if defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) - return __builtin_clzll(v) ^ 63U; -/* Sorry, only supported in x64/Itanium.. and both have fast FPU which makes integer-only encoder pointless */ -#elif (defined(__INTEL_COMPILER) || defined(_MSC_VER)) && (defined(_M_IA64) || defined(_M_X64)) - { - uint32_t idx; - _BitScanReverse64(&idx, v); - return idx; - } -#else -/* Brain-damaged compilers will use the fastest possible way that is, - de Bruijn sequences (http://supertech.csail.mit.edu/papers/debruijn.pdf) - (C) Timothy B. Terriberry (tterribe@xiph.org) 2001-2009 CC0 (Public domain). -*/ - { - static const uint8_t DEBRUIJN_IDX64[64]={ - 0, 1, 2, 7, 3,13, 8,19, 4,25,14,28, 9,34,20,40, - 5,17,26,38,15,46,29,48,10,31,35,54,21,50,41,57, - 63, 6,12,18,24,27,33,39,16,37,45,47,30,53,49,56, - 62,11,23,32,36,44,52,55,61,22,43,51,60,42,59,58 - }; - v|= v>>1; - v|= v>>2; - v|= v>>4; - v|= v>>8; - v|= v>>16; - v|= v>>32; - v= (v>>1)+1; - return DEBRUIJN_IDX64[v*FLAC__U64L(0x218A392CD3D5DBF)>>58&0x3F]; - } -#endif -} - -uint32_t FLAC__bitmath_silog2(FLAC__int64 v); - -#endif diff --git a/lib/flac/src/include/private/bitreader.h b/lib/flac/src/include/private/bitreader.h deleted file mode 100644 index 585a5db..0000000 --- a/lib/flac/src/include/private/bitreader.h +++ /dev/null @@ -1,91 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PRIVATE__BITREADER_H -#define FLAC__PRIVATE__BITREADER_H - -#include /* for FILE */ -#include "FLAC/ordinals.h" -#include "cpu.h" - -/* - * opaque structure definition - */ -struct FLAC__BitReader; -typedef struct FLAC__BitReader FLAC__BitReader; - -typedef FLAC__bool (*FLAC__BitReaderReadCallback)(FLAC__byte buffer[], size_t *bytes, void *client_data); - -/* - * construction, deletion, initialization, etc functions - */ -FLAC__BitReader *FLAC__bitreader_new(void); -void FLAC__bitreader_delete(FLAC__BitReader *br); -FLAC__bool FLAC__bitreader_init(FLAC__BitReader *br, FLAC__BitReaderReadCallback rcb, void *cd); -void FLAC__bitreader_free(FLAC__BitReader *br); /* does not 'free(br)' */ -FLAC__bool FLAC__bitreader_clear(FLAC__BitReader *br); -void FLAC__bitreader_dump(const FLAC__BitReader *br, FILE *out); - -/* - * CRC functions - */ -void FLAC__bitreader_reset_read_crc16(FLAC__BitReader *br, FLAC__uint16 seed); -FLAC__uint16 FLAC__bitreader_get_read_crc16(FLAC__BitReader *br); - -/* - * info functions - */ -FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br); -uint32_t FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br); -uint32_t FLAC__bitreader_get_input_bits_unconsumed(const FLAC__BitReader *br); - -/* - * read functions - */ - -FLAC__bool FLAC__bitreader_read_raw_uint32(FLAC__BitReader *br, FLAC__uint32 *val, uint32_t bits); -FLAC__bool FLAC__bitreader_read_raw_int32(FLAC__BitReader *br, FLAC__int32 *val, uint32_t bits); -FLAC__bool FLAC__bitreader_read_raw_uint64(FLAC__BitReader *br, FLAC__uint64 *val, uint32_t bits); -FLAC__bool FLAC__bitreader_read_uint32_little_endian(FLAC__BitReader *br, FLAC__uint32 *val); /*only for bits=32*/ -FLAC__bool FLAC__bitreader_skip_bits_no_crc(FLAC__BitReader *br, uint32_t bits); /* WATCHOUT: does not CRC the skipped data! */ /*@@@@ add to unit tests */ -FLAC__bool FLAC__bitreader_skip_byte_block_aligned_no_crc(FLAC__BitReader *br, uint32_t nvals); /* WATCHOUT: does not CRC the read data! */ -FLAC__bool FLAC__bitreader_read_byte_block_aligned_no_crc(FLAC__BitReader *br, FLAC__byte *val, uint32_t nvals); /* WATCHOUT: does not CRC the read data! */ -FLAC__bool FLAC__bitreader_read_unary_unsigned(FLAC__BitReader *br, uint32_t *val); -FLAC__bool FLAC__bitreader_read_rice_signed(FLAC__BitReader *br, int *val, uint32_t parameter); -FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], uint32_t nvals, uint32_t parameter); -#if 0 /* UNUSED */ -FLAC__bool FLAC__bitreader_read_golomb_signed(FLAC__BitReader *br, int *val, uint32_t parameter); -FLAC__bool FLAC__bitreader_read_golomb_unsigned(FLAC__BitReader *br, uint32_t *val, uint32_t parameter); -#endif -FLAC__bool FLAC__bitreader_read_utf8_uint32(FLAC__BitReader *br, FLAC__uint32 *val, FLAC__byte *raw, uint32_t *rawlen); -FLAC__bool FLAC__bitreader_read_utf8_uint64(FLAC__BitReader *br, FLAC__uint64 *val, FLAC__byte *raw, uint32_t *rawlen); -#endif diff --git a/lib/flac/src/include/private/bitwriter.h b/lib/flac/src/include/private/bitwriter.h deleted file mode 100644 index 672f282..0000000 --- a/lib/flac/src/include/private/bitwriter.h +++ /dev/null @@ -1,104 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PRIVATE__BITWRITER_H -#define FLAC__PRIVATE__BITWRITER_H - -#include /* for FILE */ -#include "FLAC/ordinals.h" - -/* - * opaque structure definition - */ -struct FLAC__BitWriter; -typedef struct FLAC__BitWriter FLAC__BitWriter; - -/* - * construction, deletion, initialization, etc functions - */ -FLAC__BitWriter *FLAC__bitwriter_new(void); -void FLAC__bitwriter_delete(FLAC__BitWriter *bw); -FLAC__bool FLAC__bitwriter_init(FLAC__BitWriter *bw); -void FLAC__bitwriter_free(FLAC__BitWriter *bw); /* does not 'free(buffer)' */ -void FLAC__bitwriter_clear(FLAC__BitWriter *bw); -void FLAC__bitwriter_dump(const FLAC__BitWriter *bw, FILE *out); - -/* - * CRC functions - * - * non-const *bw because they have to cal FLAC__bitwriter_get_buffer() - */ -FLAC__bool FLAC__bitwriter_get_write_crc16(FLAC__BitWriter *bw, FLAC__uint16 *crc); -FLAC__bool FLAC__bitwriter_get_write_crc8(FLAC__BitWriter *bw, FLAC__byte *crc); - -/* - * info functions - */ -FLAC__bool FLAC__bitwriter_is_byte_aligned(const FLAC__BitWriter *bw); -uint32_t FLAC__bitwriter_get_input_bits_unconsumed(const FLAC__BitWriter *bw); /* can be called anytime, returns total # of bits unconsumed */ - -/* - * direct buffer access - * - * there may be no calls on the bitwriter between get and release. - * the bitwriter continues to own the returned buffer. - * before get, bitwriter MUST be byte aligned: check with FLAC__bitwriter_is_byte_aligned() - */ -FLAC__bool FLAC__bitwriter_get_buffer(FLAC__BitWriter *bw, const FLAC__byte **buffer, size_t *bytes); -void FLAC__bitwriter_release_buffer(FLAC__BitWriter *bw); - -/* - * write functions - */ -FLAC__bool FLAC__bitwriter_write_zeroes(FLAC__BitWriter *bw, uint32_t bits); -FLAC__bool FLAC__bitwriter_write_raw_uint32(FLAC__BitWriter *bw, FLAC__uint32 val, uint32_t bits); -FLAC__bool FLAC__bitwriter_write_raw_int32(FLAC__BitWriter *bw, FLAC__int32 val, uint32_t bits); -FLAC__bool FLAC__bitwriter_write_raw_uint64(FLAC__BitWriter *bw, FLAC__uint64 val, uint32_t bits); -FLAC__bool FLAC__bitwriter_write_raw_uint32_little_endian(FLAC__BitWriter *bw, FLAC__uint32 val); /*only for bits=32*/ -FLAC__bool FLAC__bitwriter_write_byte_block(FLAC__BitWriter *bw, const FLAC__byte vals[], uint32_t nvals); -FLAC__bool FLAC__bitwriter_write_unary_unsigned(FLAC__BitWriter *bw, uint32_t val); -uint32_t FLAC__bitwriter_rice_bits(FLAC__int32 val, uint32_t parameter); -#if 0 /* UNUSED */ -uint32_t FLAC__bitwriter_golomb_bits_signed(int val, uint32_t parameter); -uint32_t FLAC__bitwriter_golomb_bits_unsigned(uint32_t val, uint32_t parameter); -#endif -FLAC__bool FLAC__bitwriter_write_rice_signed(FLAC__BitWriter *bw, FLAC__int32 val, uint32_t parameter); -FLAC__bool FLAC__bitwriter_write_rice_signed_block(FLAC__BitWriter *bw, const FLAC__int32 *vals, uint32_t nvals, uint32_t parameter); -#if 0 /* UNUSED */ -FLAC__bool FLAC__bitwriter_write_golomb_signed(FLAC__BitWriter *bw, int val, uint32_t parameter); -FLAC__bool FLAC__bitwriter_write_golomb_unsigned(FLAC__BitWriter *bw, uint32_t val, uint32_t parameter); -#endif -FLAC__bool FLAC__bitwriter_write_utf8_uint32(FLAC__BitWriter *bw, FLAC__uint32 val); -FLAC__bool FLAC__bitwriter_write_utf8_uint64(FLAC__BitWriter *bw, FLAC__uint64 val); -FLAC__bool FLAC__bitwriter_zero_pad_to_byte_boundary(FLAC__BitWriter *bw); - -#endif diff --git a/lib/flac/src/include/private/cpu.h b/lib/flac/src/include/private/cpu.h deleted file mode 100644 index fc31350..0000000 --- a/lib/flac/src/include/private/cpu.h +++ /dev/null @@ -1,195 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PRIVATE__CPU_H -#define FLAC__PRIVATE__CPU_H - -#include "FLAC/ordinals.h" - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef FLAC__CPU_X86_64 - -#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64) -#define FLAC__CPU_X86_64 -#endif - -#endif - -#ifndef FLAC__CPU_IA32 - -#if defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) ||defined( __i386) || defined(_M_IX86) -#define FLAC__CPU_IA32 -#endif - -#endif - -#ifndef __has_attribute -#define __has_attribute(x) 0 -#endif - -#if FLAC__HAS_X86INTRIN -/* SSE intrinsics support by ICC/MSVC/GCC */ -#if defined __INTEL_COMPILER - #define FLAC__SSE_TARGET(x) - #define FLAC__SSE_SUPPORTED 1 - #define FLAC__SSE2_SUPPORTED 1 - #if (__INTEL_COMPILER >= 1000) /* Intel C++ Compiler 10.0 */ - #define FLAC__SSSE3_SUPPORTED 1 - #define FLAC__SSE4_1_SUPPORTED 1 - #endif - #if (__INTEL_COMPILER >= 1110) /* Intel C++ Compiler 11.1 */ - #define FLAC__AVX_SUPPORTED 1 - #endif - #if (__INTEL_COMPILER >= 1300) /* Intel C++ Compiler 13.0 */ - #define FLAC__AVX2_SUPPORTED 1 - #define FLAC__FMA_SUPPORTED 1 - #endif -#elif defined __clang__ && __has_attribute(__target__) /* clang */ - #define FLAC__SSE_TARGET(x) __attribute__ ((__target__ (x))) - #if __has_builtin(__builtin_ia32_maxps) - #define FLAC__SSE_SUPPORTED 1 - #endif - #if __has_builtin(__builtin_ia32_pmuludq128) - #define FLAC__SSE2_SUPPORTED 1 - #endif - #if __has_builtin(__builtin_ia32_pabsd128) - #define FLAC__SSSE3_SUPPORTED 1 - #endif - #if __has_builtin(__builtin_ia32_pmuldq128) - #define FLAC__SSE4_1_SUPPORTED 1 - #endif - #if __has_builtin(__builtin_ia32_pabsd256) - #define FLAC__AVX2_SUPPORTED 1 - #endif -#elif defined __GNUC__ && !defined __clang__ && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) /* GCC 4.9+ */ - #define FLAC__SSE_TARGET(x) __attribute__ ((__target__ (x))) - #define FLAC__SSE_SUPPORTED 1 - #define FLAC__SSE2_SUPPORTED 1 - #define FLAC__SSSE3_SUPPORTED 1 - #define FLAC__SSE4_1_SUPPORTED 1 - #ifdef FLAC__USE_AVX - #define FLAC__AVX_SUPPORTED 1 - #define FLAC__AVX2_SUPPORTED 1 - #define FLAC__FMA_SUPPORTED 1 - #endif -#elif defined _MSC_VER - #define FLAC__SSE_TARGET(x) - #define FLAC__SSE_SUPPORTED 1 - #define FLAC__SSE2_SUPPORTED 1 - #if (_MSC_VER >= 1500) /* MS Visual Studio 2008 */ - #define FLAC__SSSE3_SUPPORTED 1 - #define FLAC__SSE4_1_SUPPORTED 1 - #endif - #if (_MSC_FULL_VER >= 160040219) /* MS Visual Studio 2010 SP1 */ - #define FLAC__AVX_SUPPORTED 1 - #endif - #if (_MSC_VER >= 1700) /* MS Visual Studio 2012 */ - #define FLAC__AVX2_SUPPORTED 1 - #define FLAC__FMA_SUPPORTED 1 - #endif -#else - #define FLAC__SSE_TARGET(x) - #ifdef __SSE__ - #define FLAC__SSE_SUPPORTED 1 - #endif - #ifdef __SSE2__ - #define FLAC__SSE2_SUPPORTED 1 - #endif - #ifdef __SSSE3__ - #define FLAC__SSSE3_SUPPORTED 1 - #endif - #ifdef __SSE4_1__ - #define FLAC__SSE4_1_SUPPORTED 1 - #endif - #ifdef __AVX__ - #define FLAC__AVX_SUPPORTED 1 - #endif - #ifdef __AVX2__ - #define FLAC__AVX2_SUPPORTED 1 - #endif - #ifdef __FMA__ - #define FLAC__FMA_SUPPORTED 1 - #endif -#endif /* compiler version */ -#endif /* intrinsics support */ - - -#ifndef FLAC__AVX_SUPPORTED -#define FLAC__AVX_SUPPORTED 0 -#endif - -typedef enum { - FLAC__CPUINFO_TYPE_IA32, - FLAC__CPUINFO_TYPE_X86_64, - FLAC__CPUINFO_TYPE_PPC, - FLAC__CPUINFO_TYPE_UNKNOWN -} FLAC__CPUInfo_Type; - -typedef struct { - FLAC__bool intel; - - FLAC__bool cmov; - FLAC__bool mmx; - FLAC__bool sse; - FLAC__bool sse2; - - FLAC__bool sse3; - FLAC__bool ssse3; - FLAC__bool sse41; - FLAC__bool sse42; - FLAC__bool avx; - FLAC__bool avx2; - FLAC__bool fma; -} FLAC__CPUInfo_x86; - -typedef struct { - FLAC__bool arch_3_00; - FLAC__bool arch_2_07; -} FLAC__CPUInfo_ppc; - -typedef struct { - FLAC__bool use_asm; - FLAC__CPUInfo_Type type; - FLAC__CPUInfo_x86 x86; - FLAC__CPUInfo_ppc ppc; -} FLAC__CPUInfo; - -void FLAC__cpu_info(FLAC__CPUInfo *info); - -FLAC__uint32 FLAC__cpu_have_cpuid_asm_ia32(void); - -void FLAC__cpu_info_asm_ia32(FLAC__uint32 level, FLAC__uint32 *eax, FLAC__uint32 *ebx, FLAC__uint32 *ecx, FLAC__uint32 *edx); - -#endif diff --git a/lib/flac/src/include/private/crc.h b/lib/flac/src/include/private/crc.h deleted file mode 100644 index 5fc7e5e..0000000 --- a/lib/flac/src/include/private/crc.h +++ /dev/null @@ -1,60 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2018 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PRIVATE__CRC_H -#define FLAC__PRIVATE__CRC_H - -#include "FLAC/ordinals.h" - -/* 8 bit CRC generator, MSB shifted first -** polynomial = x^8 + x^2 + x^1 + x^0 -** init = 0 -*/ -FLAC__uint8 FLAC__crc8(const FLAC__byte *data, uint32_t len); - -/* 16 bit CRC generator, MSB shifted first -** polynomial = x^16 + x^15 + x^2 + x^0 -** init = 0 -*/ -extern FLAC__uint16 const FLAC__crc16_table[8][256]; - -#define FLAC__CRC16_UPDATE(data, crc) ((((crc)<<8) & 0xffff) ^ FLAC__crc16_table[0][((crc)>>8) ^ (data)]) -/* this alternate may be faster on some systems/compilers */ -#if 0 -#define FLAC__CRC16_UPDATE(data, crc) ((((crc)<<8) ^ FLAC__crc16_table[0][((crc)>>8) ^ (data)]) & 0xffff) -#endif - -FLAC__uint16 FLAC__crc16(const FLAC__byte *data, uint32_t len); -FLAC__uint16 FLAC__crc16_update_words32(const FLAC__uint32 *words, uint32_t len, FLAC__uint16 crc); -FLAC__uint16 FLAC__crc16_update_words64(const FLAC__uint64 *words, uint32_t len, FLAC__uint16 crc); - -#endif diff --git a/lib/flac/src/include/private/fixed.h b/lib/flac/src/include/private/fixed.h deleted file mode 100644 index 9edf0ab..0000000 --- a/lib/flac/src/include/private/fixed.h +++ /dev/null @@ -1,107 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PRIVATE__FIXED_H -#define FLAC__PRIVATE__FIXED_H - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "private/cpu.h" -#include "private/float.h" -#include "FLAC/format.h" - -/* - * FLAC__fixed_compute_best_predictor() - * -------------------------------------------------------------------- - * Compute the best fixed predictor and the expected bits-per-sample - * of the residual signal for each order. The _wide() version uses - * 64-bit integers which is statistically necessary when bits-per- - * sample + log2(blocksize) > 30 - * - * IN data[0,data_len-1] - * IN data_len - * OUT residual_bits_per_sample[0,FLAC__MAX_FIXED_ORDER] - */ -#ifndef FLAC__INTEGER_ONLY_LIBRARY -uint32_t FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); -uint32_t FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); -# ifndef FLAC__NO_ASM -# if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN -# ifdef FLAC__SSE2_SUPPORTED -uint32_t FLAC__fixed_compute_best_predictor_intrin_sse2(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1]); -uint32_t FLAC__fixed_compute_best_predictor_wide_intrin_sse2(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1]); -# endif -# ifdef FLAC__SSSE3_SUPPORTED -uint32_t FLAC__fixed_compute_best_predictor_intrin_ssse3(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); -uint32_t FLAC__fixed_compute_best_predictor_wide_intrin_ssse3(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1]); -# endif -# endif -# if defined FLAC__CPU_IA32 && defined FLAC__HAS_NASM -uint32_t FLAC__fixed_compute_best_predictor_asm_ia32_mmx_cmov(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); -# endif -# endif -#else -uint32_t FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); -uint32_t FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); -#endif - -/* - * FLAC__fixed_compute_residual() - * -------------------------------------------------------------------- - * Compute the residual signal obtained from sutracting the predicted - * signal from the original. - * - * IN data[-order,data_len-1] original signal (NOTE THE INDICES!) - * IN data_len length of original signal - * IN order <= FLAC__MAX_FIXED_ORDER fixed-predictor order - * OUT residual[0,data_len-1] residual signal - */ -void FLAC__fixed_compute_residual(const FLAC__int32 data[], uint32_t data_len, uint32_t order, FLAC__int32 residual[]); - -/* - * FLAC__fixed_restore_signal() - * -------------------------------------------------------------------- - * Restore the original signal by summing the residual and the - * predictor. - * - * IN residual[0,data_len-1] residual signal - * IN data_len length of original signal - * IN order <= FLAC__MAX_FIXED_ORDER fixed-predictor order - * *** IMPORTANT: the caller must pass in the historical samples: - * IN data[-order,-1] previously-reconstructed historical samples - * OUT data[0,data_len-1] original signal - */ -void FLAC__fixed_restore_signal(const FLAC__int32 residual[], uint32_t data_len, uint32_t order, FLAC__int32 data[]); - -#endif diff --git a/lib/flac/src/include/private/float.h b/lib/flac/src/include/private/float.h deleted file mode 100644 index cb32da4..0000000 --- a/lib/flac/src/include/private/float.h +++ /dev/null @@ -1,95 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2004-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PRIVATE__FLOAT_H -#define FLAC__PRIVATE__FLOAT_H - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "FLAC/ordinals.h" - -/* - * All the code in libFLAC that uses float and double - * should be protected by checks of the macro - * FLAC__INTEGER_ONLY_LIBRARY. - * - */ -#ifndef FLAC__INTEGER_ONLY_LIBRARY -/* - * FLAC__real is the basic floating point type used in LPC analysis. - * - * WATCHOUT: changing FLAC__real will change the signatures of many - * functions that have assembly language equivalents and break them. - */ -typedef float FLAC__real; -#else -/* - * The convention for FLAC__fixedpoint is to use the upper 16 bits - * for the integer part and lower 16 bits for the fractional part. - */ -typedef FLAC__int32 FLAC__fixedpoint; -extern const FLAC__fixedpoint FLAC__FP_ZERO; -extern const FLAC__fixedpoint FLAC__FP_ONE_HALF; -extern const FLAC__fixedpoint FLAC__FP_ONE; -extern const FLAC__fixedpoint FLAC__FP_LN2; -extern const FLAC__fixedpoint FLAC__FP_E; - -#define FLAC__fixedpoint_trunc(x) ((x)>>16) - -#define FLAC__fixedpoint_mul(x, y) ( (FLAC__fixedpoint) ( ((FLAC__int64)(x)*(FLAC__int64)(y)) >> 16 ) ) - -#define FLAC__fixedpoint_div(x, y) ( (FLAC__fixedpoint) ( ( ((FLAC__int64)(x)<<32) / (FLAC__int64)(y) ) >> 16 ) ) - -/* - * FLAC__fixedpoint_log2() - * -------------------------------------------------------------------- - * Returns the base-2 logarithm of the fixed-point number 'x' using an - * algorithm by Knuth for x >= 1.0 - * - * 'fracbits' is the number of fractional bits of 'x'. 'fracbits' must - * be < 32 and evenly divisible by 4 (0 is OK but not very precise). - * - * 'precision' roughly limits the number of iterations that are done; - * use (uint32_t)(-1) for maximum precision. - * - * If 'x' is less than one -- that is, x < (1< -#endif - -#include "private/cpu.h" -#include "private/float.h" -#include "FLAC/format.h" - -#ifndef FLAC__INTEGER_ONLY_LIBRARY - -/* - * FLAC__lpc_window_data() - * -------------------------------------------------------------------- - * Applies the given window to the data. - * OPT: asm implementation - * - * IN in[0,data_len-1] - * IN window[0,data_len-1] - * OUT out[0,lag-1] - * IN data_len - */ -void FLAC__lpc_window_data(const FLAC__int32 in[], const FLAC__real window[], FLAC__real out[], uint32_t data_len); - -/* - * FLAC__lpc_compute_autocorrelation() - * -------------------------------------------------------------------- - * Compute the autocorrelation for lags between 0 and lag-1. - * Assumes data[] outside of [0,data_len-1] == 0. - * Asserts that lag > 0. - * - * IN data[0,data_len-1] - * IN data_len - * IN 0 < lag <= data_len - * OUT autoc[0,lag-1] - */ -void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]); -#ifndef FLAC__NO_ASM -# ifdef FLAC__CPU_IA32 -# ifdef FLAC__HAS_NASM -void FLAC__lpc_compute_autocorrelation_asm_ia32(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]); -void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_4_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]); -void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_8_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]); -void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_12_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]); -void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_16_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]); -# endif -# endif -# if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN -# ifdef FLAC__SSE_SUPPORTED -void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]); -void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]); -void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]); -void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]); -void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4_new(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]); -void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8_new(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]); -void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12_new(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]); -void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16_new(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]); -# endif -# endif -#if defined(FLAC__CPU_PPC64) && defined(FLAC__USE_VSX) -#ifdef FLAC__HAS_TARGET_POWER9 -void FLAC__lpc_compute_autocorrelation_intrin_power9_vsx_lag_4(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]); -void FLAC__lpc_compute_autocorrelation_intrin_power9_vsx_lag_8(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]); -void FLAC__lpc_compute_autocorrelation_intrin_power9_vsx_lag_12(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]); -void FLAC__lpc_compute_autocorrelation_intrin_power9_vsx_lag_16(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]); -#endif -#ifdef FLAC__HAS_TARGET_POWER8 -void FLAC__lpc_compute_autocorrelation_intrin_power8_vsx_lag_4(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]); -void FLAC__lpc_compute_autocorrelation_intrin_power8_vsx_lag_8(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]); -void FLAC__lpc_compute_autocorrelation_intrin_power8_vsx_lag_12(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]); -void FLAC__lpc_compute_autocorrelation_intrin_power8_vsx_lag_16(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]); -#endif -#endif -#endif - -/* - * FLAC__lpc_compute_lp_coefficients() - * -------------------------------------------------------------------- - * Computes LP coefficients for orders 1..max_order. - * Do not call if autoc[0] == 0.0. This means the signal is zero - * and there is no point in calculating a predictor. - * - * IN autoc[0,max_order] autocorrelation values - * IN 0 < max_order <= FLAC__MAX_LPC_ORDER max LP order to compute - * OUT lp_coeff[0,max_order-1][0,max_order-1] LP coefficients for each order - * *** IMPORTANT: - * *** lp_coeff[0,max_order-1][max_order,FLAC__MAX_LPC_ORDER-1] are untouched - * OUT error[0,max_order-1] error for each order (more - * specifically, the variance of - * the error signal times # of - * samples in the signal) - * - * Example: if max_order is 9, the LP coefficients for order 9 will be - * in lp_coeff[8][0,8], the LP coefficients for order 8 will be - * in lp_coeff[7][0,7], etc. - */ -void FLAC__lpc_compute_lp_coefficients(const FLAC__real autoc[], uint32_t *max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], double error[]); - -/* - * FLAC__lpc_quantize_coefficients() - * -------------------------------------------------------------------- - * Quantizes the LP coefficients. NOTE: precision + bits_per_sample - * must be less than 32 (sizeof(FLAC__int32)*8). - * - * IN lp_coeff[0,order-1] LP coefficients - * IN order LP order - * IN FLAC__MIN_QLP_COEFF_PRECISION < precision - * desired precision (in bits, including sign - * bit) of largest coefficient - * OUT qlp_coeff[0,order-1] quantized coefficients - * OUT shift # of bits to shift right to get approximated - * LP coefficients. NOTE: could be negative. - * RETURN 0 => quantization OK - * 1 => coefficients require too much shifting for *shift to - * fit in the LPC subframe header. 'shift' is unset. - * 2 => coefficients are all zero, which is bad. 'shift' is - * unset. - */ -int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], uint32_t order, uint32_t precision, FLAC__int32 qlp_coeff[], int *shift); - -/* - * FLAC__lpc_compute_residual_from_qlp_coefficients() - * -------------------------------------------------------------------- - * Compute the residual signal obtained from sutracting the predicted - * signal from the original. - * - * IN data[-order,data_len-1] original signal (NOTE THE INDICES!) - * IN data_len length of original signal - * IN qlp_coeff[0,order-1] quantized LP coefficients - * IN order > 0 LP order - * IN lp_quantization quantization of LP coefficients in bits - * OUT residual[0,data_len-1] residual signal - */ -void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); -void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); -#ifndef FLAC__NO_ASM -# ifdef FLAC__CPU_IA32 -# ifdef FLAC__HAS_NASM -void FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); -void FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); -void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_asm_ia32(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); -# endif -# endif -# if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN -# ifdef FLAC__SSE2_SUPPORTED -void FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_sse2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); -void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); -# endif -# ifdef FLAC__SSE4_1_SUPPORTED -void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse41(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); -void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_sse41(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); -# endif -# ifdef FLAC__AVX2_SUPPORTED -void FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_avx2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); -void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_avx2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); -void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_avx2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); -# endif -# endif -#endif - -#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ - -/* - * FLAC__lpc_restore_signal() - * -------------------------------------------------------------------- - * Restore the original signal by summing the residual and the - * predictor. - * - * IN residual[0,data_len-1] residual signal - * IN data_len length of original signal - * IN qlp_coeff[0,order-1] quantized LP coefficients - * IN order > 0 LP order - * IN lp_quantization quantization of LP coefficients in bits - * *** IMPORTANT: the caller must pass in the historical samples: - * IN data[-order,-1] previously-reconstructed historical samples - * OUT data[0,data_len-1] original signal - */ -void FLAC__lpc_restore_signal(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]); -void FLAC__lpc_restore_signal_wide(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]); -#ifndef FLAC__NO_ASM -# ifdef FLAC__CPU_IA32 -# ifdef FLAC__HAS_NASM -void FLAC__lpc_restore_signal_asm_ia32(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]); -void FLAC__lpc_restore_signal_asm_ia32_mmx(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]); -void FLAC__lpc_restore_signal_wide_asm_ia32(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]); -# endif /* FLAC__HAS_NASM */ -# endif /* FLAC__CPU_IA32 */ -# if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN -# ifdef FLAC__SSE4_1_SUPPORTED -void FLAC__lpc_restore_signal_intrin_sse41(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]); -void FLAC__lpc_restore_signal_16_intrin_sse41(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]); -void FLAC__lpc_restore_signal_wide_intrin_sse41(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]); -# endif -# endif -#endif /* FLAC__NO_ASM */ - -#ifndef FLAC__INTEGER_ONLY_LIBRARY - -/* - * FLAC__lpc_compute_expected_bits_per_residual_sample() - * -------------------------------------------------------------------- - * Compute the expected number of bits per residual signal sample - * based on the LP error (which is related to the residual variance). - * - * IN lpc_error >= 0.0 error returned from calculating LP coefficients - * IN total_samples > 0 # of samples in residual signal - * RETURN expected bits per sample - */ -double FLAC__lpc_compute_expected_bits_per_residual_sample(double lpc_error, uint32_t total_samples); -double FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(double lpc_error, double error_scale); - -/* - * FLAC__lpc_compute_best_order() - * -------------------------------------------------------------------- - * Compute the best order from the array of signal errors returned - * during coefficient computation. - * - * IN lpc_error[0,max_order-1] >= 0.0 error returned from calculating LP coefficients - * IN max_order > 0 max LP order - * IN total_samples > 0 # of samples in residual signal - * IN overhead_bits_per_order # of bits overhead for each increased LP order - * (includes warmup sample size and quantized LP coefficient) - * RETURN [1,max_order] best order - */ -uint32_t FLAC__lpc_compute_best_order(const double lpc_error[], uint32_t max_order, uint32_t total_samples, uint32_t overhead_bits_per_order); - -#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ - -#endif diff --git a/lib/flac/src/include/private/macros.h b/lib/flac/src/include/private/macros.h deleted file mode 100644 index 02eada4..0000000 --- a/lib/flac/src/include/private/macros.h +++ /dev/null @@ -1,72 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2012-2016 Xiph.org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PRIVATE__MACROS_H -#define FLAC__PRIVATE__MACROS_H - -#if defined(__GNUC__) && (__GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 3)) - -#define flac_max(a,b) \ - ({ __typeof__ (a) _a = (a); \ - __typeof__ (b) _b = (b); \ - _a > _b ? _a : _b; }) - -#define MIN_PASTE(A,B) A##B -#define MIN_IMPL(A,B,L) ({ \ - __typeof__(A) MIN_PASTE(__a,L) = (A); \ - __typeof__(B) MIN_PASTE(__b,L) = (B); \ - MIN_PASTE(__a,L) < MIN_PASTE(__b,L) ? MIN_PASTE(__a,L) : MIN_PASTE(__b,L); \ - }) - -#define flac_min(A,B) MIN_IMPL(A,B,__COUNTER__) - -/* Whatever other unix that has sys/param.h */ -#elif defined(HAVE_SYS_PARAM_H) -#include -#define flac_max(a,b) MAX(a,b) -#define flac_min(a,b) MIN(a,b) - -/* Windows VS has them in stdlib.h.. XXX:Untested */ -#elif defined(_MSC_VER) -#include -#define flac_max(a,b) __max(a,b) -#define flac_min(a,b) __min(a,b) -#endif - -#ifndef flac_min -#define flac_min(x,y) ((x) <= (y) ? (x) : (y)) -#endif - -#ifndef flac_max -#define flac_max(x,y) ((x) >= (y) ? (x) : (y)) -#endif - -#endif diff --git a/lib/flac/src/include/private/md5.h b/lib/flac/src/include/private/md5.h deleted file mode 100644 index f9d79c3..0000000 --- a/lib/flac/src/include/private/md5.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef FLAC__PRIVATE__MD5_H -#define FLAC__PRIVATE__MD5_H - -/* - * This is the header file for the MD5 message-digest algorithm. - * The algorithm is due to Ron Rivest. This code was - * written by Colin Plumb in 1993, no copyright is claimed. - * This code is in the public domain; do with it what you wish. - * - * Equivalent code is available from RSA Data Security, Inc. - * This code has been tested against that, and is equivalent, - * except that you don't need to include two pages of legalese - * with every copy. - * - * To compute the message digest of a chunk of bytes, declare an - * MD5Context structure, pass it to MD5Init, call MD5Update as - * needed on buffers full of bytes, and then call MD5Final, which - * will fill a supplied 16-byte array with the digest. - * - * Changed so as no longer to depend on Colin Plumb's `usual.h' - * header definitions; now uses stuff from dpkg's config.h - * - Ian Jackson . - * Still in the public domain. - * - * Josh Coalson: made some changes to integrate with libFLAC. - * Still in the public domain, with no warranty. - */ - -#include "FLAC/ordinals.h" - -typedef union { - FLAC__byte *p8; - FLAC__int16 *p16; - FLAC__int32 *p32; -} FLAC__multibyte; - -typedef struct { - FLAC__uint32 in[16]; - FLAC__uint32 buf[4]; - FLAC__uint32 bytes[2]; - FLAC__multibyte internal_buf; - size_t capacity; -} FLAC__MD5Context; - -void FLAC__MD5Init(FLAC__MD5Context *context); -void FLAC__MD5Final(FLAC__byte digest[16], FLAC__MD5Context *context); - -FLAC__bool FLAC__MD5Accumulate(FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], uint32_t channels, uint32_t samples, uint32_t bytes_per_sample); - -#endif diff --git a/lib/flac/src/include/private/memory.h b/lib/flac/src/include/private/memory.h deleted file mode 100644 index a6d3faf..0000000 --- a/lib/flac/src/include/private/memory.h +++ /dev/null @@ -1,58 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PRIVATE__MEMORY_H -#define FLAC__PRIVATE__MEMORY_H - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include /* for size_t */ - -#include "private/float.h" -#include "FLAC/ordinals.h" /* for FLAC__bool */ - -/* Returns the unaligned address returned by malloc. - * Use free() on this address to deallocate. - */ -void *FLAC__memory_alloc_aligned(size_t bytes, void **aligned_address); -FLAC__bool FLAC__memory_alloc_aligned_int32_array(size_t elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_pointer); -FLAC__bool FLAC__memory_alloc_aligned_uint32_array(size_t elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_pointer); -FLAC__bool FLAC__memory_alloc_aligned_uint64_array(size_t elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_pointer); -FLAC__bool FLAC__memory_alloc_aligned_unsigned_array(size_t elements, uint32_t **unaligned_pointer, uint32_t **aligned_pointer); -#ifndef FLAC__INTEGER_ONLY_LIBRARY -FLAC__bool FLAC__memory_alloc_aligned_real_array(size_t elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer); -#endif -void *safe_malloc_mul_2op_p(size_t size1, size_t size2); - -#endif diff --git a/lib/flac/src/include/private/metadata.h b/lib/flac/src/include/private/metadata.h deleted file mode 100644 index 161947f..0000000 --- a/lib/flac/src/include/private/metadata.h +++ /dev/null @@ -1,46 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2002-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PRIVATE__METADATA_H -#define FLAC__PRIVATE__METADATA_H - -#include "FLAC/metadata.h" - -/* WATCHOUT: all malloc()ed data in the block is free()ed; this may not - * be a consistent state (e.g. PICTURE) or equivalent to the initial - * state after FLAC__metadata_object_new() - */ -void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object); - -void FLAC__metadata_object_cuesheet_track_delete_data(FLAC__StreamMetadata_CueSheet_Track *object); - -#endif diff --git a/lib/flac/src/include/private/ogg_decoder_aspect.h b/lib/flac/src/include/private/ogg_decoder_aspect.h deleted file mode 100644 index 0a8534d..0000000 --- a/lib/flac/src/include/private/ogg_decoder_aspect.h +++ /dev/null @@ -1,80 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec - * Copyright (C) 2002-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PRIVATE__OGG_DECODER_ASPECT_H -#define FLAC__PRIVATE__OGG_DECODER_ASPECT_H - -#include - -#include "FLAC/ordinals.h" -#include "FLAC/stream_decoder.h" /* for FLAC__StreamDecoderReadStatus */ - -typedef struct FLAC__OggDecoderAspect { - /* these are storage for values that can be set through the API */ - FLAC__bool use_first_serial_number; - long serial_number; - - /* these are for internal state related to Ogg decoding */ - ogg_stream_state stream_state; - ogg_sync_state sync_state; - uint32_t version_major, version_minor; - FLAC__bool need_serial_number; - FLAC__bool end_of_stream; - FLAC__bool have_working_page; /* only if true will the following vars be valid */ - ogg_page working_page; - FLAC__bool have_working_packet; /* only if true will the following vars be valid */ - ogg_packet working_packet; /* as we work through the packet we will move working_packet.packet forward and working_packet.bytes down */ -} FLAC__OggDecoderAspect; - -void FLAC__ogg_decoder_aspect_set_serial_number(FLAC__OggDecoderAspect *aspect, long value); -void FLAC__ogg_decoder_aspect_set_defaults(FLAC__OggDecoderAspect *aspect); -FLAC__bool FLAC__ogg_decoder_aspect_init(FLAC__OggDecoderAspect *aspect); -void FLAC__ogg_decoder_aspect_finish(FLAC__OggDecoderAspect *aspect); -void FLAC__ogg_decoder_aspect_flush(FLAC__OggDecoderAspect *aspect); -void FLAC__ogg_decoder_aspect_reset(FLAC__OggDecoderAspect *aspect); - -typedef enum { - FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK = 0, - FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM, - FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC, - FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC, - FLAC__OGG_DECODER_ASPECT_READ_STATUS_UNSUPPORTED_MAPPING_VERSION, - FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT, - FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR, - FLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR -} FLAC__OggDecoderAspectReadStatus; - -typedef FLAC__OggDecoderAspectReadStatus (*FLAC__OggDecoderAspectReadCallbackProxy)(const void *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data); - -FLAC__OggDecoderAspectReadStatus FLAC__ogg_decoder_aspect_read_callback_wrapper(FLAC__OggDecoderAspect *aspect, FLAC__byte buffer[], size_t *bytes, FLAC__OggDecoderAspectReadCallbackProxy read_callback, const FLAC__StreamDecoder *decoder, void *client_data); - -#endif diff --git a/lib/flac/src/include/private/ogg_encoder_aspect.h b/lib/flac/src/include/private/ogg_encoder_aspect.h deleted file mode 100644 index f3c95f9..0000000 --- a/lib/flac/src/include/private/ogg_encoder_aspect.h +++ /dev/null @@ -1,63 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec - * Copyright (C) 2002-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PRIVATE__OGG_ENCODER_ASPECT_H -#define FLAC__PRIVATE__OGG_ENCODER_ASPECT_H - -#include - -#include "FLAC/ordinals.h" -#include "FLAC/stream_encoder.h" /* for FLAC__StreamEncoderWriteStatus */ - -typedef struct FLAC__OggEncoderAspect { - /* these are storage for values that can be set through the API */ - long serial_number; - uint32_t num_metadata; - - /* these are for internal state related to Ogg encoding */ - ogg_stream_state stream_state; - ogg_page page; - FLAC__bool seen_magic; /* true if we've seen the fLaC magic in the write callback yet */ - FLAC__bool is_first_packet; - FLAC__uint64 samples_written; -} FLAC__OggEncoderAspect; - -void FLAC__ogg_encoder_aspect_set_serial_number(FLAC__OggEncoderAspect *aspect, long value); -FLAC__bool FLAC__ogg_encoder_aspect_set_num_metadata(FLAC__OggEncoderAspect *aspect, uint32_t value); -void FLAC__ogg_encoder_aspect_set_defaults(FLAC__OggEncoderAspect *aspect); -FLAC__bool FLAC__ogg_encoder_aspect_init(FLAC__OggEncoderAspect *aspect); -void FLAC__ogg_encoder_aspect_finish(FLAC__OggEncoderAspect *aspect); - -typedef FLAC__StreamEncoderWriteStatus (*FLAC__OggEncoderAspectWriteCallbackProxy)(const void *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, void *client_data); - -FLAC__StreamEncoderWriteStatus FLAC__ogg_encoder_aspect_write_callback_wrapper(FLAC__OggEncoderAspect *aspect, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, FLAC__bool is_last_block, FLAC__OggEncoderAspectWriteCallbackProxy write_callback, void *encoder, void *client_data); -#endif diff --git a/lib/flac/src/include/private/ogg_helper.h b/lib/flac/src/include/private/ogg_helper.h deleted file mode 100644 index 4c1000c..0000000 --- a/lib/flac/src/include/private/ogg_helper.h +++ /dev/null @@ -1,44 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec - * Copyright (C) 2004-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PRIVATE__OGG_HELPER_H -#define FLAC__PRIVATE__OGG_HELPER_H - -#include -#include "FLAC/stream_encoder.h" /* for FLAC__StreamEncoder */ - -void simple_ogg_page__init(ogg_page *page); -void simple_ogg_page__clear(ogg_page *page); -FLAC__bool simple_ogg_page__get_at(FLAC__StreamEncoder *encoder, FLAC__uint64 position, ogg_page *page, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderReadCallback read_callback, void *client_data); -FLAC__bool simple_ogg_page__set_at(FLAC__StreamEncoder *encoder, FLAC__uint64 position, ogg_page *page, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderWriteCallback write_callback, void *client_data); - -#endif diff --git a/lib/flac/src/include/private/ogg_mapping.h b/lib/flac/src/include/private/ogg_mapping.h deleted file mode 100644 index 6eb609e..0000000 --- a/lib/flac/src/include/private/ogg_mapping.h +++ /dev/null @@ -1,64 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec - * Copyright (C) 2004-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PRIVATE__OGG_MAPPING_H -#define FLAC__PRIVATE__OGG_MAPPING_H - -#include "FLAC/ordinals.h" - -/** The length of the packet type field in bytes. */ -#define FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH (1u) - -extern const uint32_t FLAC__OGG_MAPPING_PACKET_TYPE_LEN; /* = 8 bits */ - -extern const FLAC__byte FLAC__OGG_MAPPING_FIRST_HEADER_PACKET_TYPE; /* = 0x7f */ - -/** The length of the 'FLAC' magic in bytes. */ -#define FLAC__OGG_MAPPING_MAGIC_LENGTH (4u) - -extern const FLAC__byte * const FLAC__OGG_MAPPING_MAGIC; /* = "FLAC" */ - -extern const uint32_t FLAC__OGG_MAPPING_VERSION_MAJOR_LEN; /* = 8 bits */ -extern const uint32_t FLAC__OGG_MAPPING_VERSION_MINOR_LEN; /* = 8 bits */ - -/** The length of the Ogg FLAC mapping major version number in bytes. */ -#define FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH (1u) - -/** The length of the Ogg FLAC mapping minor version number in bytes. */ -#define FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH (1u) - -extern const uint32_t FLAC__OGG_MAPPING_NUM_HEADERS_LEN; /* = 16 bits */ - -/** The length of the #-of-header-packets number bytes. */ -#define FLAC__OGG_MAPPING_NUM_HEADERS_LENGTH (2u) - -#endif diff --git a/lib/flac/src/include/private/stream_encoder.h b/lib/flac/src/include/private/stream_encoder.h deleted file mode 100644 index ade648b..0000000 --- a/lib/flac/src/include/private/stream_encoder.h +++ /dev/null @@ -1,67 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PRIVATE__STREAM_ENCODER_H -#define FLAC__PRIVATE__STREAM_ENCODER_H - -#ifdef HAVE_CONFIG_H -#include -#endif - -/* - * This is used to avoid overflow with unusual signals in 32-bit - * accumulator in the *precompute_partition_info_sums_* functions. - */ -#define FLAC__MAX_EXTRA_RESIDUAL_BPS 4 - -#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN -#include "private/cpu.h" -#include "FLAC/format.h" - -#ifdef FLAC__SSE2_SUPPORTED -extern void FLAC__precompute_partition_info_sums_intrin_sse2(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[], - uint32_t residual_samples, uint32_t predictor_order, uint32_t min_partition_order, uint32_t max_partition_order, uint32_t bps); -#endif - -#ifdef FLAC__SSSE3_SUPPORTED -extern void FLAC__precompute_partition_info_sums_intrin_ssse3(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[], - uint32_t residual_samples, uint32_t predictor_order, uint32_t min_partition_order, uint32_t max_partition_order, uint32_t bps); -#endif - -#ifdef FLAC__AVX2_SUPPORTED -extern void FLAC__precompute_partition_info_sums_intrin_avx2(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[], - uint32_t residual_samples, uint32_t predictor_order, uint32_t min_partition_order, uint32_t max_partition_order, uint32_t bps); -#endif - -#endif - -#endif diff --git a/lib/flac/src/include/private/stream_encoder_framing.h b/lib/flac/src/include/private/stream_encoder_framing.h deleted file mode 100644 index 8df1049..0000000 --- a/lib/flac/src/include/private/stream_encoder_framing.h +++ /dev/null @@ -1,46 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PRIVATE__STREAM_ENCODER_FRAMING_H -#define FLAC__PRIVATE__STREAM_ENCODER_FRAMING_H - -#include "FLAC/format.h" -#include "bitwriter.h" - -FLAC__bool FLAC__add_metadata_block(const FLAC__StreamMetadata *metadata, FLAC__BitWriter *bw); -FLAC__bool FLAC__frame_add_header(const FLAC__FrameHeader *header, FLAC__BitWriter *bw); -FLAC__bool FLAC__subframe_add_constant(const FLAC__Subframe_Constant *subframe, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw); -FLAC__bool FLAC__subframe_add_fixed(const FLAC__Subframe_Fixed *subframe, uint32_t residual_samples, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw); -FLAC__bool FLAC__subframe_add_lpc(const FLAC__Subframe_LPC *subframe, uint32_t residual_samples, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw); -FLAC__bool FLAC__subframe_add_verbatim(const FLAC__Subframe_Verbatim *subframe, uint32_t samples, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw); - -#endif diff --git a/lib/flac/src/include/private/window.h b/lib/flac/src/include/private/window.h deleted file mode 100644 index bfed774..0000000 --- a/lib/flac/src/include/private/window.h +++ /dev/null @@ -1,74 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2006-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PRIVATE__WINDOW_H -#define FLAC__PRIVATE__WINDOW_H - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "private/float.h" -#include "FLAC/format.h" - -#ifndef FLAC__INTEGER_ONLY_LIBRARY - -/* - * FLAC__window_*() - * -------------------------------------------------------------------- - * Calculates window coefficients according to different apodization - * functions. - * - * OUT window[0,L-1] - * IN L (number of points in window) - */ -void FLAC__window_bartlett(FLAC__real *window, const FLAC__int32 L); -void FLAC__window_bartlett_hann(FLAC__real *window, const FLAC__int32 L); -void FLAC__window_blackman(FLAC__real *window, const FLAC__int32 L); -void FLAC__window_blackman_harris_4term_92db_sidelobe(FLAC__real *window, const FLAC__int32 L); -void FLAC__window_connes(FLAC__real *window, const FLAC__int32 L); -void FLAC__window_flattop(FLAC__real *window, const FLAC__int32 L); -void FLAC__window_gauss(FLAC__real *window, const FLAC__int32 L, const FLAC__real stddev); /* 0.0 < stddev <= 0.5 */ -void FLAC__window_hamming(FLAC__real *window, const FLAC__int32 L); -void FLAC__window_hann(FLAC__real *window, const FLAC__int32 L); -void FLAC__window_kaiser_bessel(FLAC__real *window, const FLAC__int32 L); -void FLAC__window_nuttall(FLAC__real *window, const FLAC__int32 L); -void FLAC__window_rectangle(FLAC__real *window, const FLAC__int32 L); -void FLAC__window_triangle(FLAC__real *window, const FLAC__int32 L); -void FLAC__window_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p); -void FLAC__window_partial_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end); -void FLAC__window_punchout_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end); -void FLAC__window_welch(FLAC__real *window, const FLAC__int32 L); - -#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ - -#endif diff --git a/lib/flac/src/include/protected/Makefile.am b/lib/flac/src/include/protected/Makefile.am deleted file mode 100644 index d9c6476..0000000 --- a/lib/flac/src/include/protected/Makefile.am +++ /dev/null @@ -1,35 +0,0 @@ -# libFLAC - Free Lossless Audio Codec library -# Copyright (C) 2001-2009 Josh Coalson -# Copyright (C) 2011-2016 Xiph.Org Foundation -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# - Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# - Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# - Neither the name of the Xiph.org Foundation nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -noinst_HEADERS = \ - all.h \ - stream_decoder.h \ - stream_encoder.h diff --git a/lib/flac/src/include/protected/Makefile.in b/lib/flac/src/include/protected/Makefile.in deleted file mode 100644 index eb3b781..0000000 --- a/lib/flac/src/include/protected/Makefile.in +++ /dev/null @@ -1,589 +0,0 @@ -# Makefile.in generated by automake 1.16.1 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994-2018 Free Software Foundation, Inc. - -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - -# libFLAC - Free Lossless Audio Codec library -# Copyright (C) 2001-2009 Josh Coalson -# Copyright (C) 2011-2016 Xiph.Org Foundation -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# - Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# - Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# - Neither the name of the Xiph.org Foundation nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -VPATH = @srcdir@ -am__is_gnu_make = { \ - if test -z '$(MAKELEVEL)'; then \ - false; \ - elif test -n '$(MAKE_HOST)'; then \ - true; \ - elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ - true; \ - else \ - false; \ - fi; \ -} -am__make_running_with_option = \ - case $${target_option-} in \ - ?) ;; \ - *) echo "am__make_running_with_option: internal error: invalid" \ - "target option '$${target_option-}' specified" >&2; \ - exit 1;; \ - esac; \ - has_opt=no; \ - sane_makeflags=$$MAKEFLAGS; \ - if $(am__is_gnu_make); then \ - sane_makeflags=$$MFLAGS; \ - else \ - case $$MAKEFLAGS in \ - *\\[\ \ ]*) \ - bs=\\; \ - sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ - | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ - esac; \ - fi; \ - skip_next=no; \ - strip_trailopt () \ - { \ - flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ - }; \ - for flg in $$sane_makeflags; do \ - test $$skip_next = yes && { skip_next=no; continue; }; \ - case $$flg in \ - *=*|--*) continue;; \ - -*I) strip_trailopt 'I'; skip_next=yes;; \ - -*I?*) strip_trailopt 'I';; \ - -*O) strip_trailopt 'O'; skip_next=yes;; \ - -*O?*) strip_trailopt 'O';; \ - -*l) strip_trailopt 'l'; skip_next=yes;; \ - -*l?*) strip_trailopt 'l';; \ - -[dEDm]) skip_next=yes;; \ - -[JT]) skip_next=yes;; \ - esac; \ - case $$flg in \ - *$$target_option*) has_opt=yes; break;; \ - esac; \ - done; \ - test $$has_opt = yes -am__make_dryrun = (target_option=n; $(am__make_running_with_option)) -am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -subdir = src/libFLAC/include/protected -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/add_cflags.m4 \ - $(top_srcdir)/m4/add_cxxflags.m4 \ - $(top_srcdir)/m4/ax_add_fortify_source.m4 \ - $(top_srcdir)/m4/ax_check_enable_debug.m4 \ - $(top_srcdir)/m4/bswap.m4 $(top_srcdir)/m4/c_attribute.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)/m4/xmms.m4 \ - $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ - $(am__DIST_COMMON) -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = $(top_builddir)/config.h -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -AM_V_P = $(am__v_P_@AM_V@) -am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) -am__v_P_0 = false -am__v_P_1 = : -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = -SOURCES = -DIST_SOURCES = -am__can_run_installinfo = \ - case $$AM_UPDATE_INFO_DIR in \ - n|no|NO) false;; \ - *) (install-info --version) >/dev/null 2>&1;; \ - esac -HEADERS = $(noinst_HEADERS) -am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) -# Read a list of newline-separated strings from the standard input, -# and print each of them once, without duplicates. Input order is -# *not* preserved. -am__uniquify_input = $(AWK) '\ - BEGIN { nonempty = 0; } \ - { items[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in items) print i; }; } \ -' -# Make sure the list of sources is unique. This is necessary because, -# e.g., the same source file might be shared among _SOURCES variables -# for different programs/libraries. -am__define_uniq_tagged_files = \ - list='$(am__tagged_files)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | $(am__uniquify_input)` -ETAGS = etags -CTAGS = ctags -am__DIST_COMMON = $(srcdir)/Makefile.in -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = @ACLOCAL@ -AMTAR = @AMTAR@ -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ -AR = @AR@ -AS = @AS@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -CC = @CC@ -CCAS = @CCAS@ -CCASDEPMODE = @CCASDEPMODE@ -CCASFLAGS = @CCASFLAGS@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ -CXX = @CXX@ -CXXCPP = @CXXCPP@ -CXXDEPMODE = @CXXDEPMODE@ -CXXFLAGS = @CXXFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -DLLTOOL = @DLLTOOL@ -DOCBOOK_TO_MAN = @DOCBOOK_TO_MAN@ -DOXYGEN = @DOXYGEN@ -DSYMUTIL = @DSYMUTIL@ -DUMPBIN = @DUMPBIN@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -ENABLE_64_BIT_WORDS = @ENABLE_64_BIT_WORDS@ -EXEEXT = @EXEEXT@ -FGREP = @FGREP@ -FLAC__HAS_OGG = @FLAC__HAS_OGG@ -FLAC__TEST_LEVEL = @FLAC__TEST_LEVEL@ -FLAC__TEST_WITH_VALGRIND = @FLAC__TEST_WITH_VALGRIND@ -GCC_MAJOR_VERSION = @GCC_MAJOR_VERSION@ -GCC_MINOR_VERSION = @GCC_MINOR_VERSION@ -GCC_VERSION = @GCC_VERSION@ -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@ -LIPO = @LIPO@ -LN_S = @LN_S@ -LTLIBICONV = @LTLIBICONV@ -LTLIBOBJS = @LTLIBOBJS@ -LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ -MAKEINFO = @MAKEINFO@ -MANIFEST_TOOL = @MANIFEST_TOOL@ -MKDIR_P = @MKDIR_P@ -NASM = @NASM@ -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@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -RANLIB = @RANLIB@ -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_DUMPBIN = @ac_ct_DUMPBIN@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localedir = @localedir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -runstatedir = @runstatedir@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -srcdir = @srcdir@ -sysconfdir = @sysconfdir@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -noinst_HEADERS = \ - all.h \ - stream_decoder.h \ - stream_encoder.h - -all: all-am - -.SUFFIXES: -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ - && { if test -f $@; then exit 0; else break; fi; }; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/libFLAC/include/protected/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign src/libFLAC/include/protected/Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(am__aclocal_m4_deps): - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs - -ID: $(am__tagged_files) - $(am__define_uniq_tagged_files); mkid -fID $$unique -tags: tags-am -TAGS: tags - -tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - set x; \ - here=`pwd`; \ - $(am__define_uniq_tagged_files); \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: ctags-am - -CTAGS: ctags -ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - $(am__define_uniq_tagged_files); \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" -cscopelist: cscopelist-am - -cscopelist-am: $(am__tagged_files) - list='$(am__tagged_files)'; \ - case "$(srcdir)" in \ - [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ - *) sdir=$(subdir)/$(srcdir) ;; \ - esac; \ - for i in $$list; do \ - if test -f "$$i"; then \ - echo "$(subdir)/$$i"; \ - else \ - echo "$$sdir/$$i"; \ - fi; \ - done >> $(top_builddir)/cscope.files - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -distdir: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) distdir-am - -distdir-am: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: check-am -all-am: Makefile $(HEADERS) -installdirs: -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - if test -z '$(STRIP)'; then \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - install; \ - else \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ - fi -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-am - -clean-am: clean-generic clean-libtool mostlyclean-am - -distclean: distclean-am - -rm -f Makefile -distclean-am: clean-am distclean-generic distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -html-am: - -info: info-am - -info-am: - -install-data-am: - -install-dvi: install-dvi-am - -install-dvi-am: - -install-exec-am: - -install-html: install-html-am - -install-html-am: - -install-info: install-info-am - -install-info-am: - -install-man: - -install-pdf: install-pdf-am - -install-pdf-am: - -install-ps: install-ps-am - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-generic mostlyclean-libtool - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: - -.MAKE: install-am install-strip - -.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ - clean-libtool cscopelist-am ctags ctags-am distclean \ - distclean-generic distclean-libtool distclean-tags distdir dvi \ - dvi-am html html-am info info-am install install-am \ - install-data install-data-am install-dvi install-dvi-am \ - install-exec install-exec-am install-html install-html-am \ - install-info install-info-am install-man install-pdf \ - install-pdf-am install-ps install-ps-am install-strip \ - installcheck installcheck-am installdirs maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-generic \ - mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ - uninstall-am - -.PRECIOUS: Makefile - - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/lib/flac/src/include/protected/all.h b/lib/flac/src/include/protected/all.h deleted file mode 100644 index 9468bd3..0000000 --- a/lib/flac/src/include/protected/all.h +++ /dev/null @@ -1,39 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PROTECTED__ALL_H -#define FLAC__PROTECTED__ALL_H - -#include "stream_decoder.h" -#include "stream_encoder.h" - -#endif diff --git a/lib/flac/src/include/protected/stream_decoder.h b/lib/flac/src/include/protected/stream_decoder.h deleted file mode 100644 index f7e2002..0000000 --- a/lib/flac/src/include/protected/stream_decoder.h +++ /dev/null @@ -1,65 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PROTECTED__STREAM_DECODER_H -#define FLAC__PROTECTED__STREAM_DECODER_H - -#include "FLAC/stream_decoder.h" -#if FLAC__HAS_OGG -#include "private/ogg_decoder_aspect.h" -#endif - -typedef struct FLAC__StreamDecoderProtected { - FLAC__StreamDecoderState state; - FLAC__StreamDecoderInitStatus initstate; - uint32_t channels; - FLAC__ChannelAssignment channel_assignment; - uint32_t bits_per_sample; - uint32_t sample_rate; /* in Hz */ - uint32_t blocksize; /* in samples (per channel) */ - FLAC__bool md5_checking; /* if true, generate MD5 signature of decoded data and compare against signature in the STREAMINFO metadata block */ -#if FLAC__HAS_OGG - FLAC__OggDecoderAspect ogg_decoder_aspect; -#endif -} FLAC__StreamDecoderProtected; - -/* - * return the number of input bytes consumed - */ -uint32_t FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecoder *decoder); - -/* - * return client_data from decoder - */ -FLAC_API void *get_client_data_from_decoder(FLAC__StreamDecoder *decoder); - -#endif diff --git a/lib/flac/src/include/protected/stream_encoder.h b/lib/flac/src/include/protected/stream_encoder.h deleted file mode 100644 index c290904..0000000 --- a/lib/flac/src/include/protected/stream_encoder.h +++ /dev/null @@ -1,118 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PROTECTED__STREAM_ENCODER_H -#define FLAC__PROTECTED__STREAM_ENCODER_H - -#include "FLAC/stream_encoder.h" -#if FLAC__HAS_OGG -#include "private/ogg_encoder_aspect.h" -#endif - -#ifndef FLAC__INTEGER_ONLY_LIBRARY - -#include "private/float.h" - -#define FLAC__MAX_APODIZATION_FUNCTIONS 32 - -typedef enum { - FLAC__APODIZATION_BARTLETT, - FLAC__APODIZATION_BARTLETT_HANN, - FLAC__APODIZATION_BLACKMAN, - FLAC__APODIZATION_BLACKMAN_HARRIS_4TERM_92DB_SIDELOBE, - FLAC__APODIZATION_CONNES, - FLAC__APODIZATION_FLATTOP, - FLAC__APODIZATION_GAUSS, - FLAC__APODIZATION_HAMMING, - FLAC__APODIZATION_HANN, - FLAC__APODIZATION_KAISER_BESSEL, - FLAC__APODIZATION_NUTTALL, - FLAC__APODIZATION_RECTANGLE, - FLAC__APODIZATION_TRIANGLE, - FLAC__APODIZATION_TUKEY, - FLAC__APODIZATION_PARTIAL_TUKEY, - FLAC__APODIZATION_PUNCHOUT_TUKEY, - FLAC__APODIZATION_WELCH -} FLAC__ApodizationFunction; - -typedef struct { - FLAC__ApodizationFunction type; - union { - struct { - FLAC__real stddev; - } gauss; - struct { - FLAC__real p; - } tukey; - struct { - FLAC__real p; - FLAC__real start; - FLAC__real end; - } multiple_tukey; - } parameters; -} FLAC__ApodizationSpecification; - -#endif // #ifndef FLAC__INTEGER_ONLY_LIBRARY - -typedef struct FLAC__StreamEncoderProtected { - FLAC__StreamEncoderState state; - FLAC__bool verify; - FLAC__bool streamable_subset; - FLAC__bool do_md5; - FLAC__bool do_mid_side_stereo; - FLAC__bool loose_mid_side_stereo; - uint32_t channels; - uint32_t bits_per_sample; - uint32_t sample_rate; - uint32_t blocksize; -#ifndef FLAC__INTEGER_ONLY_LIBRARY - uint32_t num_apodizations; - FLAC__ApodizationSpecification apodizations[FLAC__MAX_APODIZATION_FUNCTIONS]; -#endif - uint32_t max_lpc_order; - uint32_t qlp_coeff_precision; - FLAC__bool do_qlp_coeff_prec_search; - FLAC__bool do_exhaustive_model_search; - FLAC__bool do_escape_coding; - uint32_t min_residual_partition_order; - uint32_t max_residual_partition_order; - uint32_t rice_parameter_search_dist; - FLAC__uint64 total_samples_estimate; - FLAC__StreamMetadata **metadata; - uint32_t num_metadata_blocks; - FLAC__uint64 streaminfo_offset, seektable_offset, audio_offset; -#if FLAC__HAS_OGG - FLAC__OggEncoderAspect ogg_encoder_aspect; -#endif -} FLAC__StreamEncoderProtected; - -#endif diff --git a/lib/flac/src/include/share/Makefile.am b/lib/flac/src/include/share/Makefile.am deleted file mode 100644 index 079c169..0000000 --- a/lib/flac/src/include/share/Makefile.am +++ /dev/null @@ -1,19 +0,0 @@ -## Process this file with automake to produce Makefile.in - -SUBDIRS = grabbag - -EXTRA_DIST = \ - alloc.h \ - compat.h \ - endswap.h \ - getopt.h \ - grabbag.h \ - macros.h \ - msvc2005_int.h \ - private.h \ - replaygain_analysis.h \ - replaygain_synthesis.h \ - safe_str.h \ - utf8.h \ - win_utf8_io.h \ - windows_unicode_filenames.h diff --git a/lib/flac/src/include/share/Makefile.in b/lib/flac/src/include/share/Makefile.in deleted file mode 100644 index db26217..0000000 --- a/lib/flac/src/include/share/Makefile.in +++ /dev/null @@ -1,682 +0,0 @@ -# Makefile.in generated by automake 1.16.1 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994-2018 Free Software Foundation, Inc. - -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ -VPATH = @srcdir@ -am__is_gnu_make = { \ - if test -z '$(MAKELEVEL)'; then \ - false; \ - elif test -n '$(MAKE_HOST)'; then \ - true; \ - elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ - true; \ - else \ - false; \ - fi; \ -} -am__make_running_with_option = \ - case $${target_option-} in \ - ?) ;; \ - *) echo "am__make_running_with_option: internal error: invalid" \ - "target option '$${target_option-}' specified" >&2; \ - exit 1;; \ - esac; \ - has_opt=no; \ - sane_makeflags=$$MAKEFLAGS; \ - if $(am__is_gnu_make); then \ - sane_makeflags=$$MFLAGS; \ - else \ - case $$MAKEFLAGS in \ - *\\[\ \ ]*) \ - bs=\\; \ - sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ - | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ - esac; \ - fi; \ - skip_next=no; \ - strip_trailopt () \ - { \ - flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ - }; \ - for flg in $$sane_makeflags; do \ - test $$skip_next = yes && { skip_next=no; continue; }; \ - case $$flg in \ - *=*|--*) continue;; \ - -*I) strip_trailopt 'I'; skip_next=yes;; \ - -*I?*) strip_trailopt 'I';; \ - -*O) strip_trailopt 'O'; skip_next=yes;; \ - -*O?*) strip_trailopt 'O';; \ - -*l) strip_trailopt 'l'; skip_next=yes;; \ - -*l?*) strip_trailopt 'l';; \ - -[dEDm]) skip_next=yes;; \ - -[JT]) skip_next=yes;; \ - esac; \ - case $$flg in \ - *$$target_option*) has_opt=yes; break;; \ - esac; \ - done; \ - test $$has_opt = yes -am__make_dryrun = (target_option=n; $(am__make_running_with_option)) -am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -subdir = include/share -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/add_cflags.m4 \ - $(top_srcdir)/m4/add_cxxflags.m4 \ - $(top_srcdir)/m4/ax_add_fortify_source.m4 \ - $(top_srcdir)/m4/ax_check_enable_debug.m4 \ - $(top_srcdir)/m4/bswap.m4 $(top_srcdir)/m4/c_attribute.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)/m4/xmms.m4 \ - $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = $(top_builddir)/config.h -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -AM_V_P = $(am__v_P_@AM_V@) -am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) -am__v_P_0 = false -am__v_P_1 = : -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = -SOURCES = -DIST_SOURCES = -RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ - ctags-recursive dvi-recursive html-recursive info-recursive \ - install-data-recursive install-dvi-recursive \ - install-exec-recursive install-html-recursive \ - install-info-recursive install-pdf-recursive \ - install-ps-recursive install-recursive installcheck-recursive \ - installdirs-recursive pdf-recursive ps-recursive \ - tags-recursive uninstall-recursive -am__can_run_installinfo = \ - case $$AM_UPDATE_INFO_DIR in \ - n|no|NO) false;; \ - *) (install-info --version) >/dev/null 2>&1;; \ - esac -RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ - distclean-recursive maintainer-clean-recursive -am__recursive_targets = \ - $(RECURSIVE_TARGETS) \ - $(RECURSIVE_CLEAN_TARGETS) \ - $(am__extra_recursive_targets) -AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ - distdir distdir-am -am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) -# Read a list of newline-separated strings from the standard input, -# and print each of them once, without duplicates. Input order is -# *not* preserved. -am__uniquify_input = $(AWK) '\ - BEGIN { nonempty = 0; } \ - { items[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in items) print i; }; } \ -' -# Make sure the list of sources is unique. This is necessary because, -# e.g., the same source file might be shared among _SOURCES variables -# for different programs/libraries. -am__define_uniq_tagged_files = \ - list='$(am__tagged_files)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | $(am__uniquify_input)` -ETAGS = etags -CTAGS = ctags -DIST_SUBDIRS = $(SUBDIRS) -am__DIST_COMMON = $(srcdir)/Makefile.in -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -am__relativize = \ - dir0=`pwd`; \ - sed_first='s,^\([^/]*\)/.*$$,\1,'; \ - sed_rest='s,^[^/]*/*,,'; \ - sed_last='s,^.*/\([^/]*\)$$,\1,'; \ - sed_butlast='s,/*[^/]*$$,,'; \ - while test -n "$$dir1"; do \ - first=`echo "$$dir1" | sed -e "$$sed_first"`; \ - if test "$$first" != "."; then \ - if test "$$first" = ".."; then \ - dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ - dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ - else \ - first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ - if test "$$first2" = "$$first"; then \ - dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ - else \ - dir2="../$$dir2"; \ - fi; \ - dir0="$$dir0"/"$$first"; \ - fi; \ - fi; \ - dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ - done; \ - reldir="$$dir2" -ACLOCAL = @ACLOCAL@ -AMTAR = @AMTAR@ -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ -AR = @AR@ -AS = @AS@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -CC = @CC@ -CCAS = @CCAS@ -CCASDEPMODE = @CCASDEPMODE@ -CCASFLAGS = @CCASFLAGS@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ -CXX = @CXX@ -CXXCPP = @CXXCPP@ -CXXDEPMODE = @CXXDEPMODE@ -CXXFLAGS = @CXXFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -DLLTOOL = @DLLTOOL@ -DOCBOOK_TO_MAN = @DOCBOOK_TO_MAN@ -DOXYGEN = @DOXYGEN@ -DSYMUTIL = @DSYMUTIL@ -DUMPBIN = @DUMPBIN@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -ENABLE_64_BIT_WORDS = @ENABLE_64_BIT_WORDS@ -EXEEXT = @EXEEXT@ -FGREP = @FGREP@ -FLAC__HAS_OGG = @FLAC__HAS_OGG@ -FLAC__TEST_LEVEL = @FLAC__TEST_LEVEL@ -FLAC__TEST_WITH_VALGRIND = @FLAC__TEST_WITH_VALGRIND@ -GCC_MAJOR_VERSION = @GCC_MAJOR_VERSION@ -GCC_MINOR_VERSION = @GCC_MINOR_VERSION@ -GCC_VERSION = @GCC_VERSION@ -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@ -LIPO = @LIPO@ -LN_S = @LN_S@ -LTLIBICONV = @LTLIBICONV@ -LTLIBOBJS = @LTLIBOBJS@ -LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ -MAKEINFO = @MAKEINFO@ -MANIFEST_TOOL = @MANIFEST_TOOL@ -MKDIR_P = @MKDIR_P@ -NASM = @NASM@ -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@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -RANLIB = @RANLIB@ -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_DUMPBIN = @ac_ct_DUMPBIN@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localedir = @localedir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -runstatedir = @runstatedir@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -srcdir = @srcdir@ -sysconfdir = @sysconfdir@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -SUBDIRS = grabbag -EXTRA_DIST = \ - alloc.h \ - compat.h \ - endswap.h \ - getopt.h \ - grabbag.h \ - macros.h \ - msvc2005_int.h \ - private.h \ - replaygain_analysis.h \ - replaygain_synthesis.h \ - safe_str.h \ - utf8.h \ - win_utf8_io.h \ - windows_unicode_filenames.h - -all: all-recursive - -.SUFFIXES: -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ - && { if test -f $@; then exit 0; else break; fi; }; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/share/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign include/share/Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(am__aclocal_m4_deps): - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs - -# This directory's subdirectories are mostly independent; you can cd -# into them and run 'make' without going through this Makefile. -# To change the values of 'make' variables: instead of editing Makefiles, -# (1) if the variable is set in 'config.status', edit 'config.status' -# (which will cause the Makefiles to be regenerated when you run 'make'); -# (2) otherwise, pass the desired values on the 'make' command line. -$(am__recursive_targets): - @fail=; \ - if $(am__make_keepgoing); then \ - failcom='fail=yes'; \ - else \ - failcom='exit 1'; \ - fi; \ - dot_seen=no; \ - target=`echo $@ | sed s/-recursive//`; \ - case "$@" in \ - distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ - *) list='$(SUBDIRS)' ;; \ - esac; \ - for subdir in $$list; do \ - echo "Making $$target in $$subdir"; \ - if test "$$subdir" = "."; then \ - dot_seen=yes; \ - local_target="$$target-am"; \ - else \ - local_target="$$target"; \ - fi; \ - ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || eval $$failcom; \ - done; \ - if test "$$dot_seen" = "no"; then \ - $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ - fi; test -z "$$fail" - -ID: $(am__tagged_files) - $(am__define_uniq_tagged_files); mkid -fID $$unique -tags: tags-recursive -TAGS: tags - -tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - set x; \ - here=`pwd`; \ - if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ - include_option=--etags-include; \ - empty_fix=.; \ - else \ - include_option=--include; \ - empty_fix=; \ - fi; \ - list='$(SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - test ! -f $$subdir/TAGS || \ - set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ - fi; \ - done; \ - $(am__define_uniq_tagged_files); \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: ctags-recursive - -CTAGS: ctags -ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - $(am__define_uniq_tagged_files); \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" -cscopelist: cscopelist-recursive - -cscopelist-am: $(am__tagged_files) - list='$(am__tagged_files)'; \ - case "$(srcdir)" in \ - [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ - *) sdir=$(subdir)/$(srcdir) ;; \ - esac; \ - for i in $$list; do \ - if test -f "$$i"; then \ - echo "$(subdir)/$$i"; \ - else \ - echo "$$sdir/$$i"; \ - fi; \ - done >> $(top_builddir)/cscope.files - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -distdir: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) distdir-am - -distdir-am: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done - @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - $(am__make_dryrun) \ - || test -d "$(distdir)/$$subdir" \ - || $(MKDIR_P) "$(distdir)/$$subdir" \ - || exit 1; \ - dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ - $(am__relativize); \ - new_distdir=$$reldir; \ - dir1=$$subdir; dir2="$(top_distdir)"; \ - $(am__relativize); \ - new_top_distdir=$$reldir; \ - echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ - echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ - ($(am__cd) $$subdir && \ - $(MAKE) $(AM_MAKEFLAGS) \ - top_distdir="$$new_top_distdir" \ - distdir="$$new_distdir" \ - am__remove_distdir=: \ - am__skip_length_check=: \ - am__skip_mode_fix=: \ - distdir) \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: check-recursive -all-am: Makefile -installdirs: installdirs-recursive -installdirs-am: -install: install-recursive -install-exec: install-exec-recursive -install-data: install-data-recursive -uninstall: uninstall-recursive - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-recursive -install-strip: - if test -z '$(STRIP)'; then \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - install; \ - else \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ - fi -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-recursive - -clean-am: clean-generic clean-libtool mostlyclean-am - -distclean: distclean-recursive - -rm -f Makefile -distclean-am: clean-am distclean-generic distclean-tags - -dvi: dvi-recursive - -dvi-am: - -html: html-recursive - -html-am: - -info: info-recursive - -info-am: - -install-data-am: - -install-dvi: install-dvi-recursive - -install-dvi-am: - -install-exec-am: - -install-html: install-html-recursive - -install-html-am: - -install-info: install-info-recursive - -install-info-am: - -install-man: - -install-pdf: install-pdf-recursive - -install-pdf-am: - -install-ps: install-ps-recursive - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-recursive - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-recursive - -mostlyclean-am: mostlyclean-generic mostlyclean-libtool - -pdf: pdf-recursive - -pdf-am: - -ps: ps-recursive - -ps-am: - -uninstall-am: - -.MAKE: $(am__recursive_targets) install-am install-strip - -.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ - check-am clean clean-generic clean-libtool cscopelist-am ctags \ - ctags-am distclean distclean-generic distclean-libtool \ - distclean-tags distdir dvi dvi-am html html-am info info-am \ - install install-am install-data install-data-am install-dvi \ - install-dvi-am install-exec install-exec-am install-html \ - install-html-am install-info install-info-am install-man \ - install-pdf install-pdf-am install-ps install-ps-am \ - install-strip installcheck installcheck-am installdirs \ - installdirs-am maintainer-clean maintainer-clean-generic \ - mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ - ps ps-am tags tags-am uninstall uninstall-am - -.PRECIOUS: Makefile - - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/lib/flac/src/include/share/alloc.h b/lib/flac/src/include/share/alloc.h deleted file mode 100644 index ff93945..0000000 --- a/lib/flac/src/include/share/alloc.h +++ /dev/null @@ -1,219 +0,0 @@ -/* alloc - Convenience routines for safely allocating memory - * Copyright (C) 2007-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__SHARE__ALLOC_H -#define FLAC__SHARE__ALLOC_H - -#ifdef HAVE_CONFIG_H -# include -#endif - -/* WATCHOUT: for c++ you may have to #define __STDC_LIMIT_MACROS 1 real early - * before #including this file, otherwise SIZE_MAX might not be defined - */ - -#include /* for SIZE_MAX */ -#if HAVE_STDINT_H -#include /* for SIZE_MAX in case limits.h didn't get it */ -#endif -#include /* for size_t, malloc(), etc */ -#include "share/compat.h" - -#ifndef SIZE_MAX -# ifndef SIZE_T_MAX -# ifdef _MSC_VER -# ifdef _WIN64 -# define SIZE_T_MAX FLAC__U64L(0xffffffffffffffff) -# else -# define SIZE_T_MAX 0xffffffff -# endif -# else -# error -# endif -# endif -# define SIZE_MAX SIZE_T_MAX -#endif - -/* avoid malloc()ing 0 bytes, see: - * https://www.securecoding.cert.org/confluence/display/seccode/MEM04-A.+Do+not+make+assumptions+about+the+result+of+allocating+0+bytes?focusedCommentId=5407003 -*/ -static inline void *safe_malloc_(size_t size) -{ - /* malloc(0) is undefined; FLAC src convention is to always allocate */ - if(!size) - size++; - return malloc(size); -} - -static inline void *safe_calloc_(size_t nmemb, size_t size) -{ - if(!nmemb || !size) - return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */ - return (nmemb <= INT_MAX) ? calloc(nmemb, size) : NULL; -} - -/*@@@@ there's probably a better way to prevent overflows when allocating untrusted sums but this works for now */ - -static inline void *safe_malloc_add_2op_(size_t size1, size_t size2) -{ - size2 += size1; - if(size2 < size1) - return 0; - return safe_malloc_(size2); -} - -static inline void *safe_malloc_add_3op_(size_t size1, size_t size2, size_t size3) -{ - size2 += size1; - if(size2 < size1) - return 0; - size3 += size2; - if(size3 < size2) - return 0; - return safe_malloc_(size3); -} - -static inline void *safe_malloc_add_4op_(size_t size1, size_t size2, size_t size3, size_t size4) -{ - size2 += size1; - if(size2 < size1) - return 0; - size3 += size2; - if(size3 < size2) - return 0; - size4 += size3; - if(size4 < size3) - return 0; - return safe_malloc_(size4); -} - -void *safe_malloc_mul_2op_(size_t size1, size_t size2) ; - -static inline void *safe_malloc_mul_3op_(size_t size1, size_t size2, size_t size3) -{ - if(!size1 || !size2 || !size3) - return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */ - if(size1 > SIZE_MAX / size2) - return 0; - size1 *= size2; - if(size1 > SIZE_MAX / size3) - return 0; - return malloc(size1*size3); -} - -/* size1*size2 + size3 */ -static inline void *safe_malloc_mul2add_(size_t size1, size_t size2, size_t size3) -{ - if(!size1 || !size2) - return safe_malloc_(size3); - if(size1 > SIZE_MAX / size2) - return 0; - return safe_malloc_add_2op_(size1*size2, size3); -} - -/* size1 * (size2 + size3) */ -static inline void *safe_malloc_muladd2_(size_t size1, size_t size2, size_t size3) -{ - if(!size1 || (!size2 && !size3)) - return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */ - size2 += size3; - if(size2 < size3) - return 0; - if(size1 > SIZE_MAX / size2) - return 0; - return malloc(size1*size2); -} - -static inline void *safe_realloc_(void *ptr, size_t size) -{ - void *oldptr = ptr; - void *newptr = realloc(ptr, size); - if(size > 0 && newptr == 0) - free(oldptr); - return newptr; -} -static inline void *safe_realloc_add_2op_(void *ptr, size_t size1, size_t size2) -{ - size2 += size1; - if(size2 < size1) { - free(ptr); - return 0; - } - return realloc(ptr, size2); -} - -static inline void *safe_realloc_add_3op_(void *ptr, size_t size1, size_t size2, size_t size3) -{ - size2 += size1; - if(size2 < size1) - return 0; - size3 += size2; - if(size3 < size2) - return 0; - return realloc(ptr, size3); -} - -static inline void *safe_realloc_add_4op_(void *ptr, size_t size1, size_t size2, size_t size3, size_t size4) -{ - size2 += size1; - if(size2 < size1) - return 0; - size3 += size2; - if(size3 < size2) - return 0; - size4 += size3; - if(size4 < size3) - return 0; - return realloc(ptr, size4); -} - -static inline void *safe_realloc_mul_2op_(void *ptr, size_t size1, size_t size2) -{ - if(!size1 || !size2) - return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */ - if(size1 > SIZE_MAX / size2) - return 0; - return safe_realloc_(ptr, size1*size2); -} - -/* size1 * (size2 + size3) */ -static inline void *safe_realloc_muladd2_(void *ptr, size_t size1, size_t size2, size_t size3) -{ - if(!size1 || (!size2 && !size3)) - return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */ - size2 += size3; - if(size2 < size3) - return 0; - return safe_realloc_mul_2op_(ptr, size1, size2); -} - -#endif diff --git a/lib/flac/src/include/share/compat.h b/lib/flac/src/include/share/compat.h deleted file mode 100644 index f304165..0000000 --- a/lib/flac/src/include/share/compat.h +++ /dev/null @@ -1,205 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2012-2016 Xiph.org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* This is the preferred location of all CPP hackery to make $random_compiler - * work like something approaching a C99 (or maybe more accurately GNU99) - * compiler. - * - * It is assumed that this header will be included after "config.h". - */ - -#ifndef FLAC__SHARE__COMPAT_H -#define FLAC__SHARE__COMPAT_H - -#if defined _WIN32 && !defined __CYGWIN__ -/* where MSVC puts unlink() */ -# include -#else -# include -#endif - -#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__ -#include /* for off_t */ -#define FLAC__off_t __int64 /* use this instead of off_t to fix the 2 GB limit */ -#if !defined __MINGW32__ -#define fseeko _fseeki64 -#define ftello _ftelli64 -#else /* MinGW */ -#if !defined(HAVE_FSEEKO) -#define fseeko fseeko64 -#define ftello ftello64 -#endif -#endif -#else -#define FLAC__off_t off_t -#endif - -#if HAVE_INTTYPES_H -#define __STDC_FORMAT_MACROS -#include -#endif - -#if defined(_MSC_VER) -#define strtoll _strtoi64 -#define strtoull _strtoui64 -#endif - -#if defined(_MSC_VER) && !defined(__cplusplus) -#define inline __inline -#endif - -#if defined __INTEL_COMPILER || (defined _MSC_VER && defined _WIN64) -/* MSVS generates VERY slow 32-bit code with __restrict */ -#define flac_restrict __restrict -#elif defined __GNUC__ -#define flac_restrict __restrict__ -#else -#define flac_restrict -#endif - -#define FLAC__U64L(x) x##ULL - -#if defined _MSC_VER || defined __MINGW32__ -#define FLAC__STRCASECMP _stricmp -#define FLAC__STRNCASECMP _strnicmp -#elif defined __BORLANDC__ -#define FLAC__STRCASECMP stricmp -#define FLAC__STRNCASECMP strnicmp -#else -#define FLAC__STRCASECMP strcasecmp -#define FLAC__STRNCASECMP strncasecmp -#endif - -#if defined _MSC_VER || defined __MINGW32__ || defined __EMX__ -#include /* for _setmode(), chmod() */ -#include /* for _O_BINARY */ -#else -#include /* for chown(), unlink() */ -#endif - -#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__ -#if defined __BORLANDC__ -#include /* for utime() */ -#else -#include /* for utime() */ -#endif -#else -#include /* some flavors of BSD (like OS X) require this to get time_t */ -#include /* for utime() */ -#endif - -#if defined _MSC_VER -# if _MSC_VER >= 1800 -# include -# elif _MSC_VER >= 1600 -/* Visual Studio 2010 has decent C99 support */ -# include -# define PRIu64 "llu" -# define PRId64 "lld" -# define PRIx64 "llx" -# else -# include -# ifndef UINT32_MAX -# define UINT32_MAX _UI32_MAX -# endif -# define PRIu64 "I64u" -# define PRId64 "I64d" -# define PRIx64 "I64x" -# endif -#endif /* defined _MSC_VER */ - -#ifdef _WIN32 -/* All char* strings are in UTF-8 format. Added to support Unicode files on Windows */ - -#include "share/win_utf8_io.h" -#define flac_printf printf_utf8 -#define flac_fprintf fprintf_utf8 -#define flac_vfprintf vfprintf_utf8 - -#include "share/windows_unicode_filenames.h" -#define flac_fopen flac_internal_fopen_utf8 -#define flac_chmod flac_internal_chmod_utf8 -#define flac_utime flac_internal_utime_utf8 -#define flac_unlink flac_internal_unlink_utf8 -#define flac_rename flac_internal_rename_utf8 -#define flac_stat flac_internal_stat64_utf8 - -#else - -#define flac_printf printf -#define flac_fprintf fprintf -#define flac_vfprintf vfprintf - -#define flac_fopen fopen -#define flac_chmod chmod -#define flac_utime utime -#define flac_unlink unlink -#define flac_rename rename -#define flac_stat stat - -#endif - -#ifdef _WIN32 -#define flac_stat_s __stat64 /* stat struct */ -#define flac_fstat _fstat64 -#else -#define flac_stat_s stat /* stat struct */ -#define flac_fstat fstat -#endif - -#ifdef ANDROID -#include -#endif - -#ifndef M_LN2 -#define M_LN2 0.69314718055994530942 -#endif -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -/* FLAC needs to compile and work correctly on systems with a normal ISO C99 - * snprintf as well as Microsoft Visual Studio which has an non-standards - * conformant snprint_s function. - * - * This function wraps the MS version to behave more like the ISO version. - */ -#include -#ifdef __cplusplus -extern "C" { -#endif -int flac_snprintf(char *str, size_t size, const char *fmt, ...); -int flac_vsnprintf(char *str, size_t size, const char *fmt, va_list va); -#ifdef __cplusplus -}; -#endif - -#endif /* FLAC__SHARE__COMPAT_H */ diff --git a/lib/flac/src/include/share/endswap.h b/lib/flac/src/include/share/endswap.h deleted file mode 100644 index 9088a74..0000000 --- a/lib/flac/src/include/share/endswap.h +++ /dev/null @@ -1,84 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2012-2016 Xiph.org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* It is assumed that this header will be included after "config.h". */ - -#if HAVE_BSWAP32 /* GCC and Clang */ - -/* GCC prior to 4.8 didn't provide bswap16 on x86_64 */ -#if ! HAVE_BSWAP16 -static inline unsigned short __builtin_bswap16(unsigned short a) -{ - return (a<<8)|(a>>8); -} -#endif - -#define ENDSWAP_16(x) (__builtin_bswap16 (x)) -#define ENDSWAP_32(x) (__builtin_bswap32 (x)) -#define ENDSWAP_64(x) (__builtin_bswap64 (x)) - -#elif defined _MSC_VER /* Windows */ - -#include - -#define ENDSWAP_16(x) (_byteswap_ushort (x)) -#define ENDSWAP_32(x) (_byteswap_ulong (x)) -#define ENDSWAP_64(x) (_byteswap_uint64 (x)) - -#elif defined HAVE_BYTESWAP_H /* Linux */ - -#include - -#define ENDSWAP_16(x) (bswap_16 (x)) -#define ENDSWAP_32(x) (bswap_32 (x)) -#define ENDSWAP_64(x) (bswap_64 (x)) - -#else - -#define ENDSWAP_16(x) ((((x) >> 8) & 0xFF) | (((x) & 0xFF) << 8)) -#define ENDSWAP_32(x) ((((x) >> 24) & 0xFF) | (((x) >> 8) & 0xFF00) | (((x) & 0xFF00) << 8) | (((x) & 0xFF) << 24)) -#define ENDSWAP_64(x) ((ENDSWAP_32(((x) >> 32) & 0xFFFFFFFF)) | (ENDSWAP_32((x) & 0xFFFFFFFF) << 32)) - -#endif - - -/* Host to little-endian byte swapping (for MD5 calculation) */ -#if CPU_IS_BIG_ENDIAN - -#define H2LE_16(x) ENDSWAP_16 (x) -#define H2LE_32(x) ENDSWAP_32 (x) - -#else - -#define H2LE_16(x) (x) -#define H2LE_32(x) (x) - -#endif diff --git a/lib/flac/src/include/share/getopt.h b/lib/flac/src/include/share/getopt.h deleted file mode 100644 index 66aced0..0000000 --- a/lib/flac/src/include/share/getopt.h +++ /dev/null @@ -1,184 +0,0 @@ -/* - NOTE: - I cannot get the vanilla getopt code to work (i.e. compile only what - is needed and not duplicate symbols found in the standard library) - on all the platforms that FLAC supports. In particular the gating - of code with the ELIDE_CODE #define is not accurate enough on systems - that are POSIX but not glibc. If someone has a patch that works on - GNU/Linux, Darwin, AND Solaris please submit it on the project page: - https://sourceforge.net/p/flac/patches/ - - In the meantime I have munged the global symbols and removed gates - around code, while at the same time trying to touch the original as - little as possible. -*/ -/* Declarations for getopt. - Copyright (C) 1989,90,91,92,93,94,96,97,98 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ - -#ifndef SHARE__GETOPT_H -#define SHARE__GETOPT_H - -/*[JEC] was:#ifndef __need_getopt*/ -/*[JEC] was:# define _GETOPT_H 1*/ -/*[JEC] was:#endif*/ - -#ifdef __cplusplus -extern "C" { -#endif - -/* For communication from `share__getopt' to the caller. - When `share__getopt' finds an option that takes an argument, - the argument value is returned here. - Also, when `ordering' is RETURN_IN_ORDER, - each non-option ARGV-element is returned here. */ - -extern char *share__optarg; - -/* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `share__getopt'. - - On entry to `share__getopt', zero means this is the first call; initialize. - - When `share__getopt' returns -1, this is the index of the first of the - non-option elements that the caller should itself scan. - - Otherwise, `share__optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ - -extern int share__optind; - -/* Callers store zero here to inhibit the error message `share__getopt' prints - for unrecognized options. */ - -extern int share__opterr; - -/* Set to an option character which was unrecognized. */ - -extern int share__optopt; - -/*[JEC] was:#ifndef __need_getopt */ -/* Describe the long-named options requested by the application. - The LONG_OPTIONS argument to share__getopt_long or share__getopt_long_only is a vector - of `struct share__option' terminated by an element containing a name which is - zero. - - The field `has_arg' is: - share__no_argument (or 0) if the option does not take an argument, - share__required_argument (or 1) if the option requires an argument, - share__optional_argument (or 2) if the option takes an optional argument. - - If the field `flag' is not NULL, it points to a variable that is set - to the value given in the field `val' when the option is found, but - left unchanged if the option is not found. - - To have a long-named option do something other than set an `int' to - a compiled-in constant, such as set a value from `share__optarg', set the - option's `flag' field to zero and its `val' field to a nonzero - value (the equivalent single-letter option character, if there is - one). For long options that have a zero `flag' field, `share__getopt' - returns the contents of the `val' field. */ - -struct share__option -{ -# if defined __STDC__ && __STDC__ - const char *name; -# else - char *name; -# endif - /* has_arg can't be an enum because some compilers complain about - type mismatches in all the code that assumes it is an int. */ - int has_arg; - int *flag; - int val; -}; - -/* Names for the values of the `has_arg' field of `struct share__option'. */ - -# define share__no_argument 0 -# define share__required_argument 1 -# define share__optional_argument 2 -/*[JEC] was:#endif*/ /* need getopt */ - - -/* Get definitions and prototypes for functions to process the - arguments in ARGV (ARGC of them, minus the program name) for - options given in OPTS. - - Return the option character from OPTS just read. Return -1 when - there are no more options. For unrecognized options, or options - missing arguments, `share__optopt' is set to the option letter, and '?' is - returned. - - The OPTS string is a list of characters which are recognized option - letters, optionally followed by colons, specifying that that letter - takes an argument, to be placed in `share__optarg'. - - If a letter in OPTS is followed by two colons, its argument is - optional. This behavior is specific to the GNU `share__getopt'. - - The argument `--' causes premature termination of argument - scanning, explicitly telling `share__getopt' that there are no more - options. - - If OPTS begins with `--', then non-option arguments are treated as - arguments to the option '\0'. This behavior is specific to the GNU - `share__getopt'. */ - -/*[JEC] was:#if defined __STDC__ && __STDC__*/ -/*[JEC] was:# ifdef __GNU_LIBRARY__*/ -/* Many other libraries have conflicting prototypes for getopt, with - differences in the consts, in stdlib.h. To avoid compilation - errors, only prototype getopt for the GNU C library. */ -extern int share__getopt (int argc, char *const *argv, const char *shortopts); -/*[JEC] was:# else*/ /* not __GNU_LIBRARY__ */ -/*[JEC] was:extern int getopt ();*/ -/*[JEC] was:# endif*/ /* __GNU_LIBRARY__ */ - -/*[JEC] was:# ifndef __need_getopt*/ -extern int share__getopt_long (int argc, char *const *argv, const char *shortopts, - const struct share__option *longopts, int *longind); -extern int share__getopt_long_only (int argc, char *const *argv, - const char *shortopts, - const struct share__option *longopts, int *longind); - -/* Internal only. Users should not call this directly. */ -extern int share___getopt_internal (int argc, char *const *argv, - const char *shortopts, - const struct share__option *longopts, int *longind, - int long_only); -/*[JEC] was:# endif*/ -/*[JEC] was:#else*/ /* not __STDC__ */ -/*[JEC] was:extern int getopt ();*/ -/*[JEC] was:# ifndef __need_getopt*/ -/*[JEC] was:extern int getopt_long ();*/ -/*[JEC] was:extern int getopt_long_only ();*/ - -/*[JEC] was:extern int _getopt_internal ();*/ -/*[JEC] was:# endif*/ -/*[JEC] was:#endif*/ /* __STDC__ */ - -#ifdef __cplusplus -} -#endif - -/* Make sure we later can get all the definitions and declarations. */ -/*[JEC] was:#undef __need_getopt*/ - -#endif /* getopt.h */ diff --git a/lib/flac/src/include/share/grabbag.h b/lib/flac/src/include/share/grabbag.h deleted file mode 100644 index 92ec998..0000000 --- a/lib/flac/src/include/share/grabbag.h +++ /dev/null @@ -1,30 +0,0 @@ -/* grabbag - Convenience lib for various routines common to several tools - * Copyright (C) 2002-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef SHARE__GRABBAG_H -#define SHARE__GRABBAG_H - -/* These can't be included by themselves, only from within grabbag.h */ -#include "grabbag/cuesheet.h" -#include "grabbag/file.h" -#include "grabbag/picture.h" -#include "grabbag/replaygain.h" -#include "grabbag/seektable.h" - -#endif diff --git a/lib/flac/src/include/share/grabbag/Makefile.am b/lib/flac/src/include/share/grabbag/Makefile.am deleted file mode 100644 index 22baa15..0000000 --- a/lib/flac/src/include/share/grabbag/Makefile.am +++ /dev/null @@ -1,8 +0,0 @@ -## Process this file with automake to produce Makefile.in - -EXTRA_DIST = \ - cuesheet.h \ - file.h \ - picture.h \ - replaygain.h \ - seektable.h diff --git a/lib/flac/src/include/share/grabbag/Makefile.in b/lib/flac/src/include/share/grabbag/Makefile.in deleted file mode 100644 index fc4e6ce..0000000 --- a/lib/flac/src/include/share/grabbag/Makefile.in +++ /dev/null @@ -1,492 +0,0 @@ -# Makefile.in generated by automake 1.16.1 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994-2018 Free Software Foundation, Inc. - -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ -VPATH = @srcdir@ -am__is_gnu_make = { \ - if test -z '$(MAKELEVEL)'; then \ - false; \ - elif test -n '$(MAKE_HOST)'; then \ - true; \ - elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ - true; \ - else \ - false; \ - fi; \ -} -am__make_running_with_option = \ - case $${target_option-} in \ - ?) ;; \ - *) echo "am__make_running_with_option: internal error: invalid" \ - "target option '$${target_option-}' specified" >&2; \ - exit 1;; \ - esac; \ - has_opt=no; \ - sane_makeflags=$$MAKEFLAGS; \ - if $(am__is_gnu_make); then \ - sane_makeflags=$$MFLAGS; \ - else \ - case $$MAKEFLAGS in \ - *\\[\ \ ]*) \ - bs=\\; \ - sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ - | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ - esac; \ - fi; \ - skip_next=no; \ - strip_trailopt () \ - { \ - flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ - }; \ - for flg in $$sane_makeflags; do \ - test $$skip_next = yes && { skip_next=no; continue; }; \ - case $$flg in \ - *=*|--*) continue;; \ - -*I) strip_trailopt 'I'; skip_next=yes;; \ - -*I?*) strip_trailopt 'I';; \ - -*O) strip_trailopt 'O'; skip_next=yes;; \ - -*O?*) strip_trailopt 'O';; \ - -*l) strip_trailopt 'l'; skip_next=yes;; \ - -*l?*) strip_trailopt 'l';; \ - -[dEDm]) skip_next=yes;; \ - -[JT]) skip_next=yes;; \ - esac; \ - case $$flg in \ - *$$target_option*) has_opt=yes; break;; \ - esac; \ - done; \ - test $$has_opt = yes -am__make_dryrun = (target_option=n; $(am__make_running_with_option)) -am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -subdir = include/share/grabbag -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/add_cflags.m4 \ - $(top_srcdir)/m4/add_cxxflags.m4 \ - $(top_srcdir)/m4/ax_add_fortify_source.m4 \ - $(top_srcdir)/m4/ax_check_enable_debug.m4 \ - $(top_srcdir)/m4/bswap.m4 $(top_srcdir)/m4/c_attribute.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)/m4/xmms.m4 \ - $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = $(top_builddir)/config.h -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -AM_V_P = $(am__v_P_@AM_V@) -am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) -am__v_P_0 = false -am__v_P_1 = : -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = -SOURCES = -DIST_SOURCES = -am__can_run_installinfo = \ - case $$AM_UPDATE_INFO_DIR in \ - n|no|NO) false;; \ - *) (install-info --version) >/dev/null 2>&1;; \ - esac -am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) -am__DIST_COMMON = $(srcdir)/Makefile.in -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = @ACLOCAL@ -AMTAR = @AMTAR@ -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ -AR = @AR@ -AS = @AS@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -CC = @CC@ -CCAS = @CCAS@ -CCASDEPMODE = @CCASDEPMODE@ -CCASFLAGS = @CCASFLAGS@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ -CXX = @CXX@ -CXXCPP = @CXXCPP@ -CXXDEPMODE = @CXXDEPMODE@ -CXXFLAGS = @CXXFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -DLLTOOL = @DLLTOOL@ -DOCBOOK_TO_MAN = @DOCBOOK_TO_MAN@ -DOXYGEN = @DOXYGEN@ -DSYMUTIL = @DSYMUTIL@ -DUMPBIN = @DUMPBIN@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -ENABLE_64_BIT_WORDS = @ENABLE_64_BIT_WORDS@ -EXEEXT = @EXEEXT@ -FGREP = @FGREP@ -FLAC__HAS_OGG = @FLAC__HAS_OGG@ -FLAC__TEST_LEVEL = @FLAC__TEST_LEVEL@ -FLAC__TEST_WITH_VALGRIND = @FLAC__TEST_WITH_VALGRIND@ -GCC_MAJOR_VERSION = @GCC_MAJOR_VERSION@ -GCC_MINOR_VERSION = @GCC_MINOR_VERSION@ -GCC_VERSION = @GCC_VERSION@ -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@ -LIPO = @LIPO@ -LN_S = @LN_S@ -LTLIBICONV = @LTLIBICONV@ -LTLIBOBJS = @LTLIBOBJS@ -LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ -MAKEINFO = @MAKEINFO@ -MANIFEST_TOOL = @MANIFEST_TOOL@ -MKDIR_P = @MKDIR_P@ -NASM = @NASM@ -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@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -RANLIB = @RANLIB@ -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_DUMPBIN = @ac_ct_DUMPBIN@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localedir = @localedir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -runstatedir = @runstatedir@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -srcdir = @srcdir@ -sysconfdir = @sysconfdir@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -EXTRA_DIST = \ - cuesheet.h \ - file.h \ - picture.h \ - replaygain.h \ - seektable.h - -all: all-am - -.SUFFIXES: -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ - && { if test -f $@; then exit 0; else break; fi; }; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/share/grabbag/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign include/share/grabbag/Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(am__aclocal_m4_deps): - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs -tags TAGS: - -ctags CTAGS: - -cscope cscopelist: - - -distdir: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) distdir-am - -distdir-am: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: check-am -all-am: Makefile -installdirs: -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - if test -z '$(STRIP)'; then \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - install; \ - else \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ - fi -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-am - -clean-am: clean-generic clean-libtool mostlyclean-am - -distclean: distclean-am - -rm -f Makefile -distclean-am: clean-am distclean-generic - -dvi: dvi-am - -dvi-am: - -html: html-am - -html-am: - -info: info-am - -info-am: - -install-data-am: - -install-dvi: install-dvi-am - -install-dvi-am: - -install-exec-am: - -install-html: install-html-am - -install-html-am: - -install-info: install-info-am - -install-info-am: - -install-man: - -install-pdf: install-pdf-am - -install-pdf-am: - -install-ps: install-ps-am - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-generic mostlyclean-libtool - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: - -.MAKE: install-am install-strip - -.PHONY: all all-am check check-am clean clean-generic clean-libtool \ - cscopelist-am ctags-am distclean distclean-generic \ - distclean-libtool distdir dvi dvi-am html html-am info info-am \ - install install-am install-data install-data-am install-dvi \ - install-dvi-am install-exec install-exec-am install-html \ - install-html-am install-info install-info-am install-man \ - install-pdf install-pdf-am install-ps install-ps-am \ - install-strip installcheck installcheck-am installdirs \ - maintainer-clean maintainer-clean-generic mostlyclean \ - mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ - tags-am uninstall uninstall-am - -.PRECIOUS: Makefile - - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/lib/flac/src/include/share/grabbag/cuesheet.h b/lib/flac/src/include/share/grabbag/cuesheet.h deleted file mode 100644 index b465ae6..0000000 --- a/lib/flac/src/include/share/grabbag/cuesheet.h +++ /dev/null @@ -1,43 +0,0 @@ -/* grabbag - Convenience lib for various routines common to several tools - * Copyright (C) 2002-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */ - -#ifndef GRABBAG__CUESHEET_H -#define GRABBAG__CUESHEET_H - -#include -#include "FLAC/metadata.h" - -#ifdef __cplusplus -extern "C" { -#endif - -unsigned grabbag__cuesheet_msf_to_frame(unsigned minutes, unsigned seconds, unsigned frames); -void grabbag__cuesheet_frame_to_msf(unsigned frame, unsigned *minutes, unsigned *seconds, unsigned *frames); - -FLAC__StreamMetadata *grabbag__cuesheet_parse(FILE *file, const char **error_message, unsigned *last_line_read, unsigned sample_rate, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset); - -void grabbag__cuesheet_emit(FILE *file, const FLAC__StreamMetadata *cuesheet, const char *file_reference); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/flac/src/include/share/grabbag/file.h b/lib/flac/src/include/share/grabbag/file.h deleted file mode 100644 index b3f4148..0000000 --- a/lib/flac/src/include/share/grabbag/file.h +++ /dev/null @@ -1,65 +0,0 @@ -/* grabbag - Convenience lib for various routines common to several tools - * Copyright (C) 2002-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/* Convenience routines for manipulating files */ - -/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */ - -#ifndef GRABAG__FILE_H -#define GRABAG__FILE_H - -/* needed because of off_t */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include /* for off_t */ -#include /* for FILE */ -#include "FLAC/ordinals.h" -#include "share/compat.h" - -#ifdef __cplusplus -extern "C" { -#endif - -void grabbag__file_copy_metadata(const char *srcpath, const char *destpath); -FLAC__off_t grabbag__file_get_filesize(const char *srcpath); -const char *grabbag__file_get_basename(const char *srcpath); - -/* read_only == false means "make file writable by user" - * read_only == true means "make file read-only for everyone" - */ -FLAC__bool grabbag__file_change_stats(const char *filename, FLAC__bool read_only); - -/* returns true iff stat() succeeds for both files and they have the same device and inode. */ -/* on windows, uses GetFileInformationByHandle() to compare */ -FLAC__bool grabbag__file_are_same(const char *f1, const char *f2); - -/* attempts to make writable before unlinking */ -FLAC__bool grabbag__file_remove_file(const char *filename); - -/* these will forcibly set stdin/stdout to binary mode (for OSes that require it) */ -FILE *grabbag__file_get_binary_stdin(void); -FILE *grabbag__file_get_binary_stdout(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/flac/src/include/share/grabbag/picture.h b/lib/flac/src/include/share/grabbag/picture.h deleted file mode 100644 index ea308f1..0000000 --- a/lib/flac/src/include/share/grabbag/picture.h +++ /dev/null @@ -1,54 +0,0 @@ -/* grabbag - Convenience lib for various routines common to several tools - * Copyright (C) 2006-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */ - -#ifndef GRABBAG__PICTURE_H -#define GRABBAG__PICTURE_H - -#include "FLAC/metadata.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* spec should be of the form "[TYPE]|MIME_TYPE|[DESCRIPTION]|[WIDTHxHEIGHTxDEPTH[/COLORS]]|FILE", e.g. - * "|image/jpeg|||cover.jpg" - * "4|image/jpeg||300x300x24|backcover.jpg" - * "|image/png|description|300x300x24/71|cover.png" - * "-->|image/gif||300x300x24/71|http://blah.blah.blah/cover.gif" - * - * empty type means default to FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER - * empty resolution spec means to get from the file (cannot get used with "-->" linked images) - * spec and error_message must not be NULL - */ -FLAC__StreamMetadata *grabbag__picture_parse_specification(const char *spec, const char **error_message); - -typedef struct PictureResolution -{ uint32_t width, height, depth, colors ; -} PictureResolution ; - -FLAC__StreamMetadata *grabbag__picture_from_specification(int type, const char *mime_type, const char * description, - const PictureResolution * res, const char * filepath, const char **error_message); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/flac/src/include/share/grabbag/replaygain.h b/lib/flac/src/include/share/grabbag/replaygain.h deleted file mode 100644 index faa3272..0000000 --- a/lib/flac/src/include/share/grabbag/replaygain.h +++ /dev/null @@ -1,73 +0,0 @@ -/* grabbag - Convenience lib for various routines common to several tools - * Copyright (C) 2002-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/* - * This wraps the replaygain_analysis lib, which is LGPL. This wrapper - * allows analysis of different input resolutions by automatically - * scaling the input signal - */ - -/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */ - -#ifndef GRABBAG__REPLAYGAIN_H -#define GRABBAG__REPLAYGAIN_H - -#include "FLAC/metadata.h" - -#ifdef __cplusplus -extern "C" { -#endif - -extern const unsigned GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED; - -extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS; /* = "REPLAYGAIN_REFERENCE_LOUDNESS" */ -extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN; /* = "REPLAYGAIN_TRACK_GAIN" */ -extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK; /* = "REPLAYGAIN_TRACK_PEAK" */ -extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN; /* = "REPLAYGAIN_ALBUM_GAIN" */ -extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK; /* = "REPLAYGAIN_ALBUM_PEAK" */ - -FLAC__bool grabbag__replaygain_is_valid_sample_frequency(unsigned sample_frequency); - -FLAC__bool grabbag__replaygain_init(unsigned sample_frequency); - -/* 'bps' must be valid for FLAC, i.e. >=4 and <= 32 */ -FLAC__bool grabbag__replaygain_analyze(const FLAC__int32 * const input[], FLAC__bool is_stereo, unsigned bps, unsigned samples); - -void grabbag__replaygain_get_album(float *gain, float *peak); -void grabbag__replaygain_get_title(float *gain, float *peak); - -/* These three functions return an error string on error, or NULL if successful */ -const char *grabbag__replaygain_analyze_file(const char *filename, float *title_gain, float *title_peak); -const char *grabbag__replaygain_store_to_vorbiscomment(FLAC__StreamMetadata *block, float album_gain, float album_peak, float title_gain, float title_peak); -const char *grabbag__replaygain_store_to_vorbiscomment_reference(FLAC__StreamMetadata *block); -const char *grabbag__replaygain_store_to_vorbiscomment_album(FLAC__StreamMetadata *block, float album_gain, float album_peak); -const char *grabbag__replaygain_store_to_vorbiscomment_title(FLAC__StreamMetadata *block, float title_gain, float title_peak); -const char *grabbag__replaygain_store_to_file(const char *filename, float album_gain, float album_peak, float title_gain, float title_peak, FLAC__bool preserve_modtime); -const char *grabbag__replaygain_store_to_file_reference(const char *filename, FLAC__bool preserve_modtime); -const char *grabbag__replaygain_store_to_file_album(const char *filename, float album_gain, float album_peak, FLAC__bool preserve_modtime); -const char *grabbag__replaygain_store_to_file_title(const char *filename, float title_gain, float title_peak, FLAC__bool preserve_modtime); - -FLAC__bool grabbag__replaygain_load_from_vorbiscomment(const FLAC__StreamMetadata *block, FLAC__bool album_mode, FLAC__bool strict, double *reference, double *gain, double *peak); -double grabbag__replaygain_compute_scale_factor(double peak, double gain, double preamp, FLAC__bool prevent_clipping); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/flac/src/include/share/grabbag/seektable.h b/lib/flac/src/include/share/grabbag/seektable.h deleted file mode 100644 index ac294a3..0000000 --- a/lib/flac/src/include/share/grabbag/seektable.h +++ /dev/null @@ -1,39 +0,0 @@ -/* grabbag - Convenience lib for various routines common to several tools - * Copyright (C) 2002-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/* Convenience routines for working with seek tables */ - -/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */ - -#ifndef GRABAG__SEEKTABLE_H -#define GRABAG__SEEKTABLE_H - -#include "FLAC/format.h" - -#ifdef __cplusplus -extern "C" { -#endif - -FLAC__bool grabbag__seektable_convert_specification_to_template(const char *spec, FLAC__bool only_explicit_placeholders, FLAC__uint64 total_samples_to_encode, unsigned sample_rate, FLAC__StreamMetadata *seektable_template, FLAC__bool *spec_has_real_points); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/flac/src/include/share/macros.h b/lib/flac/src/include/share/macros.h deleted file mode 100644 index 20b3ea5..0000000 --- a/lib/flac/src/include/share/macros.h +++ /dev/null @@ -1,45 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2013-2016 Xiph.org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -/* FLAC_CHECK_RETURN : Check the return value of the provided function and - * print an error message if it fails (ie returns a value < 0). - * - * Ideally, a library should not print anything, but this macro is only used - * for things that extremely unlikely to fail, like `chown` to a previoulsy - * saved `uid`. - */ - -#define FLAC_CHECK_RETURN(x) \ - { if ((x) < 0) \ - fprintf (stderr, "%s : %s\n", #x, strerror (errno)) ; \ - } diff --git a/lib/flac/src/include/share/msvc2005_int.h b/lib/flac/src/include/share/msvc2005_int.h deleted file mode 100644 index f789fb1..0000000 --- a/lib/flac/src/include/share/msvc2005_int.h +++ /dev/null @@ -1,53 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2017 Xiph.org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* This header file defines integer [u]intNN_t types. - * It is auto-included in all files via "Force Includes" (/FI) - * option in all *.vcproj files (Visual Studio 2005, 2008) - */ - -#ifndef FLAC__SHARE__MSVC2005_INT_H -#define FLAC__SHARE__MSVC2005_INT_H - -#if defined _MSC_VER && _MSC_VER < 1600 - -typedef signed __int8 int8_t; -typedef signed __int16 int16_t; -typedef signed __int32 int32_t; -typedef signed __int64 int64_t; -typedef unsigned __int8 uint8_t; -typedef unsigned __int16 uint16_t; -typedef unsigned __int32 uint32_t; -typedef unsigned __int64 uint64_t; - -#endif - -#endif /* FLAC__SHARE__MSVC2005_INT_H */ diff --git a/lib/flac/src/include/share/private.h b/lib/flac/src/include/share/private.h deleted file mode 100644 index 03083d3..0000000 --- a/lib/flac/src/include/share/private.h +++ /dev/null @@ -1,45 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2013-2016 Xiph.org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__SHARE__PRIVATE_H -#define FLAC__SHARE__PRIVATE_H - -/* - * Unpublished debug routines from libFLAC. This should not be used from any - * client code other than code shipped with the FLAC sources. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_disable_constant_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value); -FLAC_API FLAC__bool FLAC__stream_encoder_disable_fixed_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value); -FLAC_API FLAC__bool FLAC__stream_encoder_disable_verbatim_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value); -FLAC_API FLAC__bool FLAC__stream_encoder_set_do_md5(FLAC__StreamEncoder *encoder, FLAC__bool value); -FLAC_API FLAC__bool FLAC__stream_encoder_get_do_md5(const FLAC__StreamEncoder *encoder); - -#endif /* FLAC__SHARE__PRIVATE_H */ diff --git a/lib/flac/src/include/share/replaygain_analysis.h b/lib/flac/src/include/share/replaygain_analysis.h deleted file mode 100644 index f06a9b2..0000000 --- a/lib/flac/src/include/share/replaygain_analysis.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * ReplayGainAnalysis - analyzes input samples and give the recommended dB change - * Copyright (C) 2001 David Robinson and Glen Sawyer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * concept and filter values by David Robinson (David@Robinson.org) - * -- blame him if you think the idea is flawed - * coding by Glen Sawyer (glensawyer@hotmail.com) 442 N 700 E, Provo, UT 84606 USA - * -- blame him if you think this runs too slowly, or the coding is otherwise flawed - * minor cosmetic tweaks to integrate with FLAC by Josh Coalson - * - * For an explanation of the concepts and the basic algorithms involved, go to: - * http://www.replaygain.org/ - */ - -#ifndef GAIN_ANALYSIS_H -#define GAIN_ANALYSIS_H - -#include - -#define GAIN_NOT_ENOUGH_SAMPLES -24601 -#define GAIN_ANALYSIS_ERROR 0 -#define GAIN_ANALYSIS_OK 1 - -#define INIT_GAIN_ANALYSIS_ERROR 0 -#define INIT_GAIN_ANALYSIS_OK 1 - -#ifdef __cplusplus -extern "C" { -#endif - -typedef float flac_float_t; /* Type used for filtering */ - -extern flac_float_t ReplayGainReferenceLoudness; /* in dB SPL, currently == 89.0 */ - -int InitGainAnalysis ( long samplefreq ); -int ValidGainFrequency ( long samplefreq ); -int AnalyzeSamples ( const flac_float_t* left_samples, const flac_float_t* right_samples, size_t num_samples, int num_channels ); -flac_float_t GetTitleGain ( void ); -flac_float_t GetAlbumGain ( void ); - -#ifdef __cplusplus -} -#endif - -#endif /* GAIN_ANALYSIS_H */ diff --git a/lib/flac/src/include/share/replaygain_synthesis.h b/lib/flac/src/include/share/replaygain_synthesis.h deleted file mode 100644 index 5f4c3ff..0000000 --- a/lib/flac/src/include/share/replaygain_synthesis.h +++ /dev/null @@ -1,52 +0,0 @@ -/* replaygain_synthesis - Routines for applying ReplayGain to a signal - * Copyright (C) 2002-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef FLAC__SHARE__REPLAYGAIN_SYNTHESIS_H -#define FLAC__SHARE__REPLAYGAIN_SYNTHESIS_H - -#include /* for size_t */ -#include "FLAC/format.h" - -#define FLAC_SHARE__MAX_SUPPORTED_CHANNELS FLAC__MAX_CHANNELS - -typedef enum { - NOISE_SHAPING_NONE = 0, - NOISE_SHAPING_LOW = 1, - NOISE_SHAPING_MEDIUM = 2, - NOISE_SHAPING_HIGH = 3 -} NoiseShaping; - -typedef struct { - const float* FilterCoeff; - FLAC__uint64 Mask; - double Add; - float Dither; - float ErrorHistory [FLAC_SHARE__MAX_SUPPORTED_CHANNELS] [16]; /* 16th order Noise shaping */ - float DitherHistory [FLAC_SHARE__MAX_SUPPORTED_CHANNELS] [16]; - int LastRandomNumber [FLAC_SHARE__MAX_SUPPORTED_CHANNELS]; - unsigned LastHistoryIndex; - NoiseShaping ShapingType; -} DitherContext; - -void FLAC__replaygain_synthesis__init_dither_context(DitherContext *dither, int bits, int shapingtype); - -/* scale = (float) pow(10., (double)replaygain * 0.05); */ -size_t FLAC__replaygain_synthesis__apply_gain(FLAC__byte *data_out, FLAC__bool little_endian_data_out, FLAC__bool unsigned_data_out, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, const unsigned source_bps, const unsigned target_bps, const double scale, const FLAC__bool hard_limit, FLAC__bool do_dithering, DitherContext *dither_context); - -#endif diff --git a/lib/flac/src/include/share/safe_str.h b/lib/flac/src/include/share/safe_str.h deleted file mode 100644 index eb974c5..0000000 --- a/lib/flac/src/include/share/safe_str.h +++ /dev/null @@ -1,69 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2013-2016 Xiph.org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* Safe string handling functions to replace things like strcpy, strncpy, - * strcat, strncat etc. - * All of these functions guarantee a correctly NUL terminated string but - * the string may be truncated if the destination buffer was too short. - */ - -#ifndef FLAC__SHARE_SAFE_STR_H -#define FLAC__SHARE_SAFE_STR_H - -static inline char * -safe_strncat(char *dest, const char *src, size_t dest_size) -{ - char * ret; - - if (dest_size < 1) - return dest; - - ret = strncat(dest, src, dest_size - strlen (dest)); - dest [dest_size - 1] = 0; - - return ret; -} - -static inline char * -safe_strncpy(char *dest, const char *src, size_t dest_size) -{ - char * ret; - - if (dest_size < 1) - return dest; - - ret = strncpy(dest, src, dest_size); - dest [dest_size - 1] = 0; - - return ret; -} - -#endif /* FLAC__SHARE_SAFE_STR_H */ diff --git a/lib/flac/src/include/share/utf8.h b/lib/flac/src/include/share/utf8.h deleted file mode 100644 index 7d6650d..0000000 --- a/lib/flac/src/include/share/utf8.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef SHARE__UTF8_H -#define SHARE__UTF8_H - -/* - * Convert a string between UTF-8 and the locale's charset. - * Invalid bytes are replaced by '#', and characters that are - * not available in the target encoding are replaced by '?'. - * - * If the locale's charset is not set explicitly then it is - * obtained using nl_langinfo(CODESET), where available, the - * environment variable CHARSET, or assumed to be US-ASCII. - * - * Return value of conversion functions: - * - * -1 : memory allocation failed - * 0 : data was converted exactly - * 1 : valid data was converted approximately (using '?') - * 2 : input was invalid (but still converted, using '#') - * 3 : unknown encoding (but still converted, using '?') - */ - -int utf8_encode(const char *from, char **to); -int utf8_decode(const char *from, char **to); - -#endif diff --git a/lib/flac/src/include/share/win_utf8_io.h b/lib/flac/src/include/share/win_utf8_io.h deleted file mode 100644 index 6031b89..0000000 --- a/lib/flac/src/include/share/win_utf8_io.h +++ /dev/null @@ -1,61 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2013-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef _WIN32 - -#ifndef flac__win_utf8_io_h -#define flac__win_utf8_io_h - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -size_t strlen_utf8(const char *str); -int win_get_console_width(void); - -int get_utf8_argv(int *argc, char ***argv); - -int printf_utf8(const char *format, ...); -int fprintf_utf8(FILE *stream, const char *format, ...); -int vfprintf_utf8(FILE *stream, const char *format, va_list argptr); - -#include -HANDLE WINAPI CreateFile_utf8(const char *lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif -#endif diff --git a/lib/flac/src/include/share/windows_unicode_filenames.h b/lib/flac/src/include/share/windows_unicode_filenames.h deleted file mode 100644 index 526b30d..0000000 --- a/lib/flac/src/include/share/windows_unicode_filenames.h +++ /dev/null @@ -1,63 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2013-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef _WIN32 - -#ifndef flac__windows_unicode_filenames_h -#define flac__windows_unicode_filenames_h - -#include -#include -#include -#include "FLAC/ordinals.h" - -#ifdef __cplusplus -extern "C" { -#endif - -void flac_internal_set_utf8_filenames(FLAC__bool flag); -FLAC__bool flac_internal_get_utf8_filenames(void); -#define flac_set_utf8_filenames flac_internal_set_utf8_filenames -#define flac_get_utf8_filenames flac_internal_get_utf8_filenames - -FILE* flac_internal_fopen_utf8(const char *filename, const char *mode); -int flac_internal_stat64_utf8(const char *path, struct __stat64 *buffer); -int flac_internal_chmod_utf8(const char *filename, int pmode); -int flac_internal_utime_utf8(const char *filename, struct utimbuf *times); -int flac_internal_unlink_utf8(const char *filename); -int flac_internal_rename_utf8(const char *oldname, const char *newname); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif -#endif diff --git a/lib/flac/src/lpc.c b/lib/flac/src/lpc.c deleted file mode 100644 index 0673895..0000000 --- a/lib/flac/src/lpc.c +++ /dev/null @@ -1,1357 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - -#include "FLAC/assert.h" -#include "FLAC/format.h" -#include "share/compat.h" -#include "private/bitmath.h" -#include "private/lpc.h" -#include "private/macros.h" -#if !defined(NDEBUG) || defined FLAC__OVERFLOW_DETECT || defined FLAC__OVERFLOW_DETECT_VERBOSE -#include -#endif - -/* OPT: #undef'ing this may improve the speed on some architectures */ -#define FLAC__LPC_UNROLLED_FILTER_LOOPS - -#ifndef FLAC__INTEGER_ONLY_LIBRARY - -#if defined(_MSC_VER) && (_MSC_VER < 1800) -#include -static inline long int lround(double x) { - return (long)(x + _copysign(0.5, x)); -} -#elif !defined(HAVE_LROUND) && defined(__GNUC__) -static inline long int lround(double x) { - return (long)(x + __builtin_copysign(0.5, x)); -} -/* If this fails, we are in the presence of a mid 90's compiler, move along... */ -#endif - -void FLAC__lpc_window_data(const FLAC__int32 in[], const FLAC__real window[], FLAC__real out[], uint32_t data_len) -{ - uint32_t i; - for(i = 0; i < data_len; i++) - out[i] = in[i] * window[i]; -} - -void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]) -{ - /* a readable, but slower, version */ -#if 0 - FLAC__real d; - uint32_t i; - - FLAC__ASSERT(lag > 0); - FLAC__ASSERT(lag <= data_len); - - /* - * Technically we should subtract the mean first like so: - * for(i = 0; i < data_len; i++) - * data[i] -= mean; - * but it appears not to make enough of a difference to matter, and - * most signals are already closely centered around zero - */ - while(lag--) { - for(i = lag, d = 0.0; i < data_len; i++) - d += data[i] * data[i - lag]; - autoc[lag] = d; - } -#endif - - /* - * this version tends to run faster because of better data locality - * ('data_len' is usually much larger than 'lag') - */ - FLAC__real d; - uint32_t sample, coeff; - const uint32_t limit = data_len - lag; - - FLAC__ASSERT(lag > 0); - FLAC__ASSERT(lag <= data_len); - - for(coeff = 0; coeff < lag; coeff++) - autoc[coeff] = 0.0; - for(sample = 0; sample <= limit; sample++) { - d = data[sample]; - for(coeff = 0; coeff < lag; coeff++) - autoc[coeff] += d * data[sample+coeff]; - } - for(; sample < data_len; sample++) { - d = data[sample]; - for(coeff = 0; coeff < data_len - sample; coeff++) - autoc[coeff] += d * data[sample+coeff]; - } -} - -void FLAC__lpc_compute_lp_coefficients(const FLAC__real autoc[], uint32_t *max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], double error[]) -{ - uint32_t i, j; - double r, err, lpc[FLAC__MAX_LPC_ORDER]; - - FLAC__ASSERT(0 != max_order); - FLAC__ASSERT(0 < *max_order); - FLAC__ASSERT(*max_order <= FLAC__MAX_LPC_ORDER); - FLAC__ASSERT(autoc[0] != 0.0); - - err = autoc[0]; - - for(i = 0; i < *max_order; i++) { - /* Sum up this iteration's reflection coefficient. */ - r = -autoc[i+1]; - for(j = 0; j < i; j++) - r -= lpc[j] * autoc[i-j]; - r /= err; - - /* Update LPC coefficients and total error. */ - lpc[i]=r; - for(j = 0; j < (i>>1); j++) { - double tmp = lpc[j]; - lpc[j] += r * lpc[i-1-j]; - lpc[i-1-j] += r * tmp; - } - if(i & 1) - lpc[j] += lpc[j] * r; - - err *= (1.0 - r * r); - - /* save this order */ - for(j = 0; j <= i; j++) - lp_coeff[i][j] = (FLAC__real)(-lpc[j]); /* negate FIR filter coeff to get predictor coeff */ - error[i] = err; - - /* see SF bug https://sourceforge.net/p/flac/bugs/234/ */ - if(err == 0.0) { - *max_order = i+1; - return; - } - } -} - -int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], uint32_t order, uint32_t precision, FLAC__int32 qlp_coeff[], int *shift) -{ - uint32_t i; - double cmax; - FLAC__int32 qmax, qmin; - - FLAC__ASSERT(precision > 0); - FLAC__ASSERT(precision >= FLAC__MIN_QLP_COEFF_PRECISION); - - /* drop one bit for the sign; from here on out we consider only |lp_coeff[i]| */ - precision--; - qmax = 1 << precision; - qmin = -qmax; - qmax--; - - /* calc cmax = max( |lp_coeff[i]| ) */ - cmax = 0.0; - for(i = 0; i < order; i++) { - const double d = fabs(lp_coeff[i]); - if(d > cmax) - cmax = d; - } - - if(cmax <= 0.0) { - /* => coefficients are all 0, which means our constant-detect didn't work */ - return 2; - } - else { - const int max_shiftlimit = (1 << (FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN-1)) - 1; - const int min_shiftlimit = -max_shiftlimit - 1; - int log2cmax; - - (void)frexp(cmax, &log2cmax); - log2cmax--; - *shift = (int)precision - log2cmax - 1; - - if(*shift > max_shiftlimit) - *shift = max_shiftlimit; - else if(*shift < min_shiftlimit) - return 1; - } - - if(*shift >= 0) { - double error = 0.0; - FLAC__int32 q; - for(i = 0; i < order; i++) { - error += lp_coeff[i] * (1 << *shift); - q = lround(error); - -#ifdef FLAC__OVERFLOW_DETECT - if(q > qmax+1) /* we expect q==qmax+1 occasionally due to rounding */ - fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q>qmax %d>%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmax,*shift,cmax,precision+1,i,lp_coeff[i]); - else if(q < qmin) - fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q qmax) - q = qmax; - else if(q < qmin) - q = qmin; - error -= q; - qlp_coeff[i] = q; - } - } - /* negative shift is very rare but due to design flaw, negative shift is - * not allowed in the decoder, so it must be handled specially by scaling - * down coeffs - */ - else { - const int nshift = -(*shift); - double error = 0.0; - FLAC__int32 q; -#ifndef NDEBUG - fprintf(stderr,"FLAC__lpc_quantize_coefficients: negative shift=%d order=%u cmax=%f\n", *shift, order, cmax); -#endif - for(i = 0; i < order; i++) { - error += lp_coeff[i] / (1 << nshift); - q = lround(error); -#ifdef FLAC__OVERFLOW_DETECT - if(q > qmax+1) /* we expect q==qmax+1 occasionally due to rounding */ - fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q>qmax %d>%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmax,*shift,cmax,precision+1,i,lp_coeff[i]); - else if(q < qmin) - fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q qmax) - q = qmax; - else if(q < qmin) - q = qmin; - error -= q; - qlp_coeff[i] = q; - } - *shift = 0; - } - - return 0; -} - -#if defined(_MSC_VER) -// silence MSVC warnings about __restrict modifier -#pragma warning ( disable : 4028 ) -#endif - -void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 * flac_restrict data, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict residual) -#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS) -{ - FLAC__int64 sumo; - uint32_t i, j; - FLAC__int32 sum; - const FLAC__int32 *history; - -#ifdef FLAC__OVERFLOW_DETECT_VERBOSE - fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization); - for(i=0;i 0); - - for(i = 0; i < data_len; i++) { - sumo = 0; - sum = 0; - history = data; - for(j = 0; j < order; j++) { - sum += qlp_coeff[j] * (*(--history)); - sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history); - if(sumo > 2147483647ll || sumo < -2147483648ll) - fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%" PRId64 "\n",i,j,qlp_coeff[j],*history,sumo); - } - *(residual++) = *(data++) - (sum >> lp_quantization); - } - - /* Here's a slower but clearer version: - for(i = 0; i < data_len; i++) { - sum = 0; - for(j = 0; j < order; j++) - sum += qlp_coeff[j] * data[i-j-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - */ -} -#else /* fully unrolled version for normal use */ -{ - int i; - FLAC__int32 sum; - - FLAC__ASSERT(order > 0); - FLAC__ASSERT(order <= 32); - - /* - * We do unique versions up to 12th order since that's the subset limit. - * Also they are roughly ordered to match frequency of occurrence to - * minimize branching. - */ - if(order <= 12) { - if(order > 8) { - if(order > 10) { - if(order == 12) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[11] * data[i-12]; - sum += qlp_coeff[10] * data[i-11]; - sum += qlp_coeff[9] * data[i-10]; - sum += qlp_coeff[8] * data[i-9]; - sum += qlp_coeff[7] * data[i-8]; - sum += qlp_coeff[6] * data[i-7]; - sum += qlp_coeff[5] * data[i-6]; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - else { /* order == 11 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[10] * data[i-11]; - sum += qlp_coeff[9] * data[i-10]; - sum += qlp_coeff[8] * data[i-9]; - sum += qlp_coeff[7] * data[i-8]; - sum += qlp_coeff[6] * data[i-7]; - sum += qlp_coeff[5] * data[i-6]; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - } - else { - if(order == 10) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[9] * data[i-10]; - sum += qlp_coeff[8] * data[i-9]; - sum += qlp_coeff[7] * data[i-8]; - sum += qlp_coeff[6] * data[i-7]; - sum += qlp_coeff[5] * data[i-6]; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - else { /* order == 9 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[8] * data[i-9]; - sum += qlp_coeff[7] * data[i-8]; - sum += qlp_coeff[6] * data[i-7]; - sum += qlp_coeff[5] * data[i-6]; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - } - } - else if(order > 4) { - if(order > 6) { - if(order == 8) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[7] * data[i-8]; - sum += qlp_coeff[6] * data[i-7]; - sum += qlp_coeff[5] * data[i-6]; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - else { /* order == 7 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[6] * data[i-7]; - sum += qlp_coeff[5] * data[i-6]; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - } - else { - if(order == 6) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[5] * data[i-6]; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - else { /* order == 5 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - } - } - else { - if(order > 2) { - if(order == 4) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - else { /* order == 3 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - } - else { - if(order == 2) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - else { /* order == 1 */ - for(i = 0; i < (int)data_len; i++) - residual[i] = data[i] - ((qlp_coeff[0] * data[i-1]) >> lp_quantization); - } - } - } - } - else { /* order > 12 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - switch(order) { - case 32: sum += qlp_coeff[31] * data[i-32]; /* Falls through. */ - case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */ - case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */ - case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */ - case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */ - case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */ - case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */ - case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */ - case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */ - case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */ - case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */ - case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */ - case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */ - case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */ - case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */ - case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */ - case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */ - case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */ - case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */ - case 13: sum += qlp_coeff[12] * data[i-13]; - sum += qlp_coeff[11] * data[i-12]; - sum += qlp_coeff[10] * data[i-11]; - sum += qlp_coeff[ 9] * data[i-10]; - sum += qlp_coeff[ 8] * data[i- 9]; - sum += qlp_coeff[ 7] * data[i- 8]; - sum += qlp_coeff[ 6] * data[i- 7]; - sum += qlp_coeff[ 5] * data[i- 6]; - sum += qlp_coeff[ 4] * data[i- 5]; - sum += qlp_coeff[ 3] * data[i- 4]; - sum += qlp_coeff[ 2] * data[i- 3]; - sum += qlp_coeff[ 1] * data[i- 2]; - sum += qlp_coeff[ 0] * data[i- 1]; - } - residual[i] = data[i] - (sum >> lp_quantization); - } - } -} -#endif - -void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 * flac_restrict data, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict residual) -#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS) -{ - uint32_t i, j; - FLAC__int64 sum; - const FLAC__int32 *history; - -#ifdef FLAC__OVERFLOW_DETECT_VERBOSE - fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization); - for(i=0;i 0); - - for(i = 0; i < data_len; i++) { - sum = 0; - history = data; - for(j = 0; j < order; j++) - sum += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*(--history)); - if(FLAC__bitmath_silog2(sum >> lp_quantization) > 32) { - fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, sum=%" PRId64 "\n", i, (sum >> lp_quantization)); - break; - } - if(FLAC__bitmath_silog2((FLAC__int64)(*data) - (sum >> lp_quantization)) > 32) { - fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, data=%d, sum=%" PRId64 ", residual=%" PRId64 "\n", i, *data, (int64_t)(sum >> lp_quantization), ((FLAC__int64)(*data) - (sum >> lp_quantization))); - break; - } - *(residual++) = *(data++) - (FLAC__int32)(sum >> lp_quantization); - } -} -#else /* fully unrolled version for normal use */ -{ - int i; - FLAC__int64 sum; - - FLAC__ASSERT(order > 0); - FLAC__ASSERT(order <= 32); - - /* - * We do unique versions up to 12th order since that's the subset limit. - * Also they are roughly ordered to match frequency of occurrence to - * minimize branching. - */ - if(order <= 12) { - if(order > 8) { - if(order > 10) { - if(order == 12) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[11] * (FLAC__int64)data[i-12]; - sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; - sum += qlp_coeff[9] * (FLAC__int64)data[i-10]; - sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; - sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; - sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; - sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization); - } - } - else { /* order == 11 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; - sum += qlp_coeff[9] * (FLAC__int64)data[i-10]; - sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; - sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; - sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; - sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization); - } - } - } - else { - if(order == 10) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[9] * (FLAC__int64)data[i-10]; - sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; - sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; - sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; - sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization); - } - } - else { /* order == 9 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; - sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; - sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; - sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization); - } - } - } - } - else if(order > 4) { - if(order > 6) { - if(order == 8) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; - sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; - sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization); - } - } - else { /* order == 7 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; - sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization); - } - } - } - else { - if(order == 6) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization); - } - } - else { /* order == 5 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization); - } - } - } - } - else { - if(order > 2) { - if(order == 4) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization); - } - } - else { /* order == 3 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization); - } - } - } - else { - if(order == 2) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization); - } - } - else { /* order == 1 */ - for(i = 0; i < (int)data_len; i++) - residual[i] = data[i] - (FLAC__int32)((qlp_coeff[0] * (FLAC__int64)data[i-1]) >> lp_quantization); - } - } - } - } - else { /* order > 12 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - switch(order) { - case 32: sum += qlp_coeff[31] * (FLAC__int64)data[i-32]; /* Falls through. */ - case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31]; /* Falls through. */ - case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30]; /* Falls through. */ - case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29]; /* Falls through. */ - case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28]; /* Falls through. */ - case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27]; /* Falls through. */ - case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26]; /* Falls through. */ - case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25]; /* Falls through. */ - case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24]; /* Falls through. */ - case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23]; /* Falls through. */ - case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22]; /* Falls through. */ - case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21]; /* Falls through. */ - case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20]; /* Falls through. */ - case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19]; /* Falls through. */ - case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18]; /* Falls through. */ - case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17]; /* Falls through. */ - case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16]; /* Falls through. */ - case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15]; /* Falls through. */ - case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14]; /* Falls through. */ - case 13: sum += qlp_coeff[12] * (FLAC__int64)data[i-13]; - sum += qlp_coeff[11] * (FLAC__int64)data[i-12]; - sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; - sum += qlp_coeff[ 9] * (FLAC__int64)data[i-10]; - sum += qlp_coeff[ 8] * (FLAC__int64)data[i- 9]; - sum += qlp_coeff[ 7] * (FLAC__int64)data[i- 8]; - sum += qlp_coeff[ 6] * (FLAC__int64)data[i- 7]; - sum += qlp_coeff[ 5] * (FLAC__int64)data[i- 6]; - sum += qlp_coeff[ 4] * (FLAC__int64)data[i- 5]; - sum += qlp_coeff[ 3] * (FLAC__int64)data[i- 4]; - sum += qlp_coeff[ 2] * (FLAC__int64)data[i- 3]; - sum += qlp_coeff[ 1] * (FLAC__int64)data[i- 2]; - sum += qlp_coeff[ 0] * (FLAC__int64)data[i- 1]; - } - residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization); - } - } -} -#endif - -#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ - -void FLAC__lpc_restore_signal(const FLAC__int32 * flac_restrict residual, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict data) -#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS) -{ - FLAC__int64 sumo; - uint32_t i, j; - FLAC__int32 sum; - const FLAC__int32 *r = residual, *history; - -#ifdef FLAC__OVERFLOW_DETECT_VERBOSE - fprintf(stderr,"FLAC__lpc_restore_signal: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization); - for(i=0;i 0); - - for(i = 0; i < data_len; i++) { - sumo = 0; - sum = 0; - history = data; - for(j = 0; j < order; j++) { - sum += qlp_coeff[j] * (*(--history)); - sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history); - if(sumo > 2147483647ll || sumo < -2147483648ll) - fprintf(stderr,"FLAC__lpc_restore_signal: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%" PRId64 "\n",i,j,qlp_coeff[j],*history,sumo); - } - *(data++) = *(r++) + (sum >> lp_quantization); - } - - /* Here's a slower but clearer version: - for(i = 0; i < data_len; i++) { - sum = 0; - for(j = 0; j < order; j++) - sum += qlp_coeff[j] * data[i-j-1]; - data[i] = residual[i] + (sum >> lp_quantization); - } - */ -} -#else /* fully unrolled version for normal use */ -{ - int i; - FLAC__int32 sum; - - FLAC__ASSERT(order > 0); - FLAC__ASSERT(order <= 32); - - /* - * We do unique versions up to 12th order since that's the subset limit. - * Also they are roughly ordered to match frequency of occurrence to - * minimize branching. - */ - if(order <= 12) { - if(order > 8) { - if(order > 10) { - if(order == 12) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[11] * data[i-12]; - sum += qlp_coeff[10] * data[i-11]; - sum += qlp_coeff[9] * data[i-10]; - sum += qlp_coeff[8] * data[i-9]; - sum += qlp_coeff[7] * data[i-8]; - sum += qlp_coeff[6] * data[i-7]; - sum += qlp_coeff[5] * data[i-6]; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - data[i] = residual[i] + (sum >> lp_quantization); - } - } - else { /* order == 11 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[10] * data[i-11]; - sum += qlp_coeff[9] * data[i-10]; - sum += qlp_coeff[8] * data[i-9]; - sum += qlp_coeff[7] * data[i-8]; - sum += qlp_coeff[6] * data[i-7]; - sum += qlp_coeff[5] * data[i-6]; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - data[i] = residual[i] + (sum >> lp_quantization); - } - } - } - else { - if(order == 10) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[9] * data[i-10]; - sum += qlp_coeff[8] * data[i-9]; - sum += qlp_coeff[7] * data[i-8]; - sum += qlp_coeff[6] * data[i-7]; - sum += qlp_coeff[5] * data[i-6]; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - data[i] = residual[i] + (sum >> lp_quantization); - } - } - else { /* order == 9 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[8] * data[i-9]; - sum += qlp_coeff[7] * data[i-8]; - sum += qlp_coeff[6] * data[i-7]; - sum += qlp_coeff[5] * data[i-6]; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - data[i] = residual[i] + (sum >> lp_quantization); - } - } - } - } - else if(order > 4) { - if(order > 6) { - if(order == 8) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[7] * data[i-8]; - sum += qlp_coeff[6] * data[i-7]; - sum += qlp_coeff[5] * data[i-6]; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - data[i] = residual[i] + (sum >> lp_quantization); - } - } - else { /* order == 7 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[6] * data[i-7]; - sum += qlp_coeff[5] * data[i-6]; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - data[i] = residual[i] + (sum >> lp_quantization); - } - } - } - else { - if(order == 6) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[5] * data[i-6]; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - data[i] = residual[i] + (sum >> lp_quantization); - } - } - else { /* order == 5 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - data[i] = residual[i] + (sum >> lp_quantization); - } - } - } - } - else { - if(order > 2) { - if(order == 4) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - data[i] = residual[i] + (sum >> lp_quantization); - } - } - else { /* order == 3 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - data[i] = residual[i] + (sum >> lp_quantization); - } - } - } - else { - if(order == 2) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - data[i] = residual[i] + (sum >> lp_quantization); - } - } - else { /* order == 1 */ - for(i = 0; i < (int)data_len; i++) - data[i] = residual[i] + ((qlp_coeff[0] * data[i-1]) >> lp_quantization); - } - } - } - } - else { /* order > 12 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - switch(order) { - case 32: sum += qlp_coeff[31] * data[i-32]; /* Falls through. */ - case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */ - case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */ - case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */ - case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */ - case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */ - case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */ - case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */ - case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */ - case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */ - case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */ - case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */ - case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */ - case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */ - case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */ - case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */ - case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */ - case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */ - case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */ - case 13: sum += qlp_coeff[12] * data[i-13]; - sum += qlp_coeff[11] * data[i-12]; - sum += qlp_coeff[10] * data[i-11]; - sum += qlp_coeff[ 9] * data[i-10]; - sum += qlp_coeff[ 8] * data[i- 9]; - sum += qlp_coeff[ 7] * data[i- 8]; - sum += qlp_coeff[ 6] * data[i- 7]; - sum += qlp_coeff[ 5] * data[i- 6]; - sum += qlp_coeff[ 4] * data[i- 5]; - sum += qlp_coeff[ 3] * data[i- 4]; - sum += qlp_coeff[ 2] * data[i- 3]; - sum += qlp_coeff[ 1] * data[i- 2]; - sum += qlp_coeff[ 0] * data[i- 1]; - } - data[i] = residual[i] + (sum >> lp_quantization); - } - } -} -#endif - -void FLAC__lpc_restore_signal_wide(const FLAC__int32 * flac_restrict residual, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict data) -#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS) -{ - uint32_t i, j; - FLAC__int64 sum; - const FLAC__int32 *r = residual, *history; - -#ifdef FLAC__OVERFLOW_DETECT_VERBOSE - fprintf(stderr,"FLAC__lpc_restore_signal_wide: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization); - for(i=0;i 0); - - for(i = 0; i < data_len; i++) { - sum = 0; - history = data; - for(j = 0; j < order; j++) - sum += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*(--history)); - if(FLAC__bitmath_silog2(sum >> lp_quantization) > 32) { - fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, sum=%" PRId64 "\n", i, (sum >> lp_quantization)); - break; - } - if(FLAC__bitmath_silog2((FLAC__int64)(*r) + (sum >> lp_quantization)) > 32) { - fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, residual=%d, sum=%" PRId64 ", data=%" PRId64 "\n", i, *r, (sum >> lp_quantization), ((FLAC__int64)(*r) + (sum >> lp_quantization))); - break; - } - *(data++) = *(r++) + (FLAC__int32)(sum >> lp_quantization); - } -} -#else /* fully unrolled version for normal use */ -{ - int i; - FLAC__int64 sum; - - FLAC__ASSERT(order > 0); - FLAC__ASSERT(order <= 32); - - /* - * We do unique versions up to 12th order since that's the subset limit. - * Also they are roughly ordered to match frequency of occurrence to - * minimize branching. - */ - if(order <= 12) { - if(order > 8) { - if(order > 10) { - if(order == 12) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[11] * (FLAC__int64)data[i-12]; - sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; - sum += qlp_coeff[9] * (FLAC__int64)data[i-10]; - sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; - sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; - sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; - sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization); - } - } - else { /* order == 11 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; - sum += qlp_coeff[9] * (FLAC__int64)data[i-10]; - sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; - sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; - sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; - sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization); - } - } - } - else { - if(order == 10) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[9] * (FLAC__int64)data[i-10]; - sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; - sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; - sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; - sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization); - } - } - else { /* order == 9 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; - sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; - sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; - sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization); - } - } - } - } - else if(order > 4) { - if(order > 6) { - if(order == 8) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; - sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; - sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization); - } - } - else { /* order == 7 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; - sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization); - } - } - } - else { - if(order == 6) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization); - } - } - else { /* order == 5 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization); - } - } - } - } - else { - if(order > 2) { - if(order == 4) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization); - } - } - else { /* order == 3 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization); - } - } - } - else { - if(order == 2) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization); - } - } - else { /* order == 1 */ - for(i = 0; i < (int)data_len; i++) - data[i] = residual[i] + (FLAC__int32)((qlp_coeff[0] * (FLAC__int64)data[i-1]) >> lp_quantization); - } - } - } - } - else { /* order > 12 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - switch(order) { - case 32: sum += qlp_coeff[31] * (FLAC__int64)data[i-32]; /* Falls through. */ - case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31]; /* Falls through. */ - case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30]; /* Falls through. */ - case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29]; /* Falls through. */ - case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28]; /* Falls through. */ - case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27]; /* Falls through. */ - case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26]; /* Falls through. */ - case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25]; /* Falls through. */ - case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24]; /* Falls through. */ - case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23]; /* Falls through. */ - case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22]; /* Falls through. */ - case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21]; /* Falls through. */ - case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20]; /* Falls through. */ - case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19]; /* Falls through. */ - case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18]; /* Falls through. */ - case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17]; /* Falls through. */ - case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16]; /* Falls through. */ - case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15]; /* Falls through. */ - case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14]; /* Falls through. */ - case 13: sum += qlp_coeff[12] * (FLAC__int64)data[i-13]; - sum += qlp_coeff[11] * (FLAC__int64)data[i-12]; - sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; - sum += qlp_coeff[ 9] * (FLAC__int64)data[i-10]; - sum += qlp_coeff[ 8] * (FLAC__int64)data[i- 9]; - sum += qlp_coeff[ 7] * (FLAC__int64)data[i- 8]; - sum += qlp_coeff[ 6] * (FLAC__int64)data[i- 7]; - sum += qlp_coeff[ 5] * (FLAC__int64)data[i- 6]; - sum += qlp_coeff[ 4] * (FLAC__int64)data[i- 5]; - sum += qlp_coeff[ 3] * (FLAC__int64)data[i- 4]; - sum += qlp_coeff[ 2] * (FLAC__int64)data[i- 3]; - sum += qlp_coeff[ 1] * (FLAC__int64)data[i- 2]; - sum += qlp_coeff[ 0] * (FLAC__int64)data[i- 1]; - } - data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization); - } - } -} -#endif - -#if defined(_MSC_VER) -#pragma warning ( default : 4028 ) -#endif - -#ifndef FLAC__INTEGER_ONLY_LIBRARY - -double FLAC__lpc_compute_expected_bits_per_residual_sample(double lpc_error, uint32_t total_samples) -{ - double error_scale; - - FLAC__ASSERT(total_samples > 0); - - error_scale = 0.5 / (double)total_samples; - - return FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error, error_scale); -} - -double FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(double lpc_error, double error_scale) -{ - if(lpc_error > 0.0) { - double bps = (double)0.5 * log(error_scale * lpc_error) / M_LN2; - if(bps >= 0.0) - return bps; - else - return 0.0; - } - else if(lpc_error < 0.0) { /* error should not be negative but can happen due to inadequate floating-point resolution */ - return 1e32; - } - else { - return 0.0; - } -} - -uint32_t FLAC__lpc_compute_best_order(const double lpc_error[], uint32_t max_order, uint32_t total_samples, uint32_t overhead_bits_per_order) -{ - uint32_t order, indx, best_index; /* 'index' the index into lpc_error; index==order-1 since lpc_error[0] is for order==1, lpc_error[1] is for order==2, etc */ - double bits, best_bits, error_scale; - - FLAC__ASSERT(max_order > 0); - FLAC__ASSERT(total_samples > 0); - - error_scale = 0.5 / (double)total_samples; - - best_index = 0; - best_bits = (uint32_t)(-1); - - for(indx = 0, order = 1; indx < max_order; indx++, order++) { - bits = FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error[indx], error_scale) * (double)(total_samples - order) + (double)(order * overhead_bits_per_order); - if(bits < best_bits) { - best_index = indx; - best_bits = bits; - } - } - - return best_index+1; /* +1 since indx of lpc_error[] is order-1 */ -} - -#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ diff --git a/lib/flac/src/md5.c b/lib/flac/src/md5.c deleted file mode 100644 index 09933d7..0000000 --- a/lib/flac/src/md5.c +++ /dev/null @@ -1,517 +0,0 @@ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include /* for malloc() */ -#include /* for memcpy() */ - -#include "private/md5.h" -#include "share/alloc.h" -#include "share/compat.h" -#include "share/endswap.h" - -/* - * This code implements the MD5 message-digest algorithm. - * The algorithm is due to Ron Rivest. This code was - * written by Colin Plumb in 1993, no copyright is claimed. - * This code is in the public domain; do with it what you wish. - * - * Equivalent code is available from RSA Data Security, Inc. - * This code has been tested against that, and is equivalent, - * except that you don't need to include two pages of legalese - * with every copy. - * - * To compute the message digest of a chunk of bytes, declare an - * MD5Context structure, pass it to MD5Init, call MD5Update as - * needed on buffers full of bytes, and then call MD5Final, which - * will fill a supplied 16-byte array with the digest. - * - * Changed so as no longer to depend on Colin Plumb's `usual.h' header - * definitions; now uses stuff from dpkg's config.h. - * - Ian Jackson . - * Still in the public domain. - * - * Josh Coalson: made some changes to integrate with libFLAC. - * Still in the public domain. - */ - -/* The four core functions - F1 is optimized somewhat */ - -/* #define F1(x, y, z) (x & y | ~x & z) */ -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1(z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) - -/* This is the central step in the MD5 algorithm. */ -#define MD5STEP(f,w,x,y,z,in,s) \ - (w += f(x,y,z) + in, w = (w<>(32-s)) + x) - -/* - * The core of the MD5 algorithm, this alters an existing MD5 hash to - * reflect the addition of 16 longwords of new data. MD5Update blocks - * the data and converts bytes into longwords for this routine. - */ -static void FLAC__MD5Transform(FLAC__uint32 buf[4], FLAC__uint32 const in[16]) -{ - register FLAC__uint32 a, b, c, d; - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); - MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); - MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); - MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); - MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); - MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); - MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); - MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); - MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); - MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); - MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); - MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); - MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); - MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); - MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); - MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); - - MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); - MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); - MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); - MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); - MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); - MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); - MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); - MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); - MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); - MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); - MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); - MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); - MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); - MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); - MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); - MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); - - MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); - MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); - MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); - MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); - MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); - MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); - MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); - MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); - MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); - MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); - MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); - MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); - MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); - MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); - MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); - MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); - - MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); - MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); - MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); - MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); - MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); - MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); - MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); - MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); - MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); - MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); - MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); - MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); - MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); - MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); - MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); - MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; -} - -#if WORDS_BIGENDIAN -//@@@@@@ OPT: use bswap/intrinsics -static void byteSwap(FLAC__uint32 *buf, uint32_t words) -{ - register FLAC__uint32 x; - do { - x = *buf; - x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); - *buf++ = (x >> 16) | (x << 16); - } while (--words); -} -static void byteSwapX16(FLAC__uint32 *buf) -{ - register FLAC__uint32 x; - - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf = (x >> 16) | (x << 16); -} -#else -#define byteSwap(buf, words) -#define byteSwapX16(buf) -#endif - -/* - * Update context to reflect the concatenation of another buffer full - * of bytes. - */ -static void FLAC__MD5Update(FLAC__MD5Context *ctx, FLAC__byte const *buf, uint32_t len) -{ - FLAC__uint32 t; - - /* Update byte count */ - - t = ctx->bytes[0]; - if ((ctx->bytes[0] = t + len) < t) - ctx->bytes[1]++; /* Carry from low to high */ - - t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ - if (t > len) { - memcpy((FLAC__byte *)ctx->in + 64 - t, buf, len); - return; - } - /* First chunk is an odd size */ - memcpy((FLAC__byte *)ctx->in + 64 - t, buf, t); - byteSwapX16(ctx->in); - FLAC__MD5Transform(ctx->buf, ctx->in); - buf += t; - len -= t; - - /* Process data in 64-byte chunks */ - while (len >= 64) { - memcpy(ctx->in, buf, 64); - byteSwapX16(ctx->in); - FLAC__MD5Transform(ctx->buf, ctx->in); - buf += 64; - len -= 64; - } - - /* Handle any remaining bytes of data. */ - memcpy(ctx->in, buf, len); -} - -/* - * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious - * initialization constants. - */ -void FLAC__MD5Init(FLAC__MD5Context *ctx) -{ - ctx->buf[0] = 0x67452301; - ctx->buf[1] = 0xefcdab89; - ctx->buf[2] = 0x98badcfe; - ctx->buf[3] = 0x10325476; - - ctx->bytes[0] = 0; - ctx->bytes[1] = 0; - - ctx->internal_buf.p8 = 0; - ctx->capacity = 0; -} - -/* - * Final wrapup - pad to 64-byte boundary with the bit pattern - * 1 0* (64-bit count of bits processed, MSB-first) - */ -void FLAC__MD5Final(FLAC__byte digest[16], FLAC__MD5Context *ctx) -{ - int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ - FLAC__byte *p = (FLAC__byte *)ctx->in + count; - - /* Set the first char of padding to 0x80. There is always room. */ - *p++ = 0x80; - - /* Bytes of padding needed to make 56 bytes (-8..55) */ - count = 56 - 1 - count; - - if (count < 0) { /* Padding forces an extra block */ - memset(p, 0, count + 8); - byteSwapX16(ctx->in); - FLAC__MD5Transform(ctx->buf, ctx->in); - p = (FLAC__byte *)ctx->in; - count = 56; - } - memset(p, 0, count); - byteSwap(ctx->in, 14); - - /* Append length in bits and transform */ - ctx->in[14] = ctx->bytes[0] << 3; - ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; - FLAC__MD5Transform(ctx->buf, ctx->in); - - byteSwap(ctx->buf, 4); - memcpy(digest, ctx->buf, 16); - if (0 != ctx->internal_buf.p8) { - free(ctx->internal_buf.p8); - ctx->internal_buf.p8 = 0; - ctx->capacity = 0; - } - memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ -} - -/* - * Convert the incoming audio signal to a byte stream - */ -static void format_input_(FLAC__multibyte *mbuf, const FLAC__int32 * const signal[], uint32_t channels, uint32_t samples, uint32_t bytes_per_sample) -{ - FLAC__byte *buf_ = mbuf->p8; - FLAC__int16 *buf16 = mbuf->p16; - FLAC__int32 *buf32 = mbuf->p32; - FLAC__int32 a_word; - uint32_t channel, sample; - - /* Storage in the output buffer, buf, is little endian. */ - -#define BYTES_CHANNEL_SELECTOR(bytes, channels) (bytes * 100 + channels) - - /* First do the most commonly used combinations. */ - switch (BYTES_CHANNEL_SELECTOR (bytes_per_sample, channels)) { - /* One byte per sample. */ - case (BYTES_CHANNEL_SELECTOR (1, 1)): - for (sample = 0; sample < samples; sample++) - *buf_++ = signal[0][sample]; - return; - - case (BYTES_CHANNEL_SELECTOR (1, 2)): - for (sample = 0; sample < samples; sample++) { - *buf_++ = signal[0][sample]; - *buf_++ = signal[1][sample]; - } - return; - - case (BYTES_CHANNEL_SELECTOR (1, 4)): - for (sample = 0; sample < samples; sample++) { - *buf_++ = signal[0][sample]; - *buf_++ = signal[1][sample]; - *buf_++ = signal[2][sample]; - *buf_++ = signal[3][sample]; - } - return; - - case (BYTES_CHANNEL_SELECTOR (1, 6)): - for (sample = 0; sample < samples; sample++) { - *buf_++ = signal[0][sample]; - *buf_++ = signal[1][sample]; - *buf_++ = signal[2][sample]; - *buf_++ = signal[3][sample]; - *buf_++ = signal[4][sample]; - *buf_++ = signal[5][sample]; - } - return; - - case (BYTES_CHANNEL_SELECTOR (1, 8)): - for (sample = 0; sample < samples; sample++) { - *buf_++ = signal[0][sample]; - *buf_++ = signal[1][sample]; - *buf_++ = signal[2][sample]; - *buf_++ = signal[3][sample]; - *buf_++ = signal[4][sample]; - *buf_++ = signal[5][sample]; - *buf_++ = signal[6][sample]; - *buf_++ = signal[7][sample]; - } - return; - - /* Two bytes per sample. */ - case (BYTES_CHANNEL_SELECTOR (2, 1)): - for (sample = 0; sample < samples; sample++) - *buf16++ = H2LE_16(signal[0][sample]); - return; - - case (BYTES_CHANNEL_SELECTOR (2, 2)): - for (sample = 0; sample < samples; sample++) { - *buf16++ = H2LE_16(signal[0][sample]); - *buf16++ = H2LE_16(signal[1][sample]); - } - return; - - case (BYTES_CHANNEL_SELECTOR (2, 4)): - for (sample = 0; sample < samples; sample++) { - *buf16++ = H2LE_16(signal[0][sample]); - *buf16++ = H2LE_16(signal[1][sample]); - *buf16++ = H2LE_16(signal[2][sample]); - *buf16++ = H2LE_16(signal[3][sample]); - } - return; - - case (BYTES_CHANNEL_SELECTOR (2, 6)): - for (sample = 0; sample < samples; sample++) { - *buf16++ = H2LE_16(signal[0][sample]); - *buf16++ = H2LE_16(signal[1][sample]); - *buf16++ = H2LE_16(signal[2][sample]); - *buf16++ = H2LE_16(signal[3][sample]); - *buf16++ = H2LE_16(signal[4][sample]); - *buf16++ = H2LE_16(signal[5][sample]); - } - return; - - case (BYTES_CHANNEL_SELECTOR (2, 8)): - for (sample = 0; sample < samples; sample++) { - *buf16++ = H2LE_16(signal[0][sample]); - *buf16++ = H2LE_16(signal[1][sample]); - *buf16++ = H2LE_16(signal[2][sample]); - *buf16++ = H2LE_16(signal[3][sample]); - *buf16++ = H2LE_16(signal[4][sample]); - *buf16++ = H2LE_16(signal[5][sample]); - *buf16++ = H2LE_16(signal[6][sample]); - *buf16++ = H2LE_16(signal[7][sample]); - } - return; - - /* Three bytes per sample. */ - case (BYTES_CHANNEL_SELECTOR (3, 1)): - for (sample = 0; sample < samples; sample++) { - a_word = signal[0][sample]; - *buf_++ = (FLAC__byte)a_word; a_word >>= 8; - *buf_++ = (FLAC__byte)a_word; a_word >>= 8; - *buf_++ = (FLAC__byte)a_word; - } - return; - - case (BYTES_CHANNEL_SELECTOR (3, 2)): - for (sample = 0; sample < samples; sample++) { - a_word = signal[0][sample]; - *buf_++ = (FLAC__byte)a_word; a_word >>= 8; - *buf_++ = (FLAC__byte)a_word; a_word >>= 8; - *buf_++ = (FLAC__byte)a_word; - a_word = signal[1][sample]; - *buf_++ = (FLAC__byte)a_word; a_word >>= 8; - *buf_++ = (FLAC__byte)a_word; a_word >>= 8; - *buf_++ = (FLAC__byte)a_word; - } - return; - - /* Four bytes per sample. */ - case (BYTES_CHANNEL_SELECTOR (4, 1)): - for (sample = 0; sample < samples; sample++) - *buf32++ = H2LE_32(signal[0][sample]); - return; - - case (BYTES_CHANNEL_SELECTOR (4, 2)): - for (sample = 0; sample < samples; sample++) { - *buf32++ = H2LE_32(signal[0][sample]); - *buf32++ = H2LE_32(signal[1][sample]); - } - return; - - case (BYTES_CHANNEL_SELECTOR (4, 4)): - for (sample = 0; sample < samples; sample++) { - *buf32++ = H2LE_32(signal[0][sample]); - *buf32++ = H2LE_32(signal[1][sample]); - *buf32++ = H2LE_32(signal[2][sample]); - *buf32++ = H2LE_32(signal[3][sample]); - } - return; - - case (BYTES_CHANNEL_SELECTOR (4, 6)): - for (sample = 0; sample < samples; sample++) { - *buf32++ = H2LE_32(signal[0][sample]); - *buf32++ = H2LE_32(signal[1][sample]); - *buf32++ = H2LE_32(signal[2][sample]); - *buf32++ = H2LE_32(signal[3][sample]); - *buf32++ = H2LE_32(signal[4][sample]); - *buf32++ = H2LE_32(signal[5][sample]); - } - return; - - case (BYTES_CHANNEL_SELECTOR (4, 8)): - for (sample = 0; sample < samples; sample++) { - *buf32++ = H2LE_32(signal[0][sample]); - *buf32++ = H2LE_32(signal[1][sample]); - *buf32++ = H2LE_32(signal[2][sample]); - *buf32++ = H2LE_32(signal[3][sample]); - *buf32++ = H2LE_32(signal[4][sample]); - *buf32++ = H2LE_32(signal[5][sample]); - *buf32++ = H2LE_32(signal[6][sample]); - *buf32++ = H2LE_32(signal[7][sample]); - } - return; - - default: - break; - } - - /* General version. */ - switch (bytes_per_sample) { - case 1: - for (sample = 0; sample < samples; sample++) - for (channel = 0; channel < channels; channel++) - *buf_++ = signal[channel][sample]; - return; - - case 2: - for (sample = 0; sample < samples; sample++) - for (channel = 0; channel < channels; channel++) - *buf16++ = H2LE_16(signal[channel][sample]); - return; - - case 3: - for (sample = 0; sample < samples; sample++) - for (channel = 0; channel < channels; channel++) { - a_word = signal[channel][sample]; - *buf_++ = (FLAC__byte)a_word; a_word >>= 8; - *buf_++ = (FLAC__byte)a_word; a_word >>= 8; - *buf_++ = (FLAC__byte)a_word; - } - return; - - case 4: - for (sample = 0; sample < samples; sample++) - for (channel = 0; channel < channels; channel++) - *buf32++ = H2LE_32(signal[channel][sample]); - return; - - default: - break; - } -} - -/* - * Convert the incoming audio signal to a byte stream and FLAC__MD5Update it. - */ -FLAC__bool FLAC__MD5Accumulate(FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], uint32_t channels, uint32_t samples, uint32_t bytes_per_sample) -{ - const size_t bytes_needed = (size_t)channels * (size_t)samples * (size_t)bytes_per_sample; - - /* overflow check */ - if ((size_t)channels > SIZE_MAX / (size_t)bytes_per_sample) - return false; - if ((size_t)channels * (size_t)bytes_per_sample > SIZE_MAX / (size_t)samples) - return false; - - if (ctx->capacity < bytes_needed) { - if (0 == (ctx->internal_buf.p8 = safe_realloc_(ctx->internal_buf.p8, bytes_needed))) { - if (0 == (ctx->internal_buf.p8 = safe_malloc_(bytes_needed))) { - ctx->capacity = 0; - return false; - } - } - ctx->capacity = bytes_needed; - } - - format_input_(&ctx->internal_buf, signal, channels, samples, bytes_per_sample); - - FLAC__MD5Update(ctx, ctx->internal_buf.p8, bytes_needed); - - return true; -} diff --git a/lib/flac/src/memory.c b/lib/flac/src/memory.c deleted file mode 100644 index 4d320a4..0000000 --- a/lib/flac/src/memory.c +++ /dev/null @@ -1,219 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#ifdef HAVE_STDINT_H -#include -#endif - -#include "private/memory.h" -#include "FLAC/assert.h" -#include "share/compat.h" -#include "share/alloc.h" - -void *FLAC__memory_alloc_aligned(size_t bytes, void **aligned_address) -{ - void *x; - - FLAC__ASSERT(0 != aligned_address); - -#ifdef FLAC__ALIGN_MALLOC_DATA - /* align on 32-byte (256-bit) boundary */ - x = safe_malloc_add_2op_(bytes, /*+*/31L); - *aligned_address = (void*)(((uintptr_t)x + 31L) & -32L); -#else - x = safe_malloc_(bytes); - *aligned_address = x; -#endif - return x; -} - -FLAC__bool FLAC__memory_alloc_aligned_int32_array(size_t elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_pointer) -{ - FLAC__int32 *pu; /* unaligned pointer */ - union { /* union needed to comply with C99 pointer aliasing rules */ - FLAC__int32 *pa; /* aligned pointer */ - void *pv; /* aligned pointer alias */ - } u; - - FLAC__ASSERT(elements > 0); - FLAC__ASSERT(0 != unaligned_pointer); - FLAC__ASSERT(0 != aligned_pointer); - FLAC__ASSERT(unaligned_pointer != aligned_pointer); - - if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ - return false; - - pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv); - if(0 == pu) { - return false; - } - else { - if(*unaligned_pointer != 0) - free(*unaligned_pointer); - *unaligned_pointer = pu; - *aligned_pointer = u.pa; - return true; - } -} - -FLAC__bool FLAC__memory_alloc_aligned_uint32_array(size_t elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_pointer) -{ - FLAC__uint32 *pu; /* unaligned pointer */ - union { /* union needed to comply with C99 pointer aliasing rules */ - FLAC__uint32 *pa; /* aligned pointer */ - void *pv; /* aligned pointer alias */ - } u; - - FLAC__ASSERT(elements > 0); - FLAC__ASSERT(0 != unaligned_pointer); - FLAC__ASSERT(0 != aligned_pointer); - FLAC__ASSERT(unaligned_pointer != aligned_pointer); - - if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ - return false; - - pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv); - if(0 == pu) { - return false; - } - else { - if(*unaligned_pointer != 0) - free(*unaligned_pointer); - *unaligned_pointer = pu; - *aligned_pointer = u.pa; - return true; - } -} - -FLAC__bool FLAC__memory_alloc_aligned_uint64_array(size_t elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_pointer) -{ - FLAC__uint64 *pu; /* unaligned pointer */ - union { /* union needed to comply with C99 pointer aliasing rules */ - FLAC__uint64 *pa; /* aligned pointer */ - void *pv; /* aligned pointer alias */ - } u; - - FLAC__ASSERT(elements > 0); - FLAC__ASSERT(0 != unaligned_pointer); - FLAC__ASSERT(0 != aligned_pointer); - FLAC__ASSERT(unaligned_pointer != aligned_pointer); - - if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ - return false; - - pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv); - if(0 == pu) { - return false; - } - else { - if(*unaligned_pointer != 0) - free(*unaligned_pointer); - *unaligned_pointer = pu; - *aligned_pointer = u.pa; - return true; - } -} - -FLAC__bool FLAC__memory_alloc_aligned_unsigned_array(size_t elements, uint32_t **unaligned_pointer, uint32_t **aligned_pointer) -{ - uint32_t *pu; /* unaligned pointer */ - union { /* union needed to comply with C99 pointer aliasing rules */ - uint32_t *pa; /* aligned pointer */ - void *pv; /* aligned pointer alias */ - } u; - - FLAC__ASSERT(elements > 0); - FLAC__ASSERT(0 != unaligned_pointer); - FLAC__ASSERT(0 != aligned_pointer); - FLAC__ASSERT(unaligned_pointer != aligned_pointer); - - if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ - return false; - - pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv); - if(0 == pu) { - return false; - } - else { - if(*unaligned_pointer != 0) - free(*unaligned_pointer); - *unaligned_pointer = pu; - *aligned_pointer = u.pa; - return true; - } -} - -#ifndef FLAC__INTEGER_ONLY_LIBRARY - -FLAC__bool FLAC__memory_alloc_aligned_real_array(size_t elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer) -{ - FLAC__real *pu; /* unaligned pointer */ - union { /* union needed to comply with C99 pointer aliasing rules */ - FLAC__real *pa; /* aligned pointer */ - void *pv; /* aligned pointer alias */ - } u; - - FLAC__ASSERT(elements > 0); - FLAC__ASSERT(0 != unaligned_pointer); - FLAC__ASSERT(0 != aligned_pointer); - FLAC__ASSERT(unaligned_pointer != aligned_pointer); - - if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ - return false; - - pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv); - if(0 == pu) { - return false; - } - else { - if(*unaligned_pointer != 0) - free(*unaligned_pointer); - *unaligned_pointer = pu; - *aligned_pointer = u.pa; - return true; - } -} - -#endif - -void *safe_malloc_mul_2op_p(size_t size1, size_t size2) -{ - if(!size1 || !size2) - return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */ - if(size1 > SIZE_MAX / size2) - return 0; - return malloc(size1*size2); -} diff --git a/lib/flac/src/metadata_iterators.c b/lib/flac/src/metadata_iterators.c deleted file mode 100644 index 352a6c7..0000000 --- a/lib/flac/src/metadata_iterators.c +++ /dev/null @@ -1,3481 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include -#include -#include - -#include /* for stat(), maybe chmod() */ - -#include "private/metadata.h" - -#include "FLAC/assert.h" -#include "FLAC/stream_decoder.h" -#include "share/alloc.h" -#include "share/compat.h" -#include "share/macros.h" -#include "share/safe_str.h" -#include "private/macros.h" -#include "private/memory.h" - -/* Alias the first (in share/alloc.h) to the second (in src/libFLAC/memory.c). */ -#define safe_malloc_mul_2op_ safe_malloc_mul_2op_p - -/**************************************************************************** - * - * Local function declarations - * - ***************************************************************************/ - -static void pack_uint32_(FLAC__uint32 val, FLAC__byte *b, uint32_t bytes); -static void pack_uint32_little_endian_(FLAC__uint32 val, FLAC__byte *b, uint32_t bytes); -static void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, uint32_t bytes); -static FLAC__uint32 unpack_uint32_(FLAC__byte *b, uint32_t bytes); -static FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, uint32_t bytes); -static FLAC__uint64 unpack_uint64_(FLAC__byte *b, uint32_t bytes); - -static FLAC__bool read_metadata_block_header_(FLAC__Metadata_SimpleIterator *iterator); -static FLAC__bool read_metadata_block_data_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block); -static FLAC__bool read_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__bool *is_last, FLAC__MetadataType *type, uint32_t *length); -static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata *block); -static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_StreamInfo *block); -static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_Padding *block, uint32_t block_length); -static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Application *block, uint32_t block_length); -static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_SeekTable *block, uint32_t block_length); -static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entry_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment_Entry *entry, uint32_t max_length); -static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_VorbisComment *block, uint32_t block_length); -static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_track_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet_Track *track); -static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet *block); -static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Picture *block); -static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Unknown *block, uint32_t block_length); - -static FLAC__bool write_metadata_block_header_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block); -static FLAC__bool write_metadata_block_data_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block); -static FLAC__bool write_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block); -static FLAC__bool write_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block); -static FLAC__bool write_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_StreamInfo *block); -static FLAC__bool write_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Padding *block, uint32_t block_length); -static FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Application *block, uint32_t block_length); -static FLAC__bool write_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_SeekTable *block); -static FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_VorbisComment *block); -static FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_CueSheet *block); -static FLAC__bool write_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Picture *block); -static FLAC__bool write_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Unknown *block, uint32_t block_length); - -static FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *iterator, const FLAC__StreamMetadata *block); -static FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, uint32_t padding_length, FLAC__bool padding_is_last); -static FLAC__bool rewrite_whole_file_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool append); - -static void simple_iterator_push_(FLAC__Metadata_SimpleIterator *iterator); -static FLAC__bool simple_iterator_pop_(FLAC__Metadata_SimpleIterator *iterator); - -static uint32_t seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb); -static uint32_t seek_to_first_metadata_block_(FILE *f); - -static FLAC__bool simple_iterator_copy_file_prefix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, FLAC__bool append); -static FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, FLAC__off_t fixup_is_last_flag_offset, FLAC__bool backup); - -static FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status); -static FLAC__bool copy_n_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status); -static FLAC__bool copy_remaining_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__Metadata_SimpleIteratorStatus *status); -static FLAC__bool copy_remaining_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__Metadata_SimpleIteratorStatus *status); - -static FLAC__bool open_tempfile_(const char *filename, const char *tempfile_path_prefix, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status); -static FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status); -static void cleanup_tempfile_(FILE **tempfile, char **tempfilename); - -static FLAC__bool get_file_stats_(const char *filename, struct flac_stat_s *stats); -static void set_file_stats_(const char *filename, struct flac_stat_s *stats); - -static int fseek_wrapper_(FLAC__IOHandle handle, FLAC__int64 offset, int whence); -static FLAC__int64 ftell_wrapper_(FLAC__IOHandle handle); - -static FLAC__Metadata_ChainStatus get_equivalent_status_(FLAC__Metadata_SimpleIteratorStatus status); - - -#ifdef FLAC__VALGRIND_TESTING -static size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) -{ - size_t ret = fwrite(ptr, size, nmemb, stream); - if(!ferror(stream)) - fflush(stream); - return ret; -} -#else -#define local__fwrite fwrite -#endif - -/**************************************************************************** - * - * Level 0 implementation - * - ***************************************************************************/ - -static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); -static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); -static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); - -typedef struct { - FLAC__bool got_error; - FLAC__StreamMetadata *object; -} level0_client_data; - -static FLAC__StreamMetadata *get_one_metadata_block_(const char *filename, FLAC__MetadataType type) -{ - level0_client_data cd; - FLAC__StreamDecoder *decoder; - - FLAC__ASSERT(0 != filename); - - cd.got_error = false; - cd.object = 0; - - decoder = FLAC__stream_decoder_new(); - - if(0 == decoder) - return 0; - - FLAC__stream_decoder_set_md5_checking(decoder, false); - FLAC__stream_decoder_set_metadata_ignore_all(decoder); - FLAC__stream_decoder_set_metadata_respond(decoder, type); - - if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, &cd) != FLAC__STREAM_DECODER_INIT_STATUS_OK || cd.got_error) { - (void)FLAC__stream_decoder_finish(decoder); - FLAC__stream_decoder_delete(decoder); - return 0; - } - - if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder) || cd.got_error) { - (void)FLAC__stream_decoder_finish(decoder); - FLAC__stream_decoder_delete(decoder); - if(0 != cd.object) - FLAC__metadata_object_delete(cd.object); - return 0; - } - - (void)FLAC__stream_decoder_finish(decoder); - FLAC__stream_decoder_delete(decoder); - - return cd.object; -} - -FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo) -{ - FLAC__StreamMetadata *object; - - FLAC__ASSERT(0 != filename); - FLAC__ASSERT(0 != streaminfo); - - object = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_STREAMINFO); - - if (object) { - /* can just copy the contents since STREAMINFO has no internal structure */ - *streaminfo = *object; - FLAC__metadata_object_delete(object); - return true; - } - else { - return false; - } -} - -FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMetadata **tags) -{ - FLAC__ASSERT(0 != filename); - FLAC__ASSERT(0 != tags); - - *tags = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_VORBIS_COMMENT); - - return 0 != *tags; -} - -FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__StreamMetadata **cuesheet) -{ - FLAC__ASSERT(0 != filename); - FLAC__ASSERT(0 != cuesheet); - - *cuesheet = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_CUESHEET); - - return 0 != *cuesheet; -} - -FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) -{ - (void)decoder, (void)frame, (void)buffer, (void)client_data; - - return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; -} - -void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) -{ - level0_client_data *cd = (level0_client_data *)client_data; - (void)decoder; - - /* - * we assume we only get here when the one metadata block we were - * looking for was passed to us - */ - if(!cd->got_error && 0 == cd->object) { - if(0 == (cd->object = FLAC__metadata_object_clone(metadata))) - cd->got_error = true; - } -} - -void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) -{ - level0_client_data *cd = (level0_client_data *)client_data; - (void)decoder; - - if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC) - cd->got_error = true; -} - -FLAC_API FLAC__bool FLAC__metadata_get_picture(const char *filename, FLAC__StreamMetadata **picture, FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, uint32_t max_width, uint32_t max_height, uint32_t max_depth, uint32_t max_colors) -{ - FLAC__Metadata_SimpleIterator *it; - FLAC__uint64 max_area_seen = 0; - FLAC__uint64 max_depth_seen = 0; - - FLAC__ASSERT(0 != filename); - FLAC__ASSERT(0 != picture); - - *picture = 0; - - it = FLAC__metadata_simple_iterator_new(); - if(0 == it) - return false; - if(!FLAC__metadata_simple_iterator_init(it, filename, /*read_only=*/true, /*preserve_file_stats=*/true)) { - FLAC__metadata_simple_iterator_delete(it); - return false; - } - do { - if(FLAC__metadata_simple_iterator_get_block_type(it) == FLAC__METADATA_TYPE_PICTURE) { - FLAC__StreamMetadata *obj = FLAC__metadata_simple_iterator_get_block(it); - FLAC__uint64 area = (FLAC__uint64)obj->data.picture.width * (FLAC__uint64)obj->data.picture.height; - /* check constraints */ - if( - (type == (FLAC__StreamMetadata_Picture_Type)(-1) || type == obj->data.picture.type) && - (mime_type == 0 || !strcmp(mime_type, obj->data.picture.mime_type)) && - (description == 0 || !strcmp((const char *)description, (const char *)obj->data.picture.description)) && - obj->data.picture.width <= max_width && - obj->data.picture.height <= max_height && - obj->data.picture.depth <= max_depth && - obj->data.picture.colors <= max_colors && - (area > max_area_seen || (area == max_area_seen && obj->data.picture.depth > max_depth_seen)) - ) { - if(*picture) - FLAC__metadata_object_delete(*picture); - *picture = obj; - max_area_seen = area; - max_depth_seen = obj->data.picture.depth; - } - else { - FLAC__metadata_object_delete(obj); - } - } - } while(FLAC__metadata_simple_iterator_next(it)); - - FLAC__metadata_simple_iterator_delete(it); - - return (0 != *picture); -} - - -/**************************************************************************** - * - * Level 1 implementation - * - ***************************************************************************/ - -#define SIMPLE_ITERATOR_MAX_PUSH_DEPTH (1+4) -/* 1 for initial offset, +4 for our own personal use */ - -struct FLAC__Metadata_SimpleIterator { - FILE *file; - char *filename, *tempfile_path_prefix; - struct flac_stat_s stats; - FLAC__bool has_stats; - FLAC__bool is_writable; - FLAC__Metadata_SimpleIteratorStatus status; - FLAC__off_t offset[SIMPLE_ITERATOR_MAX_PUSH_DEPTH]; - FLAC__off_t first_offset; /* this is the offset to the STREAMINFO block */ - uint32_t depth; - /* this is the metadata block header of the current block we are pointing to: */ - FLAC__bool is_last; - FLAC__MetadataType type; - uint32_t length; -}; - -FLAC_API const char * const FLAC__Metadata_SimpleIteratorStatusString[] = { - "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK", - "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT", - "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE", - "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE", - "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE", - "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA", - "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR", - "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR", - "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR", - "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR", - "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR", - "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR", - "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR" -}; - - -FLAC_API FLAC__Metadata_SimpleIterator *FLAC__metadata_simple_iterator_new(void) -{ - FLAC__Metadata_SimpleIterator *iterator = calloc(1, sizeof(FLAC__Metadata_SimpleIterator)); - - if(0 != iterator) { - iterator->file = 0; - iterator->filename = 0; - iterator->tempfile_path_prefix = 0; - iterator->has_stats = false; - iterator->is_writable = false; - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; - iterator->first_offset = iterator->offset[0] = -1; - iterator->depth = 0; - } - - return iterator; -} - -static void simple_iterator_free_guts_(FLAC__Metadata_SimpleIterator *iterator) -{ - FLAC__ASSERT(0 != iterator); - - if(0 != iterator->file) { - fclose(iterator->file); - iterator->file = 0; - if(iterator->has_stats) - set_file_stats_(iterator->filename, &iterator->stats); - } - if(0 != iterator->filename) { - free(iterator->filename); - iterator->filename = 0; - } - if(0 != iterator->tempfile_path_prefix) { - free(iterator->tempfile_path_prefix); - iterator->tempfile_path_prefix = 0; - } -} - -FLAC_API void FLAC__metadata_simple_iterator_delete(FLAC__Metadata_SimpleIterator *iterator) -{ - FLAC__ASSERT(0 != iterator); - - simple_iterator_free_guts_(iterator); - free(iterator); -} - -FLAC_API FLAC__Metadata_SimpleIteratorStatus FLAC__metadata_simple_iterator_status(FLAC__Metadata_SimpleIterator *iterator) -{ - FLAC__Metadata_SimpleIteratorStatus status; - - FLAC__ASSERT(0 != iterator); - - status = iterator->status; - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; - return status; -} - -static FLAC__bool simple_iterator_prime_input_(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool read_only) -{ - uint32_t ret; - - FLAC__ASSERT(0 != iterator); - - if(read_only || 0 == (iterator->file = flac_fopen(iterator->filename, "r+b"))) { - iterator->is_writable = false; - if(read_only || errno == EACCES) { - if(0 == (iterator->file = flac_fopen(iterator->filename, "rb"))) { - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE; - return false; - } - } - else { - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE; - return false; - } - } - else { - iterator->is_writable = true; - } - - ret = seek_to_first_metadata_block_(iterator->file); - switch(ret) { - case 0: - iterator->depth = 0; - iterator->first_offset = iterator->offset[iterator->depth] = ftello(iterator->file); - return read_metadata_block_header_(iterator); - case 1: - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - return false; - case 2: - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; - return false; - case 3: - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE; - return false; - default: - FLAC__ASSERT(0); - return false; - } -} - -#if 0 -@@@ If we decide to finish implementing this, put this comment back in metadata.h -/* - * The 'tempfile_path_prefix' allows you to specify a directory where - * tempfiles should go. Remember that if your metadata edits cause the - * FLAC file to grow, the entire file will have to be rewritten. If - * 'tempfile_path_prefix' is NULL, the temp file will be written in the - * same directory as the original FLAC file. This makes replacing the - * original with the tempfile fast but requires extra space in the same - * partition for the tempfile. If space is a problem, you can pass a - * directory name belonging to a different partition in - * 'tempfile_path_prefix'. Note that you should use the forward slash - * '/' as the directory separator. A trailing slash is not needed; it - * will be added automatically. - */ -FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool preserve_file_stats, const char *tempfile_path_prefix); -#endif - -FLAC_API FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool read_only, FLAC__bool preserve_file_stats) -{ - const char *tempfile_path_prefix = 0; /*@@@ search for comments near 'flac_rename(...)' for what it will take to finish implementing this */ - - FLAC__ASSERT(0 != iterator); - FLAC__ASSERT(0 != filename); - - simple_iterator_free_guts_(iterator); - - if(!read_only && preserve_file_stats) - iterator->has_stats = get_file_stats_(filename, &iterator->stats); - - if(0 == (iterator->filename = strdup(filename))) { - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; - return false; - } - if(0 != tempfile_path_prefix && 0 == (iterator->tempfile_path_prefix = strdup(tempfile_path_prefix))) { - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; - return false; - } - - return simple_iterator_prime_input_(iterator, read_only); -} - -FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_writable(const FLAC__Metadata_SimpleIterator *iterator) -{ - FLAC__ASSERT(0 != iterator); - FLAC__ASSERT(0 != iterator->file); - - return iterator->is_writable; -} - -FLAC_API FLAC__bool FLAC__metadata_simple_iterator_next(FLAC__Metadata_SimpleIterator *iterator) -{ - FLAC__ASSERT(0 != iterator); - FLAC__ASSERT(0 != iterator->file); - - if(iterator->is_last) - return false; - - if(0 != fseeko(iterator->file, iterator->length, SEEK_CUR)) { - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; - return false; - } - - iterator->offset[iterator->depth] = ftello(iterator->file); - - return read_metadata_block_header_(iterator); -} - -FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIterator *iterator) -{ - FLAC__off_t this_offset; - - FLAC__ASSERT(0 != iterator); - FLAC__ASSERT(0 != iterator->file); - - if(iterator->offset[iterator->depth] == iterator->first_offset) - return false; - - if(0 != fseeko(iterator->file, iterator->first_offset, SEEK_SET)) { - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; - return false; - } - this_offset = iterator->first_offset; - if(!read_metadata_block_header_(iterator)) - return false; - - /* we ignore any error from ftello() and catch it in fseeko() */ - while(ftello(iterator->file) + (FLAC__off_t)iterator->length < iterator->offset[iterator->depth]) { - if(0 != fseeko(iterator->file, iterator->length, SEEK_CUR)) { - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; - return false; - } - this_offset = ftello(iterator->file); - if(!read_metadata_block_header_(iterator)) - return false; - } - - iterator->offset[iterator->depth] = this_offset; - - return true; -} - -/*@@@@add to tests*/ -FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_last(const FLAC__Metadata_SimpleIterator *iterator) -{ - FLAC__ASSERT(0 != iterator); - FLAC__ASSERT(0 != iterator->file); - - return iterator->is_last; -} - -/*@@@@add to tests*/ -FLAC_API off_t FLAC__metadata_simple_iterator_get_block_offset(const FLAC__Metadata_SimpleIterator *iterator) -{ - FLAC__ASSERT(0 != iterator); - FLAC__ASSERT(0 != iterator->file); - - return iterator->offset[iterator->depth]; -} - -FLAC_API FLAC__MetadataType FLAC__metadata_simple_iterator_get_block_type(const FLAC__Metadata_SimpleIterator *iterator) -{ - FLAC__ASSERT(0 != iterator); - FLAC__ASSERT(0 != iterator->file); - - return iterator->type; -} - -/*@@@@add to tests*/ -FLAC_API uint32_t FLAC__metadata_simple_iterator_get_block_length(const FLAC__Metadata_SimpleIterator *iterator) -{ - FLAC__ASSERT(0 != iterator); - FLAC__ASSERT(0 != iterator->file); - - return iterator->length; -} - -/*@@@@add to tests*/ -FLAC_API FLAC__bool FLAC__metadata_simple_iterator_get_application_id(FLAC__Metadata_SimpleIterator *iterator, FLAC__byte *id) -{ - const uint32_t id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8; - - FLAC__ASSERT(0 != iterator); - FLAC__ASSERT(0 != iterator->file); - FLAC__ASSERT(0 != id); - - if(iterator->type != FLAC__METADATA_TYPE_APPLICATION) { - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT; - return false; - } - - if(fread(id, 1, id_bytes, iterator->file) != id_bytes) { - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - return false; - } - - /* back up */ - if(0 != fseeko(iterator->file, -((int)id_bytes), SEEK_CUR)) { - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; - return false; - } - - return true; -} - -FLAC_API FLAC__StreamMetadata *FLAC__metadata_simple_iterator_get_block(FLAC__Metadata_SimpleIterator *iterator) -{ - FLAC__StreamMetadata *block = FLAC__metadata_object_new(iterator->type); - - FLAC__ASSERT(0 != iterator); - FLAC__ASSERT(0 != iterator->file); - - if(0 != block) { - block->is_last = iterator->is_last; - block->length = iterator->length; - - if(!read_metadata_block_data_(iterator, block)) { - FLAC__metadata_object_delete(block); - return 0; - } - - /* back up to the beginning of the block data to stay consistent */ - if(0 != fseeko(iterator->file, iterator->offset[iterator->depth] + FLAC__STREAM_METADATA_HEADER_LENGTH, SEEK_SET)) { - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; - FLAC__metadata_object_delete(block); - return 0; - } - } - else - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; - - return block; -} - -FLAC_API FLAC__bool FLAC__metadata_simple_iterator_set_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding) -{ - FLAC__ASSERT_DECLARATION(FLAC__off_t debug_target_offset = iterator->offset[iterator->depth];) - FLAC__bool ret; - - FLAC__ASSERT(0 != iterator); - FLAC__ASSERT(0 != iterator->file); - FLAC__ASSERT(0 != block); - - if(!iterator->is_writable) { - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE; - return false; - } - - if(iterator->type == FLAC__METADATA_TYPE_STREAMINFO || block->type == FLAC__METADATA_TYPE_STREAMINFO) { - if(iterator->type != block->type) { - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT; - return false; - } - } - - block->is_last = iterator->is_last; - - if(iterator->length == block->length) - return write_metadata_block_stationary_(iterator, block); - else if(iterator->length > block->length) { - if(use_padding && iterator->length >= FLAC__STREAM_METADATA_HEADER_LENGTH + block->length) { - ret = write_metadata_block_stationary_with_padding_(iterator, block, iterator->length - FLAC__STREAM_METADATA_HEADER_LENGTH - block->length, block->is_last); - FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset); - FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH); - return ret; - } - else { - ret = rewrite_whole_file_(iterator, block, /*append=*/false); - FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset); - FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH); - return ret; - } - } - else /* iterator->length < block->length */ { - uint32_t padding_leftover = 0; - FLAC__bool padding_is_last = false; - if(use_padding) { - /* first see if we can even use padding */ - if(iterator->is_last) { - use_padding = false; - } - else { - const uint32_t extra_padding_bytes_required = block->length - iterator->length; - simple_iterator_push_(iterator); - if(!FLAC__metadata_simple_iterator_next(iterator)) { - (void)simple_iterator_pop_(iterator); - return false; - } - if(iterator->type != FLAC__METADATA_TYPE_PADDING) { - use_padding = false; - } - else { - if(FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length == extra_padding_bytes_required) { - padding_leftover = 0; - block->is_last = iterator->is_last; - } - else if(iterator->length < extra_padding_bytes_required) - use_padding = false; - else { - padding_leftover = FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length - extra_padding_bytes_required; - padding_is_last = iterator->is_last; - block->is_last = false; - } - } - if(!simple_iterator_pop_(iterator)) - return false; - } - } - if(use_padding) { - if(padding_leftover == 0) { - ret = write_metadata_block_stationary_(iterator, block); - FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset); - FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH); - return ret; - } - else { - FLAC__ASSERT(padding_leftover >= FLAC__STREAM_METADATA_HEADER_LENGTH); - ret = write_metadata_block_stationary_with_padding_(iterator, block, padding_leftover - FLAC__STREAM_METADATA_HEADER_LENGTH, padding_is_last); - FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset); - FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH); - return ret; - } - } - else { - ret = rewrite_whole_file_(iterator, block, /*append=*/false); - FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset); - FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH); - return ret; - } - } -} - -FLAC_API FLAC__bool FLAC__metadata_simple_iterator_insert_block_after(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding) -{ - uint32_t padding_leftover = 0; - FLAC__bool padding_is_last = false; - - FLAC__ASSERT_DECLARATION(FLAC__off_t debug_target_offset = iterator->offset[iterator->depth] + FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length;) - FLAC__bool ret; - - FLAC__ASSERT(0 != iterator); - FLAC__ASSERT(0 != iterator->file); - FLAC__ASSERT(0 != block); - - if(!iterator->is_writable) { - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE; - return false; - } - - if(block->type == FLAC__METADATA_TYPE_STREAMINFO) { - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT; - return false; - } - - block->is_last = iterator->is_last; - - if(use_padding) { - /* first see if we can even use padding */ - if(iterator->is_last) { - use_padding = false; - } - else { - simple_iterator_push_(iterator); - if(!FLAC__metadata_simple_iterator_next(iterator)) { - (void)simple_iterator_pop_(iterator); - return false; - } - if(iterator->type != FLAC__METADATA_TYPE_PADDING) { - use_padding = false; - } - else { - if(iterator->length == block->length) { - padding_leftover = 0; - block->is_last = iterator->is_last; - } - else if(iterator->length < FLAC__STREAM_METADATA_HEADER_LENGTH + block->length) - use_padding = false; - else { - padding_leftover = iterator->length - block->length; - padding_is_last = iterator->is_last; - block->is_last = false; - } - } - if(!simple_iterator_pop_(iterator)) - return false; - } - } - if(use_padding) { - /* move to the next block, which is suitable padding */ - if(!FLAC__metadata_simple_iterator_next(iterator)) - return false; - if(padding_leftover == 0) { - ret = write_metadata_block_stationary_(iterator, block); - FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset); - FLAC__ASSERT(ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH); - return ret; - } - else { - FLAC__ASSERT(padding_leftover >= FLAC__STREAM_METADATA_HEADER_LENGTH); - ret = write_metadata_block_stationary_with_padding_(iterator, block, padding_leftover - FLAC__STREAM_METADATA_HEADER_LENGTH, padding_is_last); - FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset); - FLAC__ASSERT(ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH); - return ret; - } - } - else { - ret = rewrite_whole_file_(iterator, block, /*append=*/true); - FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset); - FLAC__ASSERT(ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH); - return ret; - } -} - -FLAC_API FLAC__bool FLAC__metadata_simple_iterator_delete_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool use_padding) -{ - FLAC__ASSERT_DECLARATION(FLAC__off_t debug_target_offset = iterator->offset[iterator->depth];) - FLAC__bool ret; - - if(!iterator->is_writable) { - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE; - return false; - } - - if(iterator->type == FLAC__METADATA_TYPE_STREAMINFO) { - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT; - return false; - } - - if(use_padding) { - FLAC__StreamMetadata *padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING); - if(0 == padding) { - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; - return false; - } - padding->length = iterator->length; - if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false)) { - FLAC__metadata_object_delete(padding); - return false; - } - FLAC__metadata_object_delete(padding); - if(!FLAC__metadata_simple_iterator_prev(iterator)) - return false; - FLAC__ASSERT(iterator->offset[iterator->depth] + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length == debug_target_offset); - FLAC__ASSERT(ftello(iterator->file) + (FLAC__off_t)iterator->length == debug_target_offset); - return true; - } - else { - ret = rewrite_whole_file_(iterator, 0, /*append=*/false); - FLAC__ASSERT(iterator->offset[iterator->depth] + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length == debug_target_offset); - FLAC__ASSERT(ftello(iterator->file) + (FLAC__off_t)iterator->length == debug_target_offset); - return ret; - } -} - - - -/**************************************************************************** - * - * Level 2 implementation - * - ***************************************************************************/ - - -typedef struct FLAC__Metadata_Node { - FLAC__StreamMetadata *data; - struct FLAC__Metadata_Node *prev, *next; -} FLAC__Metadata_Node; - -struct FLAC__Metadata_Chain { - char *filename; /* will be NULL if using callbacks */ - FLAC__bool is_ogg; - FLAC__Metadata_Node *head; - FLAC__Metadata_Node *tail; - uint32_t nodes; - FLAC__Metadata_ChainStatus status; - FLAC__off_t first_offset, last_offset; - /* - * This is the length of the chain initially read from the FLAC file. - * it is used to compare against the current length to decide whether - * or not the whole file has to be rewritten. - */ - FLAC__off_t initial_length; - /* @@@ hacky, these are currently only needed by ogg reader */ - FLAC__IOHandle handle; - FLAC__IOCallback_Read read_cb; -}; - -struct FLAC__Metadata_Iterator { - FLAC__Metadata_Chain *chain; - FLAC__Metadata_Node *current; -}; - -FLAC_API const char * const FLAC__Metadata_ChainStatusString[] = { - "FLAC__METADATA_CHAIN_STATUS_OK", - "FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT", - "FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE", - "FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE", - "FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE", - "FLAC__METADATA_CHAIN_STATUS_BAD_METADATA", - "FLAC__METADATA_CHAIN_STATUS_READ_ERROR", - "FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR", - "FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR", - "FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR", - "FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR", - "FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR", - "FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR", - "FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS", - "FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", - "FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL" -}; - - -static FLAC__Metadata_Node *node_new_(void) -{ - return calloc(1, sizeof(FLAC__Metadata_Node)); -} - -static void node_delete_(FLAC__Metadata_Node *node) -{ - FLAC__ASSERT(0 != node); - if(0 != node->data) - FLAC__metadata_object_delete(node->data); - free(node); -} - -static void chain_init_(FLAC__Metadata_Chain *chain) -{ - FLAC__ASSERT(0 != chain); - - chain->filename = 0; - chain->is_ogg = false; - chain->head = chain->tail = 0; - chain->nodes = 0; - chain->status = FLAC__METADATA_CHAIN_STATUS_OK; - chain->initial_length = 0; - chain->read_cb = 0; -} - -static void chain_clear_(FLAC__Metadata_Chain *chain) -{ - FLAC__Metadata_Node *node, *next; - - FLAC__ASSERT(0 != chain); - - for(node = chain->head; node; ) { - next = node->next; - node_delete_(node); - node = next; - } - - if(0 != chain->filename) - free(chain->filename); - - chain_init_(chain); -} - -static void chain_append_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node) -{ - FLAC__ASSERT(0 != chain); - FLAC__ASSERT(0 != node); - FLAC__ASSERT(0 != node->data); - - node->next = node->prev = 0; - node->data->is_last = true; - if(0 != chain->tail) - chain->tail->data->is_last = false; - - if(0 == chain->head) - chain->head = node; - else { - FLAC__ASSERT(0 != chain->tail); - chain->tail->next = node; - node->prev = chain->tail; - } - chain->tail = node; - chain->nodes++; -} - -static void chain_remove_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node) -{ - FLAC__ASSERT(0 != chain); - FLAC__ASSERT(0 != node); - - if(node == chain->head) - chain->head = node->next; - else - node->prev->next = node->next; - - if(node == chain->tail) - chain->tail = node->prev; - else - node->next->prev = node->prev; - - if(0 != chain->tail) - chain->tail->data->is_last = true; - - chain->nodes--; -} - -static void chain_delete_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node) -{ - chain_remove_node_(chain, node); - node_delete_(node); -} - -static FLAC__off_t chain_calculate_length_(FLAC__Metadata_Chain *chain) -{ - const FLAC__Metadata_Node *node; - FLAC__off_t length = 0; - for(node = chain->head; node; node = node->next) - length += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length); - return length; -} - -static void iterator_insert_node_(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Node *node) -{ - FLAC__ASSERT(0 != node); - FLAC__ASSERT(0 != node->data); - FLAC__ASSERT(0 != iterator); - FLAC__ASSERT(0 != iterator->current); - FLAC__ASSERT(0 != iterator->chain); - FLAC__ASSERT(0 != iterator->chain->head); - FLAC__ASSERT(0 != iterator->chain->tail); - - node->data->is_last = false; - - node->prev = iterator->current->prev; - node->next = iterator->current; - - if(0 == node->prev) - iterator->chain->head = node; - else - node->prev->next = node; - - iterator->current->prev = node; - - iterator->chain->nodes++; -} - -static void iterator_insert_node_after_(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Node *node) -{ - FLAC__ASSERT(0 != node); - FLAC__ASSERT(0 != node->data); - FLAC__ASSERT(0 != iterator); - FLAC__ASSERT(0 != iterator->current); - FLAC__ASSERT(0 != iterator->chain); - FLAC__ASSERT(0 != iterator->chain->head); - FLAC__ASSERT(0 != iterator->chain->tail); - - iterator->current->data->is_last = false; - - node->prev = iterator->current; - node->next = iterator->current->next; - - if(0 == node->next) - iterator->chain->tail = node; - else - node->next->prev = node; - - node->prev->next = node; - - iterator->chain->tail->data->is_last = true; - - iterator->chain->nodes++; -} - -/* return true iff node and node->next are both padding */ -static FLAC__bool chain_merge_adjacent_padding_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node) -{ - if(node->data->type == FLAC__METADATA_TYPE_PADDING && 0 != node->next && node->next->data->type == FLAC__METADATA_TYPE_PADDING) { - const uint32_t growth = FLAC__STREAM_METADATA_HEADER_LENGTH + node->next->data->length; - node->data->length += growth; /* new block size can be greater than max metadata block size, but it'll be fixed later in chain_prepare_for_write_() */ - - chain_delete_node_(chain, node->next); - return true; - } - else - return false; -} - -/* Returns the new length of the chain, or 0 if there was an error. */ -/* WATCHOUT: This can get called multiple times before a write, so - * it should still work when this happens. - */ -/* WATCHOUT: Make sure to also update the logic in - * FLAC__metadata_chain_check_if_tempfile_needed() if the logic here changes. - */ -static FLAC__off_t chain_prepare_for_write_(FLAC__Metadata_Chain *chain, FLAC__bool use_padding) -{ - FLAC__off_t current_length = chain_calculate_length_(chain); - - if(use_padding) { - /* if the metadata shrank and the last block is padding, we just extend the last padding block */ - if(current_length < chain->initial_length && chain->tail->data->type == FLAC__METADATA_TYPE_PADDING) { - const FLAC__off_t delta = chain->initial_length - current_length; - chain->tail->data->length += delta; - current_length += delta; - FLAC__ASSERT(current_length == chain->initial_length); - } - /* if the metadata shrank more than 4 bytes then there's room to add another padding block */ - else if(current_length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH <= chain->initial_length) { - FLAC__StreamMetadata *padding; - FLAC__Metadata_Node *node; - if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING))) { - chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR; - return 0; - } - padding->length = chain->initial_length - (FLAC__STREAM_METADATA_HEADER_LENGTH + current_length); - if(0 == (node = node_new_())) { - FLAC__metadata_object_delete(padding); - chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR; - return 0; - } - node->data = padding; - chain_append_node_(chain, node); - current_length = chain_calculate_length_(chain); - FLAC__ASSERT(current_length == chain->initial_length); - } - /* if the metadata grew but the last block is padding, try cutting the padding to restore the original length so we don't have to rewrite the whole file */ - else if(current_length > chain->initial_length) { - const FLAC__off_t delta = current_length - chain->initial_length; - if(chain->tail->data->type == FLAC__METADATA_TYPE_PADDING) { - /* if the delta is exactly the size of the last padding block, remove the padding block */ - if((FLAC__off_t)chain->tail->data->length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH == delta) { - chain_delete_node_(chain, chain->tail); - current_length = chain_calculate_length_(chain); - FLAC__ASSERT(current_length == chain->initial_length); - } - /* if there is at least 'delta' bytes of padding, trim the padding down */ - else if((FLAC__off_t)chain->tail->data->length >= delta) { - chain->tail->data->length -= delta; - current_length -= delta; - FLAC__ASSERT(current_length == chain->initial_length); - } - } - } - } - - /* check sizes of all metadata blocks; reduce padding size if necessary */ - { - FLAC__Metadata_Node *node; - for (node = chain->head; node; node = node->next) { - if(node->data->length >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) { - if(node->data->type == FLAC__METADATA_TYPE_PADDING) { - node->data->length = (1u << FLAC__STREAM_METADATA_LENGTH_LEN) - 1; - current_length = chain_calculate_length_(chain); - } else { - chain->status = FLAC__METADATA_CHAIN_STATUS_BAD_METADATA; - return 0; - } - } - } - } - - return current_length; -} - -static FLAC__bool chain_read_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__IOCallback_Tell tell_cb) -{ - FLAC__Metadata_Node *node; - - FLAC__ASSERT(0 != chain); - - /* we assume we're already at the beginning of the file */ - - switch(seek_to_first_metadata_block_cb_(handle, read_cb, seek_cb)) { - case 0: - break; - case 1: - chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR; - return false; - case 2: - chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR; - return false; - case 3: - chain->status = FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE; - return false; - default: - FLAC__ASSERT(0); - return false; - } - - { - FLAC__int64 pos = tell_cb(handle); - if(pos < 0) { - chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR; - return false; - } - chain->first_offset = (FLAC__off_t)pos; - } - - { - FLAC__bool is_last; - FLAC__MetadataType type; - uint32_t length; - - do { - node = node_new_(); - if(0 == node) { - chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR; - return false; - } - - if(!read_metadata_block_header_cb_(handle, read_cb, &is_last, &type, &length)) { - node_delete_(node); - chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR; - return false; - } - - node->data = FLAC__metadata_object_new(type); - if(0 == node->data) { - node_delete_(node); - chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR; - return false; - } - - node->data->is_last = is_last; - node->data->length = length; - - chain->status = get_equivalent_status_(read_metadata_block_data_cb_(handle, read_cb, seek_cb, node->data)); - if(chain->status != FLAC__METADATA_CHAIN_STATUS_OK) { - node_delete_(node); - return false; - } - chain_append_node_(chain, node); - } while(!is_last); - } - - { - FLAC__int64 pos = tell_cb(handle); - if(pos < 0) { - chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR; - return false; - } - chain->last_offset = (FLAC__off_t)pos; - } - - chain->initial_length = chain_calculate_length_(chain); - - return true; -} - -static FLAC__StreamDecoderReadStatus chain_read_ogg_read_cb_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) -{ - FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data; - (void)decoder; - if(*bytes > 0 && chain->status == FLAC__METADATA_CHAIN_STATUS_OK) { - *bytes = chain->read_cb(buffer, sizeof(FLAC__byte), *bytes, chain->handle); - if(*bytes == 0) - return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; - else - return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; - } - else - return FLAC__STREAM_DECODER_READ_STATUS_ABORT; -} - -static FLAC__StreamDecoderWriteStatus chain_read_ogg_write_cb_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) -{ - (void)decoder, (void)frame, (void)buffer, (void)client_data; - return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; -} - -static void chain_read_ogg_metadata_cb_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) -{ - FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data; - FLAC__Metadata_Node *node; - - (void)decoder; - - node = node_new_(); - if(0 == node) { - chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR; - return; - } - - node->data = FLAC__metadata_object_clone(metadata); - if(0 == node->data) { - node_delete_(node); - chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR; - return; - } - - chain_append_node_(chain, node); -} - -static void chain_read_ogg_error_cb_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) -{ - FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data; - (void)decoder, (void)status; - chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@@ maybe needs better error code */ -} - -static FLAC__bool chain_read_ogg_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb) -{ - FLAC__StreamDecoder *decoder; - - FLAC__ASSERT(0 != chain); - - /* we assume we're already at the beginning of the file */ - - chain->handle = handle; - chain->read_cb = read_cb; - if(0 == (decoder = FLAC__stream_decoder_new())) { - chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR; - return false; - } - FLAC__stream_decoder_set_metadata_respond_all(decoder); - if(FLAC__stream_decoder_init_ogg_stream(decoder, chain_read_ogg_read_cb_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, chain_read_ogg_write_cb_, chain_read_ogg_metadata_cb_, chain_read_ogg_error_cb_, chain) != FLAC__STREAM_DECODER_INIT_STATUS_OK) { - FLAC__stream_decoder_delete(decoder); - chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@@ maybe needs better error code */ - return false; - } - - chain->first_offset = 0; /*@@@ wrong; will need to be set correctly to implement metadata writing for Ogg FLAC */ - - if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder)) - chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@@ maybe needs better error code */ - if(chain->status != FLAC__METADATA_CHAIN_STATUS_OK) { - FLAC__stream_decoder_delete(decoder); - return false; - } - - FLAC__stream_decoder_delete(decoder); - - chain->last_offset = 0; /*@@@ wrong; will need to be set correctly to implement metadata writing for Ogg FLAC */ - - chain->initial_length = chain_calculate_length_(chain); - - return true; -} - -static FLAC__bool chain_rewrite_metadata_in_place_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, FLAC__IOCallback_Seek seek_cb) -{ - FLAC__Metadata_Node *node; - - FLAC__ASSERT(0 != chain); - FLAC__ASSERT(0 != chain->head); - - if(0 != seek_cb(handle, chain->first_offset, SEEK_SET)) { - chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR; - return false; - } - - for(node = chain->head; node; node = node->next) { - if(!write_metadata_block_header_cb_(handle, write_cb, node->data)) { - chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR; - return false; - } - if(!write_metadata_block_data_cb_(handle, write_cb, node->data)) { - chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR; - return false; - } - } - - /*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/ - - chain->status = FLAC__METADATA_CHAIN_STATUS_OK; - return true; -} - -static FLAC__bool chain_rewrite_metadata_in_place_(FLAC__Metadata_Chain *chain) -{ - FILE *file; - FLAC__bool ret; - - FLAC__ASSERT(0 != chain->filename); - - if(0 == (file = flac_fopen(chain->filename, "r+b"))) { - chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE; - return false; - } - - /* chain_rewrite_metadata_in_place_cb_() sets chain->status for us */ - ret = chain_rewrite_metadata_in_place_cb_(chain, (FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, fseek_wrapper_); - - fclose(file); - - return ret; -} - -static FLAC__bool chain_rewrite_file_(FLAC__Metadata_Chain *chain, const char *tempfile_path_prefix) -{ - FILE *f, *tempfile = NULL; - char *tempfilename; - FLAC__Metadata_SimpleIteratorStatus status; - const FLAC__Metadata_Node *node; - - FLAC__ASSERT(0 != chain); - FLAC__ASSERT(0 != chain->filename); - FLAC__ASSERT(0 != chain->head); - - /* copy the file prefix (data up to first metadata block */ - if(0 == (f = flac_fopen(chain->filename, "rb"))) { - chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE; - return false; - } - if(!open_tempfile_(chain->filename, tempfile_path_prefix, &tempfile, &tempfilename, &status)) { - chain->status = get_equivalent_status_(status); - goto err; - } - if(!copy_n_bytes_from_file_(f, tempfile, chain->first_offset, &status)) { - chain->status = get_equivalent_status_(status); - goto err; - } - - /* write the metadata */ - for(node = chain->head; node; node = node->next) { - if(!write_metadata_block_header_(tempfile, &status, node->data)) { - chain->status = get_equivalent_status_(status); - goto err; - } - if(!write_metadata_block_data_(tempfile, &status, node->data)) { - chain->status = get_equivalent_status_(status); - goto err; - } - } - /*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/ - - /* copy the file postfix (everything after the metadata) */ - if(0 != fseeko(f, chain->last_offset, SEEK_SET)) { - chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR; - goto err; - } - if(!copy_remaining_bytes_from_file_(f, tempfile, &status)) { - chain->status = get_equivalent_status_(status); - goto err; - } - - /* move the tempfile on top of the original */ - (void)fclose(f); - if(!transport_tempfile_(chain->filename, &tempfile, &tempfilename, &status)) - return false; - - return true; - -err: - (void)fclose(f); - cleanup_tempfile_(&tempfile, &tempfilename); - return false; -} - -/* assumes 'handle' is already at beginning of file */ -static FLAC__bool chain_rewrite_file_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb) -{ - FLAC__Metadata_SimpleIteratorStatus status; - const FLAC__Metadata_Node *node; - - FLAC__ASSERT(0 != chain); - FLAC__ASSERT(0 == chain->filename); - FLAC__ASSERT(0 != chain->head); - - /* copy the file prefix (data up to first metadata block */ - if(!copy_n_bytes_from_file_cb_(handle, read_cb, temp_handle, temp_write_cb, chain->first_offset, &status)) { - chain->status = get_equivalent_status_(status); - return false; - } - - /* write the metadata */ - for(node = chain->head; node; node = node->next) { - if(!write_metadata_block_header_cb_(temp_handle, temp_write_cb, node->data)) { - chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR; - return false; - } - if(!write_metadata_block_data_cb_(temp_handle, temp_write_cb, node->data)) { - chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR; - return false; - } - } - /*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/ - - /* copy the file postfix (everything after the metadata) */ - if(0 != seek_cb(handle, chain->last_offset, SEEK_SET)) { - chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR; - return false; - } - if(!copy_remaining_bytes_from_file_cb_(handle, read_cb, eof_cb, temp_handle, temp_write_cb, &status)) { - chain->status = get_equivalent_status_(status); - return false; - } - - return true; -} - -FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new(void) -{ - FLAC__Metadata_Chain *chain = calloc(1, sizeof(FLAC__Metadata_Chain)); - - if(0 != chain) - chain_init_(chain); - - return chain; -} - -FLAC_API void FLAC__metadata_chain_delete(FLAC__Metadata_Chain *chain) -{ - FLAC__ASSERT(0 != chain); - - chain_clear_(chain); - - free(chain); -} - -FLAC_API FLAC__Metadata_ChainStatus FLAC__metadata_chain_status(FLAC__Metadata_Chain *chain) -{ - FLAC__Metadata_ChainStatus status; - - FLAC__ASSERT(0 != chain); - - status = chain->status; - chain->status = FLAC__METADATA_CHAIN_STATUS_OK; - return status; -} - -static FLAC__bool chain_read_(FLAC__Metadata_Chain *chain, const char *filename, FLAC__bool is_ogg) -{ - FILE *file; - FLAC__bool ret; - - FLAC__ASSERT(0 != chain); - FLAC__ASSERT(0 != filename); - - chain_clear_(chain); - - if(0 == (chain->filename = strdup(filename))) { - chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR; - return false; - } - - chain->is_ogg = is_ogg; - - if(0 == (file = flac_fopen(filename, "rb"))) { - chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE; - return false; - } - - /* the function also sets chain->status for us */ - ret = is_ogg? - chain_read_ogg_cb_(chain, file, (FLAC__IOCallback_Read)fread) : - chain_read_cb_(chain, file, (FLAC__IOCallback_Read)fread, fseek_wrapper_, ftell_wrapper_) - ; - - fclose(file); - - return ret; -} - -FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const char *filename) -{ - return chain_read_(chain, filename, /*is_ogg=*/false); -} - -/*@@@@add to tests*/ -FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg(FLAC__Metadata_Chain *chain, const char *filename) -{ - return chain_read_(chain, filename, /*is_ogg=*/true); -} - -static FLAC__bool chain_read_with_callbacks_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, FLAC__bool is_ogg) -{ - FLAC__bool ret; - - FLAC__ASSERT(0 != chain); - - chain_clear_(chain); - - if (0 == callbacks.read || 0 == callbacks.seek || 0 == callbacks.tell) { - chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS; - return false; - } - - chain->is_ogg = is_ogg; - - /* rewind */ - if(0 != callbacks.seek(handle, 0, SEEK_SET)) { - chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR; - return false; - } - - /* the function also sets chain->status for us */ - ret = is_ogg? - chain_read_ogg_cb_(chain, handle, callbacks.read) : - chain_read_cb_(chain, handle, callbacks.read, callbacks.seek, callbacks.tell) - ; - - return ret; -} - -FLAC_API FLAC__bool FLAC__metadata_chain_read_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks) -{ - return chain_read_with_callbacks_(chain, handle, callbacks, /*is_ogg=*/false); -} - -/*@@@@add to tests*/ -FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks) -{ - return chain_read_with_callbacks_(chain, handle, callbacks, /*is_ogg=*/true); -} - -typedef enum { - LBS_NONE = 0, - LBS_SIZE_CHANGED, - LBS_BLOCK_ADDED, - LBS_BLOCK_REMOVED -} LastBlockState; - -FLAC_API FLAC__bool FLAC__metadata_chain_check_if_tempfile_needed(FLAC__Metadata_Chain *chain, FLAC__bool use_padding) -{ - /* This does all the same checks that are in chain_prepare_for_write_() - * but doesn't actually alter the chain. Make sure to update the logic - * here if chain_prepare_for_write_() changes. - */ - FLAC__off_t current_length; - LastBlockState lbs_state = LBS_NONE; - uint32_t lbs_size = 0; - - FLAC__ASSERT(0 != chain); - - current_length = chain_calculate_length_(chain); - - if(use_padding) { - const FLAC__Metadata_Node * const node = chain->tail; - /* if the metadata shrank and the last block is padding, we just extend the last padding block */ - if(current_length < chain->initial_length && node->data->type == FLAC__METADATA_TYPE_PADDING) { - lbs_state = LBS_SIZE_CHANGED; - lbs_size = node->data->length + (chain->initial_length - current_length); - } - /* if the metadata shrank more than 4 bytes then there's room to add another padding block */ - else if(current_length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH <= chain->initial_length) { - lbs_state = LBS_BLOCK_ADDED; - lbs_size = chain->initial_length - (current_length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH); - } - /* if the metadata grew but the last block is padding, try cutting the padding to restore the original length so we don't have to rewrite the whole file */ - else if(current_length > chain->initial_length) { - const FLAC__off_t delta = current_length - chain->initial_length; - if(node->data->type == FLAC__METADATA_TYPE_PADDING) { - /* if the delta is exactly the size of the last padding block, remove the padding block */ - if((FLAC__off_t)node->data->length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH == delta) { - lbs_state = LBS_BLOCK_REMOVED; - lbs_size = 0; - } - /* if there is at least 'delta' bytes of padding, trim the padding down */ - else if((FLAC__off_t)node->data->length >= delta) { - lbs_state = LBS_SIZE_CHANGED; - lbs_size = node->data->length - delta; - } - } - } - } - - current_length = 0; - /* check sizes of all metadata blocks; reduce padding size if necessary */ - { - const FLAC__Metadata_Node *node; - for(node = chain->head; node; node = node->next) { - uint32_t block_len = node->data->length; - if(node == chain->tail) { - if(lbs_state == LBS_BLOCK_REMOVED) - continue; - else if(lbs_state == LBS_SIZE_CHANGED) - block_len = lbs_size; - } - if(block_len >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) { - if(node->data->type == FLAC__METADATA_TYPE_PADDING) - block_len = (1u << FLAC__STREAM_METADATA_LENGTH_LEN) - 1; - else - return false /* the return value doesn't matter */; - } - current_length += (FLAC__STREAM_METADATA_HEADER_LENGTH + block_len); - } - - if(lbs_state == LBS_BLOCK_ADDED) { - /* test added padding block */ - uint32_t block_len = lbs_size; - if(block_len >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) - block_len = (1u << FLAC__STREAM_METADATA_LENGTH_LEN) - 1; - current_length += (FLAC__STREAM_METADATA_HEADER_LENGTH + block_len); - } - } - - return (current_length != chain->initial_length); -} - -FLAC_API FLAC__bool FLAC__metadata_chain_write(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats) -{ - struct flac_stat_s stats; - const char *tempfile_path_prefix = 0; - FLAC__off_t current_length; - - FLAC__ASSERT(0 != chain); - - if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */ - chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; - return false; - } - - if (0 == chain->filename) { - chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH; - return false; - } - - current_length = chain_prepare_for_write_(chain, use_padding); - - /* a return value of 0 means there was an error; chain->status is already set */ - if (0 == current_length) - return false; - - if(preserve_file_stats) - get_file_stats_(chain->filename, &stats); - - if(current_length == chain->initial_length) { - if(!chain_rewrite_metadata_in_place_(chain)) - return false; - } - else { - if(!chain_rewrite_file_(chain, tempfile_path_prefix)) - return false; - - /* recompute lengths and offsets */ - { - const FLAC__Metadata_Node *node; - chain->initial_length = current_length; - chain->last_offset = chain->first_offset; - for(node = chain->head; node; node = node->next) - chain->last_offset += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length); - } - } - - if(preserve_file_stats) - set_file_stats_(chain->filename, &stats); - - return true; -} - -FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks) -{ - FLAC__off_t current_length; - - FLAC__ASSERT(0 != chain); - - if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */ - chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; - return false; - } - - if (0 != chain->filename) { - chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH; - return false; - } - - if (0 == callbacks.write || 0 == callbacks.seek) { - chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS; - return false; - } - - if (FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) { - chain->status = FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL; - return false; - } - - current_length = chain_prepare_for_write_(chain, use_padding); - - /* a return value of 0 means there was an error; chain->status is already set */ - if (0 == current_length) - return false; - - FLAC__ASSERT(current_length == chain->initial_length); - - return chain_rewrite_metadata_in_place_cb_(chain, handle, callbacks.write, callbacks.seek); -} - -FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks_and_tempfile(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, FLAC__IOHandle temp_handle, FLAC__IOCallbacks temp_callbacks) -{ - FLAC__off_t current_length; - - FLAC__ASSERT(0 != chain); - - if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */ - chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; - return false; - } - - if (0 != chain->filename) { - chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH; - return false; - } - - if (0 == callbacks.read || 0 == callbacks.seek || 0 == callbacks.eof) { - chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS; - return false; - } - if (0 == temp_callbacks.write) { - chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS; - return false; - } - - if (!FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) { - chain->status = FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL; - return false; - } - - current_length = chain_prepare_for_write_(chain, use_padding); - - /* a return value of 0 means there was an error; chain->status is already set */ - if (0 == current_length) - return false; - - FLAC__ASSERT(current_length != chain->initial_length); - - /* rewind */ - if(0 != callbacks.seek(handle, 0, SEEK_SET)) { - chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR; - return false; - } - - if(!chain_rewrite_file_cb_(chain, handle, callbacks.read, callbacks.seek, callbacks.eof, temp_handle, temp_callbacks.write)) - return false; - - /* recompute lengths and offsets */ - { - const FLAC__Metadata_Node *node; - chain->initial_length = current_length; - chain->last_offset = chain->first_offset; - for(node = chain->head; node; node = node->next) - chain->last_offset += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length); - } - - return true; -} - -FLAC_API void FLAC__metadata_chain_merge_padding(FLAC__Metadata_Chain *chain) -{ - FLAC__Metadata_Node *node; - - FLAC__ASSERT(0 != chain); - - for(node = chain->head; node; ) { - if(!chain_merge_adjacent_padding_(chain, node)) - node = node->next; - } -} - -FLAC_API void FLAC__metadata_chain_sort_padding(FLAC__Metadata_Chain *chain) -{ - FLAC__Metadata_Node *node, *save; - uint32_t i; - - FLAC__ASSERT(0 != chain); - - /* - * Don't try and be too smart... this simple algo is good enough for - * the small number of nodes that we deal with. - */ - for(i = 0, node = chain->head; i < chain->nodes; i++) { - if(node->data->type == FLAC__METADATA_TYPE_PADDING) { - save = node->next; - chain_remove_node_(chain, node); - chain_append_node_(chain, node); - node = save; - } - else { - node = node->next; - } - } - - FLAC__metadata_chain_merge_padding(chain); -} - - -FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new(void) -{ - FLAC__Metadata_Iterator *iterator = calloc(1, sizeof(FLAC__Metadata_Iterator)); - - /* calloc() implies: - iterator->current = 0; - iterator->chain = 0; - */ - - return iterator; -} - -FLAC_API void FLAC__metadata_iterator_delete(FLAC__Metadata_Iterator *iterator) -{ - FLAC__ASSERT(0 != iterator); - - free(iterator); -} - -FLAC_API void FLAC__metadata_iterator_init(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Chain *chain) -{ - FLAC__ASSERT(0 != iterator); - FLAC__ASSERT(0 != chain); - FLAC__ASSERT(0 != chain->head); - - iterator->chain = chain; - iterator->current = chain->head; -} - -FLAC_API FLAC__bool FLAC__metadata_iterator_next(FLAC__Metadata_Iterator *iterator) -{ - FLAC__ASSERT(0 != iterator); - - if(0 == iterator->current || 0 == iterator->current->next) - return false; - - iterator->current = iterator->current->next; - return true; -} - -FLAC_API FLAC__bool FLAC__metadata_iterator_prev(FLAC__Metadata_Iterator *iterator) -{ - FLAC__ASSERT(0 != iterator); - - if(0 == iterator->current || 0 == iterator->current->prev) - return false; - - iterator->current = iterator->current->prev; - return true; -} - -FLAC_API FLAC__MetadataType FLAC__metadata_iterator_get_block_type(const FLAC__Metadata_Iterator *iterator) -{ - FLAC__ASSERT(0 != iterator); - FLAC__ASSERT(0 != iterator->current); - FLAC__ASSERT(0 != iterator->current->data); - - return iterator->current->data->type; -} - -FLAC_API FLAC__StreamMetadata *FLAC__metadata_iterator_get_block(FLAC__Metadata_Iterator *iterator) -{ - FLAC__ASSERT(0 != iterator); - FLAC__ASSERT(0 != iterator->current); - - return iterator->current->data; -} - -FLAC_API FLAC__bool FLAC__metadata_iterator_set_block(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block) -{ - FLAC__ASSERT(0 != iterator); - FLAC__ASSERT(0 != block); - return FLAC__metadata_iterator_delete_block(iterator, false) && FLAC__metadata_iterator_insert_block_after(iterator, block); -} - -FLAC_API FLAC__bool FLAC__metadata_iterator_delete_block(FLAC__Metadata_Iterator *iterator, FLAC__bool replace_with_padding) -{ - FLAC__Metadata_Node *save; - - FLAC__ASSERT(0 != iterator); - FLAC__ASSERT(0 != iterator->current); - - if(0 == iterator->current->prev) { - FLAC__ASSERT(iterator->current->data->type == FLAC__METADATA_TYPE_STREAMINFO); - return false; - } - - save = iterator->current->prev; - - if(replace_with_padding) { - FLAC__metadata_object_delete_data(iterator->current->data); - iterator->current->data->type = FLAC__METADATA_TYPE_PADDING; - } - else { - chain_delete_node_(iterator->chain, iterator->current); - } - - iterator->current = save; - return true; -} - -FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_before(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block) -{ - FLAC__Metadata_Node *node; - - FLAC__ASSERT(0 != iterator); - FLAC__ASSERT(0 != iterator->current); - FLAC__ASSERT(0 != block); - - if(block->type == FLAC__METADATA_TYPE_STREAMINFO) - return false; - - if(0 == iterator->current->prev) { - FLAC__ASSERT(iterator->current->data->type == FLAC__METADATA_TYPE_STREAMINFO); - return false; - } - - if(0 == (node = node_new_())) - return false; - - node->data = block; - iterator_insert_node_(iterator, node); - iterator->current = node; - return true; -} - -FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_after(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block) -{ - FLAC__Metadata_Node *node; - - FLAC__ASSERT(0 != iterator); - FLAC__ASSERT(0 != iterator->current); - FLAC__ASSERT(0 != block); - - if(block->type == FLAC__METADATA_TYPE_STREAMINFO) - return false; - - if(0 == (node = node_new_())) - return false; - - node->data = block; - iterator_insert_node_after_(iterator, node); - iterator->current = node; - return true; -} - - -/**************************************************************************** - * - * Local function definitions - * - ***************************************************************************/ - -void pack_uint32_(FLAC__uint32 val, FLAC__byte *b, uint32_t bytes) -{ - uint32_t i; - - b += bytes; - - for(i = 0; i < bytes; i++) { - *(--b) = (FLAC__byte)(val & 0xff); - val >>= 8; - } -} - -void pack_uint32_little_endian_(FLAC__uint32 val, FLAC__byte *b, uint32_t bytes) -{ - uint32_t i; - - for(i = 0; i < bytes; i++) { - *(b++) = (FLAC__byte)(val & 0xff); - val >>= 8; - } -} - -void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, uint32_t bytes) -{ - uint32_t i; - - b += bytes; - - for(i = 0; i < bytes; i++) { - *(--b) = (FLAC__byte)(val & 0xff); - val >>= 8; - } -} - -FLAC__uint32 unpack_uint32_(FLAC__byte *b, uint32_t bytes) -{ - FLAC__uint32 ret = 0; - uint32_t i; - - for(i = 0; i < bytes; i++) - ret = (ret << 8) | (FLAC__uint32)(*b++); - - return ret; -} - -FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, uint32_t bytes) -{ - FLAC__uint32 ret = 0; - uint32_t i; - - b += bytes; - - for(i = 0; i < bytes; i++) - ret = (ret << 8) | (FLAC__uint32)(*--b); - - return ret; -} - -FLAC__uint64 unpack_uint64_(FLAC__byte *b, uint32_t bytes) -{ - FLAC__uint64 ret = 0; - uint32_t i; - - for(i = 0; i < bytes; i++) - ret = (ret << 8) | (FLAC__uint64)(*b++); - - return ret; -} - -FLAC__bool read_metadata_block_header_(FLAC__Metadata_SimpleIterator *iterator) -{ - FLAC__ASSERT(0 != iterator); - FLAC__ASSERT(0 != iterator->file); - - if(!read_metadata_block_header_cb_((FLAC__IOHandle)iterator->file, (FLAC__IOCallback_Read)fread, &iterator->is_last, &iterator->type, &iterator->length)) { - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - return false; - } - - return true; -} - -FLAC__bool read_metadata_block_data_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block) -{ - FLAC__ASSERT(0 != iterator); - FLAC__ASSERT(0 != iterator->file); - - iterator->status = read_metadata_block_data_cb_((FLAC__IOHandle)iterator->file, (FLAC__IOCallback_Read)fread, fseek_wrapper_, block); - - return (iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK); -} - -FLAC__bool read_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__bool *is_last, FLAC__MetadataType *type, uint32_t *length) -{ - FLAC__byte raw_header[FLAC__STREAM_METADATA_HEADER_LENGTH]; - - if(read_cb(raw_header, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, handle) != FLAC__STREAM_METADATA_HEADER_LENGTH) - return false; - - *is_last = raw_header[0] & 0x80? true : false; - *type = (FLAC__MetadataType)(raw_header[0] & 0x7f); - *length = unpack_uint32_(raw_header + 1, 3); - - /* Note that we don't check: - * if(iterator->type >= FLAC__METADATA_TYPE_UNDEFINED) - * we just will read in an opaque block - */ - - return true; -} - -FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata *block) -{ - switch(block->type) { - case FLAC__METADATA_TYPE_STREAMINFO: - return read_metadata_block_data_streaminfo_cb_(handle, read_cb, &block->data.stream_info); - case FLAC__METADATA_TYPE_PADDING: - return read_metadata_block_data_padding_cb_(handle, seek_cb, &block->data.padding, block->length); - case FLAC__METADATA_TYPE_APPLICATION: - return read_metadata_block_data_application_cb_(handle, read_cb, &block->data.application, block->length); - case FLAC__METADATA_TYPE_SEEKTABLE: - return read_metadata_block_data_seektable_cb_(handle, read_cb, &block->data.seek_table, block->length); - case FLAC__METADATA_TYPE_VORBIS_COMMENT: - return read_metadata_block_data_vorbis_comment_cb_(handle, read_cb, seek_cb, &block->data.vorbis_comment, block->length); - case FLAC__METADATA_TYPE_CUESHEET: - return read_metadata_block_data_cuesheet_cb_(handle, read_cb, &block->data.cue_sheet); - case FLAC__METADATA_TYPE_PICTURE: - return read_metadata_block_data_picture_cb_(handle, read_cb, &block->data.picture); - default: - return read_metadata_block_data_unknown_cb_(handle, read_cb, &block->data.unknown, block->length); - } -} - -FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_StreamInfo *block) -{ - FLAC__byte buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH], *b; - - if(read_cb(buffer, 1, FLAC__STREAM_METADATA_STREAMINFO_LENGTH, handle) != FLAC__STREAM_METADATA_STREAMINFO_LENGTH) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - - b = buffer; - - /* we are using hardcoded numbers for simplicity but we should - * probably eventually write a bit-level unpacker and use the - * _STREAMINFO_ constants. - */ - block->min_blocksize = unpack_uint32_(b, 2); b += 2; - block->max_blocksize = unpack_uint32_(b, 2); b += 2; - block->min_framesize = unpack_uint32_(b, 3); b += 3; - block->max_framesize = unpack_uint32_(b, 3); b += 3; - block->sample_rate = (unpack_uint32_(b, 2) << 4) | ((uint32_t)(b[2] & 0xf0) >> 4); - block->channels = (uint32_t)((b[2] & 0x0e) >> 1) + 1; - block->bits_per_sample = ((((uint32_t)(b[2] & 0x01)) << 4) | (((uint32_t)(b[3] & 0xf0)) >> 4)) + 1; - block->total_samples = (((FLAC__uint64)(b[3] & 0x0f)) << 32) | unpack_uint64_(b+4, 4); - memcpy(block->md5sum, b+8, 16); - - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; -} - -FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_Padding *block, uint32_t block_length) -{ - (void)block; /* nothing to do; we don't care about reading the padding bytes */ - - if(0 != seek_cb(handle, block_length, SEEK_CUR)) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; - - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; -} - -FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Application *block, uint32_t block_length) -{ - const uint32_t id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8; - - if(read_cb(block->id, 1, id_bytes, handle) != id_bytes) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - - if(block_length < id_bytes) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - - block_length -= id_bytes; - - if(block_length == 0) { - block->data = 0; - } - else { - if(0 == (block->data = malloc(block_length))) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; - - if(read_cb(block->data, 1, block_length, handle) != block_length) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - } - - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; -} - -FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_SeekTable *block, uint32_t block_length) -{ - uint32_t i; - FLAC__byte buffer[FLAC__STREAM_METADATA_SEEKPOINT_LENGTH]; - - FLAC__ASSERT(block_length % FLAC__STREAM_METADATA_SEEKPOINT_LENGTH == 0); - - block->num_points = block_length / FLAC__STREAM_METADATA_SEEKPOINT_LENGTH; - - if(block->num_points == 0) - block->points = 0; - else if(0 == (block->points = safe_malloc_mul_2op_p(block->num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint)))) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; - - for(i = 0; i < block->num_points; i++) { - if(read_cb(buffer, 1, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH, handle) != FLAC__STREAM_METADATA_SEEKPOINT_LENGTH) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - /* some MAGIC NUMBERs here */ - block->points[i].sample_number = unpack_uint64_(buffer, 8); - block->points[i].stream_offset = unpack_uint64_(buffer+8, 8); - block->points[i].frame_samples = unpack_uint32_(buffer+16, 2); - } - - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; -} - -FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entry_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment_Entry *entry, uint32_t max_length) -{ - const uint32_t entry_length_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8; - FLAC__byte buffer[4]; /* magic number is asserted below */ - - FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8 == sizeof(buffer)); - - if(max_length < entry_length_len) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA; - - max_length -= entry_length_len; - if(read_cb(buffer, 1, entry_length_len, handle) != entry_length_len) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - entry->length = unpack_uint32_little_endian_(buffer, entry_length_len); - if(max_length < entry->length) { - entry->length = 0; - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA; - } else max_length -= entry->length; - - if(0 != entry->entry) - free(entry->entry); - - if(entry->length == 0) { - entry->entry = 0; - } - else { - if(0 == (entry->entry = safe_malloc_add_2op_(entry->length, /*+*/1))) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; - - if(read_cb(entry->entry, 1, entry->length, handle) != entry->length) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - - entry->entry[entry->length] = '\0'; - } - - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; -} - -FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_VorbisComment *block, uint32_t block_length) -{ - uint32_t i; - FLAC__Metadata_SimpleIteratorStatus status; - const uint32_t num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8; - FLAC__byte buffer[4]; /* magic number is asserted below */ - - FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8 == sizeof(buffer)); - - status = read_metadata_block_data_vorbis_comment_entry_cb_(handle, read_cb, &(block->vendor_string), block_length); - if(block_length >= 4) - block_length -= 4; - if(status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA) - goto skip; - else if(status != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK) - return status; - block_length -= block->vendor_string.length; - - if(block_length < num_comments_len) goto skip; else block_length -= num_comments_len; - if(read_cb(buffer, 1, num_comments_len, handle) != num_comments_len) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - block->num_comments = unpack_uint32_little_endian_(buffer, num_comments_len); - - if(block->num_comments == 0) { - block->comments = 0; - } - else if(0 == (block->comments = calloc(block->num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry)))) { - block->num_comments = 0; - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; - } - - for(i = 0; i < block->num_comments; i++) { - status = read_metadata_block_data_vorbis_comment_entry_cb_(handle, read_cb, block->comments + i, block_length); - if(block_length >= 4) block_length -= 4; - if(status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA) { - block->num_comments = i; - goto skip; - } - else if(status != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK) return status; - block_length -= block->comments[i].length; - } - - skip: - if(block_length > 0) { - /* bad metadata */ - if(0 != seek_cb(handle, block_length, SEEK_CUR)) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; - } - - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; -} - -FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_track_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet_Track *track) -{ - uint32_t i, len; - FLAC__byte buffer[32]; /* asserted below that this is big enough */ - - FLAC__ASSERT(sizeof(buffer) >= sizeof(FLAC__uint64)); - FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN/8); - FLAC__ASSERT(sizeof(buffer) >= (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8); - - FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN % 8 == 0); - len = FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN / 8; - if(read_cb(buffer, 1, len, handle) != len) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - track->offset = unpack_uint64_(buffer, len); - - FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN % 8 == 0); - len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN / 8; - if(read_cb(buffer, 1, len, handle) != len) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - track->number = (FLAC__byte)unpack_uint32_(buffer, len); - - FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0); - len = FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN / 8; - if(read_cb(track->isrc, 1, len, handle) != len) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - - FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) % 8 == 0); - len = (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8; - if(read_cb(buffer, 1, len, handle) != len) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN == 1); - FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN == 1); - track->type = buffer[0] >> 7; - track->pre_emphasis = (buffer[0] >> 6) & 1; - - FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN % 8 == 0); - len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN / 8; - if(read_cb(buffer, 1, len, handle) != len) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - track->num_indices = (FLAC__byte)unpack_uint32_(buffer, len); - - if(track->num_indices == 0) { - track->indices = 0; - } - else if(0 == (track->indices = calloc(track->num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index)))) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; - - for(i = 0; i < track->num_indices; i++) { - FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN % 8 == 0); - len = FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN / 8; - if(read_cb(buffer, 1, len, handle) != len) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - track->indices[i].offset = unpack_uint64_(buffer, len); - - FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN % 8 == 0); - len = FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN / 8; - if(read_cb(buffer, 1, len, handle) != len) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - track->indices[i].number = (FLAC__byte)unpack_uint32_(buffer, len); - - FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN % 8 == 0); - len = FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN / 8; - if(read_cb(buffer, 1, len, handle) != len) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - } - - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; -} - -FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet *block) -{ - uint32_t i, len; - FLAC__Metadata_SimpleIteratorStatus status; - FLAC__byte buffer[1024]; /* MSVC needs a constant expression so we put a magic number and assert */ - - FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN)/8 <= sizeof(buffer)); - FLAC__ASSERT(sizeof(FLAC__uint64) <= sizeof(buffer)); - - FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0); - len = FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN / 8; - if(read_cb(block->media_catalog_number, 1, len, handle) != len) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - - FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN % 8 == 0); - len = FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN / 8; - if(read_cb(buffer, 1, len, handle) != len) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - block->lead_in = unpack_uint64_(buffer, len); - - FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) % 8 == 0); - len = (FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) / 8; - if(read_cb(buffer, 1, len, handle) != len) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - block->is_cd = buffer[0]&0x80? true : false; - - FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN % 8 == 0); - len = FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN / 8; - if(read_cb(buffer, 1, len, handle) != len) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - block->num_tracks = unpack_uint32_(buffer, len); - - if(block->num_tracks == 0) { - block->tracks = 0; - } - else if(0 == (block->tracks = calloc(block->num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track)))) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; - - for(i = 0; i < block->num_tracks; i++) { - if(FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK != (status = read_metadata_block_data_cuesheet_track_cb_(handle, read_cb, block->tracks + i))) - return status; - } - - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; -} - -static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cstring_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__byte **data, FLAC__uint32 *length, FLAC__uint32 length_len) -{ - FLAC__byte buffer[sizeof(FLAC__uint32)]; - - FLAC__ASSERT(0 != data); - FLAC__ASSERT(length_len%8 == 0); - - length_len /= 8; /* convert to bytes */ - - FLAC__ASSERT(sizeof(buffer) >= length_len); - - if(read_cb(buffer, 1, length_len, handle) != length_len) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - *length = unpack_uint32_(buffer, length_len); - - if(0 != *data) - free(*data); - - if(0 == (*data = safe_malloc_add_2op_(*length, /*+*/1))) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; - - if(*length > 0) { - if(read_cb(*data, 1, *length, handle) != *length) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - } - - (*data)[*length] = '\0'; - - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; -} - -FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Picture *block) -{ - FLAC__Metadata_SimpleIteratorStatus status; - FLAC__byte buffer[4]; /* asserted below that this is big enough */ - FLAC__uint32 len; - - FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8); - FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8); - FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8); - FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8); - FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_COLORS_LEN/8); - - FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_TYPE_LEN % 8 == 0); - len = FLAC__STREAM_METADATA_PICTURE_TYPE_LEN / 8; - if(read_cb(buffer, 1, len, handle) != len) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - block->type = (FLAC__StreamMetadata_Picture_Type)unpack_uint32_(buffer, len); - - if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, (FLAC__byte**)(&(block->mime_type)), &len, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK) - return status; - - if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, &(block->description), &len, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK) - return status; - - FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN % 8 == 0); - len = FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN / 8; - if(read_cb(buffer, 1, len, handle) != len) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - block->width = unpack_uint32_(buffer, len); - - FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN % 8 == 0); - len = FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN / 8; - if(read_cb(buffer, 1, len, handle) != len) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - block->height = unpack_uint32_(buffer, len); - - FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN % 8 == 0); - len = FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN / 8; - if(read_cb(buffer, 1, len, handle) != len) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - block->depth = unpack_uint32_(buffer, len); - - FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_COLORS_LEN % 8 == 0); - len = FLAC__STREAM_METADATA_PICTURE_COLORS_LEN / 8; - if(read_cb(buffer, 1, len, handle) != len) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - block->colors = unpack_uint32_(buffer, len); - - /* for convenience we use read_metadata_block_data_picture_cstring_cb_() even though it adds an extra terminating NUL we don't use */ - if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, &(block->data), &(block->data_length), FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK) - return status; - - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; -} - -FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Unknown *block, uint32_t block_length) -{ - if(block_length == 0) { - block->data = 0; - } - else { - if(0 == (block->data = malloc(block_length))) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; - - if(read_cb(block->data, 1, block_length, handle) != block_length) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - } - - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; -} - -FLAC__bool write_metadata_block_header_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block) -{ - FLAC__ASSERT(0 != file); - FLAC__ASSERT(0 != status); - - if(!write_metadata_block_header_cb_((FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, block)) { - *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR; - return false; - } - - return true; -} - -FLAC__bool write_metadata_block_data_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block) -{ - FLAC__ASSERT(0 != file); - FLAC__ASSERT(0 != status); - - if (write_metadata_block_data_cb_((FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, block)) { - *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; - return true; - } - else { - *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR; - return false; - } -} - -FLAC__bool write_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block) -{ - FLAC__byte buffer[FLAC__STREAM_METADATA_HEADER_LENGTH]; - - FLAC__ASSERT(block->length < (1u << FLAC__STREAM_METADATA_LENGTH_LEN)); - /* double protection */ - if(block->length >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) - return false; - - buffer[0] = (block->is_last? 0x80 : 0) | (FLAC__byte)block->type; - pack_uint32_(block->length, buffer + 1, 3); - - if(write_cb(buffer, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, handle) != FLAC__STREAM_METADATA_HEADER_LENGTH) - return false; - - return true; -} - -FLAC__bool write_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block) -{ - FLAC__ASSERT(0 != block); - - switch(block->type) { - case FLAC__METADATA_TYPE_STREAMINFO: - return write_metadata_block_data_streaminfo_cb_(handle, write_cb, &block->data.stream_info); - case FLAC__METADATA_TYPE_PADDING: - return write_metadata_block_data_padding_cb_(handle, write_cb, &block->data.padding, block->length); - case FLAC__METADATA_TYPE_APPLICATION: - return write_metadata_block_data_application_cb_(handle, write_cb, &block->data.application, block->length); - case FLAC__METADATA_TYPE_SEEKTABLE: - return write_metadata_block_data_seektable_cb_(handle, write_cb, &block->data.seek_table); - case FLAC__METADATA_TYPE_VORBIS_COMMENT: - return write_metadata_block_data_vorbis_comment_cb_(handle, write_cb, &block->data.vorbis_comment); - case FLAC__METADATA_TYPE_CUESHEET: - return write_metadata_block_data_cuesheet_cb_(handle, write_cb, &block->data.cue_sheet); - case FLAC__METADATA_TYPE_PICTURE: - return write_metadata_block_data_picture_cb_(handle, write_cb, &block->data.picture); - default: - return write_metadata_block_data_unknown_cb_(handle, write_cb, &block->data.unknown, block->length); - } -} - -FLAC__bool write_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_StreamInfo *block) -{ - FLAC__byte buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH]; - const uint32_t channels1 = block->channels - 1; - const uint32_t bps1 = block->bits_per_sample - 1; - - /* we are using hardcoded numbers for simplicity but we should - * probably eventually write a bit-level packer and use the - * _STREAMINFO_ constants. - */ - pack_uint32_(block->min_blocksize, buffer, 2); - pack_uint32_(block->max_blocksize, buffer+2, 2); - pack_uint32_(block->min_framesize, buffer+4, 3); - pack_uint32_(block->max_framesize, buffer+7, 3); - buffer[10] = (block->sample_rate >> 12) & 0xff; - buffer[11] = (block->sample_rate >> 4) & 0xff; - buffer[12] = ((block->sample_rate & 0x0f) << 4) | (channels1 << 1) | (bps1 >> 4); - buffer[13] = (FLAC__byte)(((bps1 & 0x0f) << 4) | ((block->total_samples >> 32) & 0x0f)); - pack_uint32_((FLAC__uint32)block->total_samples, buffer+14, 4); - memcpy(buffer+18, block->md5sum, 16); - - if(write_cb(buffer, 1, FLAC__STREAM_METADATA_STREAMINFO_LENGTH, handle) != FLAC__STREAM_METADATA_STREAMINFO_LENGTH) - return false; - - return true; -} - -FLAC__bool write_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Padding *block, uint32_t block_length) -{ - uint32_t i, n = block_length; - FLAC__byte buffer[1024]; - - (void)block; - - memset(buffer, 0, 1024); - - for(i = 0; i < n/1024; i++) - if(write_cb(buffer, 1, 1024, handle) != 1024) - return false; - - n %= 1024; - - if(write_cb(buffer, 1, n, handle) != n) - return false; - - return true; -} - -FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Application *block, uint32_t block_length) -{ - const uint32_t id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8; - - if(write_cb(block->id, 1, id_bytes, handle) != id_bytes) - return false; - - block_length -= id_bytes; - - if(write_cb(block->data, 1, block_length, handle) != block_length) - return false; - - return true; -} - -FLAC__bool write_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_SeekTable *block) -{ - uint32_t i; - FLAC__byte buffer[FLAC__STREAM_METADATA_SEEKPOINT_LENGTH]; - - for(i = 0; i < block->num_points; i++) { - /* some MAGIC NUMBERs here */ - pack_uint64_(block->points[i].sample_number, buffer, 8); - pack_uint64_(block->points[i].stream_offset, buffer+8, 8); - pack_uint32_(block->points[i].frame_samples, buffer+16, 2); - if(write_cb(buffer, 1, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH, handle) != FLAC__STREAM_METADATA_SEEKPOINT_LENGTH) - return false; - } - - return true; -} - -FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_VorbisComment *block) -{ - uint32_t i; - const uint32_t entry_length_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8; - const uint32_t num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8; - FLAC__byte buffer[4]; /* magic number is asserted below */ - - FLAC__ASSERT(flac_max(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN, FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8 == sizeof(buffer)); - - pack_uint32_little_endian_(block->vendor_string.length, buffer, entry_length_len); - if(write_cb(buffer, 1, entry_length_len, handle) != entry_length_len) - return false; - if(write_cb(block->vendor_string.entry, 1, block->vendor_string.length, handle) != block->vendor_string.length) - return false; - - pack_uint32_little_endian_(block->num_comments, buffer, num_comments_len); - if(write_cb(buffer, 1, num_comments_len, handle) != num_comments_len) - return false; - - for(i = 0; i < block->num_comments; i++) { - pack_uint32_little_endian_(block->comments[i].length, buffer, entry_length_len); - if(write_cb(buffer, 1, entry_length_len, handle) != entry_length_len) - return false; - if(write_cb(block->comments[i].entry, 1, block->comments[i].length, handle) != block->comments[i].length) - return false; - } - - return true; -} - -FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_CueSheet *block) -{ - uint32_t i, j, len; - FLAC__byte buffer[1024]; /* asserted below that this is big enough */ - - FLAC__ASSERT(sizeof(buffer) >= sizeof(FLAC__uint64)); - FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN/8); - FLAC__ASSERT(sizeof(buffer) >= (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN)/8); - FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN/8); - - FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0); - len = FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN / 8; - if(write_cb(block->media_catalog_number, 1, len, handle) != len) - return false; - - FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN % 8 == 0); - len = FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN / 8; - pack_uint64_(block->lead_in, buffer, len); - if(write_cb(buffer, 1, len, handle) != len) - return false; - - FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) % 8 == 0); - len = (FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) / 8; - memset(buffer, 0, len); - if(block->is_cd) - buffer[0] |= 0x80; - if(write_cb(buffer, 1, len, handle) != len) - return false; - - FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN % 8 == 0); - len = FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN / 8; - pack_uint32_(block->num_tracks, buffer, len); - if(write_cb(buffer, 1, len, handle) != len) - return false; - - for(i = 0; i < block->num_tracks; i++) { - FLAC__StreamMetadata_CueSheet_Track *track = block->tracks + i; - - FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN % 8 == 0); - len = FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN / 8; - pack_uint64_(track->offset, buffer, len); - if(write_cb(buffer, 1, len, handle) != len) - return false; - - FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN % 8 == 0); - len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN / 8; - pack_uint32_(track->number, buffer, len); - if(write_cb(buffer, 1, len, handle) != len) - return false; - - FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0); - len = FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN / 8; - if(write_cb(track->isrc, 1, len, handle) != len) - return false; - - FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) % 8 == 0); - len = (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8; - memset(buffer, 0, len); - buffer[0] = (track->type << 7) | (track->pre_emphasis << 6); - if(write_cb(buffer, 1, len, handle) != len) - return false; - - FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN % 8 == 0); - len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN / 8; - pack_uint32_(track->num_indices, buffer, len); - if(write_cb(buffer, 1, len, handle) != len) - return false; - - for(j = 0; j < track->num_indices; j++) { - FLAC__StreamMetadata_CueSheet_Index *indx = track->indices + j; - - FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN % 8 == 0); - len = FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN / 8; - pack_uint64_(indx->offset, buffer, len); - if(write_cb(buffer, 1, len, handle) != len) - return false; - - FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN % 8 == 0); - len = FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN / 8; - pack_uint32_(indx->number, buffer, len); - if(write_cb(buffer, 1, len, handle) != len) - return false; - - FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN % 8 == 0); - len = FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN / 8; - memset(buffer, 0, len); - if(write_cb(buffer, 1, len, handle) != len) - return false; - } - } - - return true; -} - -FLAC__bool write_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Picture *block) -{ - uint32_t len; - size_t slen; - FLAC__byte buffer[4]; /* magic number is asserted below */ - - FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_TYPE_LEN%8); - FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN%8); - FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN%8); - FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN%8); - FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN%8); - FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN%8); - FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_COLORS_LEN%8); - FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN%8); - FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8); - FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN/8); - FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN/8); - FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8); - FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8); - FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8); - FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_COLORS_LEN/8); - FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN/8); - - len = FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8; - pack_uint32_(block->type, buffer, len); - if(write_cb(buffer, 1, len, handle) != len) - return false; - - len = FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN/8; - slen = strlen(block->mime_type); - pack_uint32_(slen, buffer, len); - if(write_cb(buffer, 1, len, handle) != len) - return false; - if(write_cb(block->mime_type, 1, slen, handle) != slen) - return false; - - len = FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN/8; - slen = strlen((const char *)block->description); - pack_uint32_(slen, buffer, len); - if(write_cb(buffer, 1, len, handle) != len) - return false; - if(write_cb(block->description, 1, slen, handle) != slen) - return false; - - len = FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8; - pack_uint32_(block->width, buffer, len); - if(write_cb(buffer, 1, len, handle) != len) - return false; - - len = FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8; - pack_uint32_(block->height, buffer, len); - if(write_cb(buffer, 1, len, handle) != len) - return false; - - len = FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8; - pack_uint32_(block->depth, buffer, len); - if(write_cb(buffer, 1, len, handle) != len) - return false; - - len = FLAC__STREAM_METADATA_PICTURE_COLORS_LEN/8; - pack_uint32_(block->colors, buffer, len); - if(write_cb(buffer, 1, len, handle) != len) - return false; - - len = FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN/8; - pack_uint32_(block->data_length, buffer, len); - if(write_cb(buffer, 1, len, handle) != len) - return false; - if(write_cb(block->data, 1, block->data_length, handle) != block->data_length) - return false; - - return true; -} - -FLAC__bool write_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Unknown *block, uint32_t block_length) -{ - if(write_cb(block->data, 1, block_length, handle) != block_length) - return false; - - return true; -} - -FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *iterator, const FLAC__StreamMetadata *block) -{ - if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) { - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; - return false; - } - - if(!write_metadata_block_header_(iterator->file, &iterator->status, block)) - return false; - - if(!write_metadata_block_data_(iterator->file, &iterator->status, block)) - return false; - - if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) { - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; - return false; - } - - return read_metadata_block_header_(iterator); -} - -FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, uint32_t padding_length, FLAC__bool padding_is_last) -{ - FLAC__StreamMetadata *padding; - - if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) { - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; - return false; - } - - block->is_last = false; - - if(!write_metadata_block_header_(iterator->file, &iterator->status, block)) - return false; - - if(!write_metadata_block_data_(iterator->file, &iterator->status, block)) - return false; - - if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING))) - return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; - - padding->is_last = padding_is_last; - padding->length = padding_length; - - if(!write_metadata_block_header_(iterator->file, &iterator->status, padding)) { - FLAC__metadata_object_delete(padding); - return false; - } - - if(!write_metadata_block_data_(iterator->file, &iterator->status, padding)) { - FLAC__metadata_object_delete(padding); - return false; - } - - FLAC__metadata_object_delete(padding); - - if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) { - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; - return false; - } - - return read_metadata_block_header_(iterator); -} - -FLAC__bool rewrite_whole_file_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool append) -{ - FILE *tempfile = NULL; - char *tempfilename = NULL; - int fixup_is_last_code = 0; /* 0 => no need to change any is_last flags */ - FLAC__off_t fixup_is_last_flag_offset = -1; - - FLAC__ASSERT(0 != block || append == false); - - if(iterator->is_last) { - if(append) { - fixup_is_last_code = 1; /* 1 => clear the is_last flag at the following offset */ - fixup_is_last_flag_offset = iterator->offset[iterator->depth]; - } - else if(0 == block) { - simple_iterator_push_(iterator); - if(!FLAC__metadata_simple_iterator_prev(iterator)) { - (void)simple_iterator_pop_(iterator); - return false; - } - fixup_is_last_code = -1; /* -1 => set the is_last the flag at the following offset */ - fixup_is_last_flag_offset = iterator->offset[iterator->depth]; - if(!simple_iterator_pop_(iterator)) - return false; - } - } - - if(!simple_iterator_copy_file_prefix_(iterator, &tempfile, &tempfilename, append)) - return false; - - if(0 != block) { - if(!write_metadata_block_header_(tempfile, &iterator->status, block)) { - cleanup_tempfile_(&tempfile, &tempfilename); - return false; - } - - if(!write_metadata_block_data_(tempfile, &iterator->status, block)) { - cleanup_tempfile_(&tempfile, &tempfilename); - return false; - } - } - - if(!simple_iterator_copy_file_postfix_(iterator, &tempfile, &tempfilename, fixup_is_last_code, fixup_is_last_flag_offset, block==0)) - return false; - - if(append) - return FLAC__metadata_simple_iterator_next(iterator); - - return true; -} - -void simple_iterator_push_(FLAC__Metadata_SimpleIterator *iterator) -{ - FLAC__ASSERT(iterator->depth+1 < SIMPLE_ITERATOR_MAX_PUSH_DEPTH); - iterator->offset[iterator->depth+1] = iterator->offset[iterator->depth]; - iterator->depth++; -} - -FLAC__bool simple_iterator_pop_(FLAC__Metadata_SimpleIterator *iterator) -{ - FLAC__ASSERT(iterator->depth > 0); - iterator->depth--; - if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) { - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; - return false; - } - - return read_metadata_block_header_(iterator); -} - -/* return meanings: - * 0: ok - * 1: read error - * 2: seek error - * 3: not a FLAC file - */ -uint32_t seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb) -{ - FLAC__byte buffer[4]; - size_t n; - uint32_t i; - - FLAC__ASSERT(FLAC__STREAM_SYNC_LENGTH == sizeof(buffer)); - - /* skip any id3v2 tag */ - errno = 0; - n = read_cb(buffer, 1, 4, handle); - if(errno) - return 1; - else if(n != 4) - return 3; - else if(0 == memcmp(buffer, "ID3", 3)) { - uint32_t tag_length = 0; - - /* skip to the tag length */ - if(seek_cb(handle, 2, SEEK_CUR) < 0) - return 2; - - /* read the length */ - for(i = 0; i < 4; i++) { - if(read_cb(buffer, 1, 1, handle) < 1 || buffer[0] & 0x80) - return 1; - tag_length <<= 7; - tag_length |= (buffer[0] & 0x7f); - } - - /* skip the rest of the tag */ - if(seek_cb(handle, tag_length, SEEK_CUR) < 0) - return 2; - - /* read the stream sync code */ - errno = 0; - n = read_cb(buffer, 1, 4, handle); - if(errno) - return 1; - else if(n != 4) - return 3; - } - - /* check for the fLaC signature */ - if(0 == memcmp(FLAC__STREAM_SYNC_STRING, buffer, FLAC__STREAM_SYNC_LENGTH)) - return 0; - else - return 3; -} - -uint32_t seek_to_first_metadata_block_(FILE *f) -{ - return seek_to_first_metadata_block_cb_((FLAC__IOHandle)f, (FLAC__IOCallback_Read)fread, fseek_wrapper_); -} - -FLAC__bool simple_iterator_copy_file_prefix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, FLAC__bool append) -{ - const FLAC__off_t offset_end = append? iterator->offset[iterator->depth] + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length : iterator->offset[iterator->depth]; - - if(0 != fseeko(iterator->file, 0, SEEK_SET)) { - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; - return false; - } - if(!open_tempfile_(iterator->filename, iterator->tempfile_path_prefix, tempfile, tempfilename, &iterator->status)) { - cleanup_tempfile_(tempfile, tempfilename); - return false; - } - if(!copy_n_bytes_from_file_(iterator->file, *tempfile, offset_end, &iterator->status)) { - cleanup_tempfile_(tempfile, tempfilename); - return false; - } - - return true; -} - -FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, FLAC__off_t fixup_is_last_flag_offset, FLAC__bool backup) -{ - FLAC__off_t save_offset = iterator->offset[iterator->depth]; - FLAC__ASSERT(0 != *tempfile); - - if(0 != fseeko(iterator->file, save_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length, SEEK_SET)) { - cleanup_tempfile_(tempfile, tempfilename); - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; - return false; - } - if(!copy_remaining_bytes_from_file_(iterator->file, *tempfile, &iterator->status)) { - cleanup_tempfile_(tempfile, tempfilename); - return false; - } - - if(fixup_is_last_code != 0) { - /* - * if code == 1, it means a block was appended to the end so - * we have to clear the is_last flag of the previous block - * if code == -1, it means the last block was deleted so - * we have to set the is_last flag of the previous block - */ - /* MAGIC NUMBERs here; we know the is_last flag is the high bit of the byte at this location */ - FLAC__byte x; - if(0 != fseeko(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) { - cleanup_tempfile_(tempfile, tempfilename); - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; - return false; - } - if(fread(&x, 1, 1, *tempfile) != 1) { - cleanup_tempfile_(tempfile, tempfilename); - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - return false; - } - if(fixup_is_last_code > 0) { - FLAC__ASSERT(x & 0x80); - x &= 0x7f; - } - else { - FLAC__ASSERT(!(x & 0x80)); - x |= 0x80; - } - if(0 != fseeko(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) { - cleanup_tempfile_(tempfile, tempfilename); - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; - return false; - } - if(local__fwrite(&x, 1, 1, *tempfile) != 1) { - cleanup_tempfile_(tempfile, tempfilename); - iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR; - return false; - } - } - - (void)fclose(iterator->file); - - if(!transport_tempfile_(iterator->filename, tempfile, tempfilename, &iterator->status)) - return false; - - if(iterator->has_stats) - set_file_stats_(iterator->filename, &iterator->stats); - - if(!simple_iterator_prime_input_(iterator, !iterator->is_writable)) - return false; - if(backup) { - while(iterator->offset[iterator->depth] + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length < save_offset) - if(!FLAC__metadata_simple_iterator_next(iterator)) - return false; - return true; - } - else { - /* move the iterator to it's original block faster by faking a push, then doing a pop_ */ - FLAC__ASSERT(iterator->depth == 0); - iterator->offset[0] = save_offset; - iterator->depth++; - return simple_iterator_pop_(iterator); - } -} - -FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status) -{ - FLAC__byte buffer[8192]; - size_t n; - - FLAC__ASSERT(bytes >= 0); - while(bytes > 0) { - n = flac_min(sizeof(buffer), (size_t)bytes); - if(fread(buffer, 1, n, file) != n) { - *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - return false; - } - if(local__fwrite(buffer, 1, n, tempfile) != n) { - *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR; - return false; - } - bytes -= n; - } - - return true; -} - -FLAC__bool copy_n_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status) -{ - FLAC__byte buffer[8192]; - size_t n; - - FLAC__ASSERT(bytes >= 0); - while(bytes > 0) { - n = flac_min(sizeof(buffer), (size_t)bytes); - if(read_cb(buffer, 1, n, handle) != n) { - *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - return false; - } - if(temp_write_cb(buffer, 1, n, temp_handle) != n) { - *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR; - return false; - } - bytes -= n; - } - - return true; -} - -FLAC__bool copy_remaining_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__Metadata_SimpleIteratorStatus *status) -{ - FLAC__byte buffer[8192]; - size_t n; - - while(!feof(file)) { - n = fread(buffer, 1, sizeof(buffer), file); - if(n == 0 && !feof(file)) { - *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - return false; - } - if(n > 0 && local__fwrite(buffer, 1, n, tempfile) != n) { - *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR; - return false; - } - } - - return true; -} - -FLAC__bool copy_remaining_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__Metadata_SimpleIteratorStatus *status) -{ - FLAC__byte buffer[8192]; - size_t n; - - while(!eof_cb(handle)) { - n = read_cb(buffer, 1, sizeof(buffer), handle); - if(n == 0 && !eof_cb(handle)) { - *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; - return false; - } - if(n > 0 && temp_write_cb(buffer, 1, n, temp_handle) != n) { - *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR; - return false; - } - } - - return true; -} - -static int -local_snprintf(char *str, size_t size, const char *fmt, ...) -{ - va_list va; - int rc; - -#if defined _MSC_VER - if (size == 0) - return 1024; -#endif - - va_start (va, fmt); - -#if defined _MSC_VER - rc = vsnprintf_s (str, size, _TRUNCATE, fmt, va); - if (rc < 0) - rc = size - 1; -#elif defined __MINGW32__ - rc = __mingw_vsnprintf (str, size, fmt, va); -#else - rc = vsnprintf (str, size, fmt, va); -#endif - va_end (va); - - return rc; -} - -FLAC__bool open_tempfile_(const char *filename, const char *tempfile_path_prefix, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status) -{ - static const char *tempfile_suffix = ".metadata_edit"; - if(0 == tempfile_path_prefix) { - size_t dest_len = strlen(filename) + strlen(tempfile_suffix) + 1; - if(0 == (*tempfilename = safe_malloc_(dest_len))) { - *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; - return false; - } - local_snprintf(*tempfilename, dest_len, "%s%s", filename, tempfile_suffix); - } - else { - const char *p = strrchr(filename, '/'); - size_t dest_len; - if(0 == p) - p = filename; - else - p++; - - dest_len = strlen(tempfile_path_prefix) + strlen(p) + strlen(tempfile_suffix) + 2; - - if(0 == (*tempfilename = safe_malloc_(dest_len))) { - *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; - return false; - } - local_snprintf(*tempfilename, dest_len, "%s/%s%s", tempfile_path_prefix, p, tempfile_suffix); - } - - if(0 == (*tempfile = flac_fopen(*tempfilename, "w+b"))) { - *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE; - return false; - } - - return true; -} - -FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status) -{ - FLAC__ASSERT(0 != filename); - FLAC__ASSERT(0 != tempfile); - FLAC__ASSERT(0 != *tempfile); - FLAC__ASSERT(0 != tempfilename); - FLAC__ASSERT(0 != *tempfilename); - FLAC__ASSERT(0 != status); - - (void)fclose(*tempfile); - *tempfile = 0; - -#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__ || defined __EMX__ - /* on some flavors of windows, flac_rename() will fail if the destination already exists */ - if(flac_unlink(filename) < 0) { - cleanup_tempfile_(tempfile, tempfilename); - *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR; - return false; - } -#endif - - /*@@@ to fully support the tempfile_path_prefix we need to update this piece to actually copy across filesystems instead of just flac_rename(): */ - if(0 != flac_rename(*tempfilename, filename)) { - cleanup_tempfile_(tempfile, tempfilename); - *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR; - return false; - } - - cleanup_tempfile_(tempfile, tempfilename); - - return true; -} - -void cleanup_tempfile_(FILE **tempfile, char **tempfilename) -{ - if(0 != *tempfile) { - (void)fclose(*tempfile); - *tempfile = 0; - } - - if(0 != *tempfilename) { - (void)flac_unlink(*tempfilename); - free(*tempfilename); - *tempfilename = 0; - } -} - -FLAC__bool get_file_stats_(const char *filename, struct flac_stat_s *stats) -{ - FLAC__ASSERT(0 != filename); - FLAC__ASSERT(0 != stats); - return (0 == flac_stat(filename, stats)); -} - -void set_file_stats_(const char *filename, struct flac_stat_s *stats) -{ - struct utimbuf srctime; - - FLAC__ASSERT(0 != filename); - FLAC__ASSERT(0 != stats); - - srctime.actime = stats->st_atime; - srctime.modtime = stats->st_mtime; - (void)flac_chmod(filename, stats->st_mode); - (void)flac_utime(filename, &srctime); -#if !defined _MSC_VER && !defined __BORLANDC__ && !defined __MINGW32__ - FLAC_CHECK_RETURN(chown(filename, stats->st_uid, -1)); - FLAC_CHECK_RETURN(chown(filename, -1, stats->st_gid)); -#endif -} - -int fseek_wrapper_(FLAC__IOHandle handle, FLAC__int64 offset, int whence) -{ - return fseeko((FILE*)handle, (FLAC__off_t)offset, whence); -} - -FLAC__int64 ftell_wrapper_(FLAC__IOHandle handle) -{ - return ftello((FILE*)handle); -} - -FLAC__Metadata_ChainStatus get_equivalent_status_(FLAC__Metadata_SimpleIteratorStatus status) -{ - switch(status) { - case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK: - return FLAC__METADATA_CHAIN_STATUS_OK; - case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT: - return FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT; - case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE: - return FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE; - case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE: - return FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE; - case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE: - return FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE; - case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA: - return FLAC__METADATA_CHAIN_STATUS_BAD_METADATA; - case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR: - return FLAC__METADATA_CHAIN_STATUS_READ_ERROR; - case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR: - return FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR; - case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR: - return FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR; - case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR: - return FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR; - case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR: - return FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR; - case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR: - return FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR; - case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR: - default: - return FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; - } -} diff --git a/lib/flac/src/metadata_object.c b/lib/flac/src/metadata_object.c deleted file mode 100644 index de8e513..0000000 --- a/lib/flac/src/metadata_object.c +++ /dev/null @@ -1,1821 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include - -#include "private/metadata.h" -#include "private/memory.h" - -#include "FLAC/assert.h" -#include "share/alloc.h" -#include "share/compat.h" - -/* Alias the first (in share/alloc.h) to the second (in src/libFLAC/memory.c). */ -#define safe_malloc_mul_2op_ safe_malloc_mul_2op_p - - -/**************************************************************************** - * - * Local routines - * - ***************************************************************************/ - -/* copy bytes: - * from = NULL && bytes = 0 - * to <- NULL - * from != NULL && bytes > 0 - * to <- copy of from - * else ASSERT - * malloc error leaves 'to' unchanged - */ -static FLAC__bool copy_bytes_(FLAC__byte **to, const FLAC__byte *from, uint32_t bytes) -{ - FLAC__ASSERT(to != NULL); - if (bytes > 0 && from != NULL) { - FLAC__byte *x; - if ((x = safe_malloc_(bytes)) == NULL) - return false; - memcpy(x, from, bytes); - *to = x; - } - else { - *to = 0; - } - return true; -} - -#if 0 /* UNUSED */ -/* like copy_bytes_(), but free()s the original '*to' if the copy succeeds and the original '*to' is non-NULL */ -static FLAC__bool free_copy_bytes_(FLAC__byte **to, const FLAC__byte *from, uint32_t bytes) -{ - FLAC__byte *copy; - FLAC__ASSERT(to != NULL); - if (copy_bytes_(©, from, bytes)) { - free(*to); - *to = copy; - return true; - } - else - return false; -} -#endif - -/* reallocate entry to 1 byte larger and add a terminating NUL */ -/* realloc() failure leaves entry unchanged */ -static FLAC__bool ensure_null_terminated_(FLAC__byte **entry, uint32_t length) -{ - FLAC__byte *x = safe_realloc_add_2op_(*entry, length, /*+*/1); - if (x != NULL) { - x[length] = '\0'; - *entry = x; - return true; - } - else - return false; -} - -/* copies the NUL-terminated C-string 'from' to '*to', leaving '*to' - * unchanged if malloc fails, free()ing the original '*to' if it - * succeeds and the original '*to' was not NULL - */ -static FLAC__bool copy_cstring_(char **to, const char *from) -{ - char *copy = strdup(from); - FLAC__ASSERT(to != NULL); - if (copy) { - free(*to); - *to = copy; - return true; - } - else - return false; -} - -static FLAC__bool copy_vcentry_(FLAC__StreamMetadata_VorbisComment_Entry *to, const FLAC__StreamMetadata_VorbisComment_Entry *from) -{ - to->length = from->length; - if (from->entry == 0) { - FLAC__ASSERT(from->length == 0); - to->entry = 0; - } - else { - FLAC__byte *x; - FLAC__ASSERT(from->length > 0); - if ((x = safe_malloc_add_2op_(from->length, /*+*/1)) == NULL) - return false; - memcpy(x, from->entry, from->length); - x[from->length] = '\0'; - to->entry = x; - } - return true; -} - -static FLAC__bool copy_track_(FLAC__StreamMetadata_CueSheet_Track *to, const FLAC__StreamMetadata_CueSheet_Track *from) -{ - memcpy(to, from, sizeof(FLAC__StreamMetadata_CueSheet_Track)); - if (from->indices == 0) { - FLAC__ASSERT(from->num_indices == 0); - } - else { - FLAC__StreamMetadata_CueSheet_Index *x; - FLAC__ASSERT(from->num_indices > 0); - if ((x = safe_malloc_mul_2op_p(from->num_indices, /*times*/sizeof(FLAC__StreamMetadata_CueSheet_Index))) == NULL) - return false; - memcpy(x, from->indices, from->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index)); - to->indices = x; - } - return true; -} - -static void seektable_calculate_length_(FLAC__StreamMetadata *object) -{ - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); - - object->length = object->data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH; -} - -static FLAC__StreamMetadata_SeekPoint *seekpoint_array_new_(uint32_t num_points) -{ - FLAC__StreamMetadata_SeekPoint *object_array; - - FLAC__ASSERT(num_points > 0); - - object_array = safe_malloc_mul_2op_p(num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint)); - - if (object_array != NULL) { - uint32_t i; - for (i = 0; i < num_points; i++) { - object_array[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER; - object_array[i].stream_offset = 0; - object_array[i].frame_samples = 0; - } - } - - return object_array; -} - -static void vorbiscomment_calculate_length_(FLAC__StreamMetadata *object) -{ - uint32_t i; - - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); - - object->length = (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN) / 8; - object->length += object->data.vorbis_comment.vendor_string.length; - object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8; - for (i = 0; i < object->data.vorbis_comment.num_comments; i++) { - object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8); - object->length += object->data.vorbis_comment.comments[i].length; - } -} - -static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_new_(uint32_t num_comments) -{ - FLAC__ASSERT(num_comments > 0); - - return safe_calloc_(num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry)); -} - -static void vorbiscomment_entry_array_delete_(FLAC__StreamMetadata_VorbisComment_Entry *object_array, uint32_t num_comments) -{ - uint32_t i; - - FLAC__ASSERT(object_array != NULL && num_comments > 0); - - for (i = 0; i < num_comments; i++) - free(object_array[i].entry); - - free(object_array); -} - -static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_copy_(const FLAC__StreamMetadata_VorbisComment_Entry *object_array, uint32_t num_comments) -{ - FLAC__StreamMetadata_VorbisComment_Entry *return_array; - - FLAC__ASSERT(object_array != NULL); - FLAC__ASSERT(num_comments > 0); - - return_array = vorbiscomment_entry_array_new_(num_comments); - - if (return_array != NULL) { - uint32_t i; - - for (i = 0; i < num_comments; i++) { - if (!copy_vcentry_(return_array+i, object_array+i)) { - vorbiscomment_entry_array_delete_(return_array, num_comments); - return 0; - } - } - } - - return return_array; -} - -static FLAC__bool vorbiscomment_set_entry_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry *dest, const FLAC__StreamMetadata_VorbisComment_Entry *src, FLAC__bool copy) -{ - FLAC__byte *save; - - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(dest != NULL); - FLAC__ASSERT(src != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); - FLAC__ASSERT((src->entry != NULL && src->length > 0) || (src->entry == NULL && src->length == 0)); - - save = dest->entry; - - if (src->entry != NULL) { - if (copy) { - /* do the copy first so that if we fail we leave the dest object untouched */ - if (!copy_vcentry_(dest, src)) - return false; - } - else { - /* we have to make sure that the string we're taking over is null-terminated */ - - /* - * Stripping the const from src->entry is OK since we're taking - * ownership of the pointer. This is a hack around a deficiency - * in the API where the same function is used for 'copy' and - * 'own', but the source entry is a const pointer. If we were - * precise, the 'own' flavor would be a separate function with a - * non-const source pointer. But it's not, so we hack away. - */ - if (!ensure_null_terminated_((FLAC__byte**)(&src->entry), src->length)) - return false; - *dest = *src; - } - } - else { - /* the src is null */ - *dest = *src; - } - - free(save); - - vorbiscomment_calculate_length_(object); - return true; -} - -static int vorbiscomment_find_entry_from_(const FLAC__StreamMetadata *object, uint32_t offset, const char *field_name, uint32_t field_name_length) -{ - uint32_t i; - - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); - FLAC__ASSERT(field_name != NULL); - - for (i = offset; i < object->data.vorbis_comment.num_comments; i++) { - if (FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) - return (int)i; - } - - return -1; -} - -static void cuesheet_calculate_length_(FLAC__StreamMetadata *object) -{ - uint32_t i; - - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); - - object->length = ( - FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN + - FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN + - FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + - FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN + - FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN - ) / 8; - - object->length += object->data.cue_sheet.num_tracks * ( - FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN + - FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN + - FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN + - FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + - FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + - FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN + - FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN - ) / 8; - - for (i = 0; i < object->data.cue_sheet.num_tracks; i++) { - object->length += object->data.cue_sheet.tracks[i].num_indices * ( - FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN + - FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN + - FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN - ) / 8; - } -} - -static FLAC__StreamMetadata_CueSheet_Index *cuesheet_track_index_array_new_(uint32_t num_indices) -{ - FLAC__ASSERT(num_indices > 0); - - return safe_calloc_(num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index)); -} - -static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_new_(uint32_t num_tracks) -{ - FLAC__ASSERT(num_tracks > 0); - - return safe_calloc_(num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track)); -} - -static void cuesheet_track_array_delete_(FLAC__StreamMetadata_CueSheet_Track *object_array, uint32_t num_tracks) -{ - uint32_t i; - - FLAC__ASSERT(object_array != NULL && num_tracks > 0); - - for (i = 0; i < num_tracks; i++) { - if (object_array[i].indices != 0) { - FLAC__ASSERT(object_array[i].num_indices > 0); - free(object_array[i].indices); - } - } - - free(object_array); -} - -static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_copy_(const FLAC__StreamMetadata_CueSheet_Track *object_array, uint32_t num_tracks) -{ - FLAC__StreamMetadata_CueSheet_Track *return_array; - - FLAC__ASSERT(object_array != NULL); - FLAC__ASSERT(num_tracks > 0); - - return_array = cuesheet_track_array_new_(num_tracks); - - if (return_array != NULL) { - uint32_t i; - - for (i = 0; i < num_tracks; i++) { - if (!copy_track_(return_array+i, object_array+i)) { - cuesheet_track_array_delete_(return_array, num_tracks); - return 0; - } - } - } - - return return_array; -} - -static FLAC__bool cuesheet_set_track_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_CueSheet_Track *dest, const FLAC__StreamMetadata_CueSheet_Track *src, FLAC__bool copy) -{ - FLAC__StreamMetadata_CueSheet_Index *save; - - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(dest != NULL); - FLAC__ASSERT(src != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); - FLAC__ASSERT((src->indices != NULL && src->num_indices > 0) || (src->indices == NULL && src->num_indices == 0)); - - save = dest->indices; - - /* do the copy first so that if we fail we leave the object untouched */ - if (copy) { - if (!copy_track_(dest, src)) - return false; - } - else { - *dest = *src; - } - - free(save); - - cuesheet_calculate_length_(object); - return true; -} - - -/**************************************************************************** - * - * Metadata object routines - * - ***************************************************************************/ - -FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type) -{ - FLAC__StreamMetadata *object; - - if (type > FLAC__MAX_METADATA_TYPE) - return 0; - - object = calloc(1, sizeof(FLAC__StreamMetadata)); - if (object != NULL) { - object->is_last = false; - object->type = type; - switch(type) { - case FLAC__METADATA_TYPE_STREAMINFO: - object->length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH; - break; - case FLAC__METADATA_TYPE_PADDING: - /* calloc() took care of this for us: - object->length = 0; - */ - break; - case FLAC__METADATA_TYPE_APPLICATION: - object->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8; - /* calloc() took care of this for us: - object->data.application.data = 0; - */ - break; - case FLAC__METADATA_TYPE_SEEKTABLE: - /* calloc() took care of this for us: - object->length = 0; - object->data.seek_table.num_points = 0; - object->data.seek_table.points = 0; - */ - break; - case FLAC__METADATA_TYPE_VORBIS_COMMENT: - object->data.vorbis_comment.vendor_string.length = (uint32_t)strlen(FLAC__VENDOR_STRING); - if (!copy_bytes_(&object->data.vorbis_comment.vendor_string.entry, (const FLAC__byte*)FLAC__VENDOR_STRING, object->data.vorbis_comment.vendor_string.length+1)) { - free(object); - return 0; - } - vorbiscomment_calculate_length_(object); - break; - case FLAC__METADATA_TYPE_CUESHEET: - cuesheet_calculate_length_(object); - break; - case FLAC__METADATA_TYPE_PICTURE: - object->length = ( - FLAC__STREAM_METADATA_PICTURE_TYPE_LEN + - FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* empty mime_type string */ - FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* empty description string */ - FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN + - FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN + - FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN + - FLAC__STREAM_METADATA_PICTURE_COLORS_LEN + - FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN + - 0 /* no data */ - ) / 8; - object->data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER; - object->data.picture.mime_type = 0; - object->data.picture.description = 0; - /* calloc() took care of this for us: - object->data.picture.width = 0; - object->data.picture.height = 0; - object->data.picture.depth = 0; - object->data.picture.colors = 0; - object->data.picture.data_length = 0; - object->data.picture.data = 0; - */ - /* now initialize mime_type and description with empty strings to make things easier on the client */ - if (!copy_cstring_(&object->data.picture.mime_type, "")) { - free(object); - return 0; - } - if (!copy_cstring_((char**)(&object->data.picture.description), "")) { - free(object->data.picture.mime_type); - free(object); - return 0; - } - break; - default: - /* calloc() took care of this for us: - object->length = 0; - object->data.unknown.data = 0; - */ - break; - } - } - - return object; -} - -FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMetadata *object) -{ - FLAC__StreamMetadata *to; - - FLAC__ASSERT(object != NULL); - - if ((to = FLAC__metadata_object_new(object->type)) != NULL) { - to->is_last = object->is_last; - to->type = object->type; - to->length = object->length; - switch(to->type) { - case FLAC__METADATA_TYPE_STREAMINFO: - memcpy(&to->data.stream_info, &object->data.stream_info, sizeof(FLAC__StreamMetadata_StreamInfo)); - break; - case FLAC__METADATA_TYPE_PADDING: - break; - case FLAC__METADATA_TYPE_APPLICATION: - if (to->length < FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8) { /* underflow check */ - FLAC__metadata_object_delete(to); - return 0; - } - memcpy(&to->data.application.id, &object->data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8); - if (!copy_bytes_(&to->data.application.data, object->data.application.data, object->length - FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8)) { - FLAC__metadata_object_delete(to); - return 0; - } - break; - case FLAC__METADATA_TYPE_SEEKTABLE: - to->data.seek_table.num_points = object->data.seek_table.num_points; - if (to->data.seek_table.num_points > UINT32_MAX / sizeof(FLAC__StreamMetadata_SeekPoint)) { /* overflow check */ - FLAC__metadata_object_delete(to); - return 0; - } - if (!copy_bytes_((FLAC__byte**)&to->data.seek_table.points, (FLAC__byte*)object->data.seek_table.points, object->data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint))) { - FLAC__metadata_object_delete(to); - return 0; - } - break; - case FLAC__METADATA_TYPE_VORBIS_COMMENT: - if (to->data.vorbis_comment.vendor_string.entry != NULL) { - free(to->data.vorbis_comment.vendor_string.entry); - to->data.vorbis_comment.vendor_string.entry = 0; - } - if (!copy_vcentry_(&to->data.vorbis_comment.vendor_string, &object->data.vorbis_comment.vendor_string)) { - FLAC__metadata_object_delete(to); - return 0; - } - if (object->data.vorbis_comment.num_comments == 0) { - to->data.vorbis_comment.comments = 0; - } - else { - to->data.vorbis_comment.comments = vorbiscomment_entry_array_copy_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments); - if (to->data.vorbis_comment.comments == NULL) { - to->data.vorbis_comment.num_comments = 0; - FLAC__metadata_object_delete(to); - return 0; - } - } - to->data.vorbis_comment.num_comments = object->data.vorbis_comment.num_comments; - break; - case FLAC__METADATA_TYPE_CUESHEET: - memcpy(&to->data.cue_sheet, &object->data.cue_sheet, sizeof(FLAC__StreamMetadata_CueSheet)); - if (object->data.cue_sheet.num_tracks == 0) { - FLAC__ASSERT(object->data.cue_sheet.tracks == NULL); - } - else { - FLAC__ASSERT(object->data.cue_sheet.tracks != 0); - to->data.cue_sheet.tracks = cuesheet_track_array_copy_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks); - if (to->data.cue_sheet.tracks == NULL) { - FLAC__metadata_object_delete(to); - return 0; - } - } - break; - case FLAC__METADATA_TYPE_PICTURE: - to->data.picture.type = object->data.picture.type; - if (!copy_cstring_(&to->data.picture.mime_type, object->data.picture.mime_type)) { - FLAC__metadata_object_delete(to); - return 0; - } - if (!copy_cstring_((char**)(&to->data.picture.description), (const char*)object->data.picture.description)) { - FLAC__metadata_object_delete(to); - return 0; - } - to->data.picture.width = object->data.picture.width; - to->data.picture.height = object->data.picture.height; - to->data.picture.depth = object->data.picture.depth; - to->data.picture.colors = object->data.picture.colors; - to->data.picture.data_length = object->data.picture.data_length; - if (!copy_bytes_((&to->data.picture.data), object->data.picture.data, object->data.picture.data_length)) { - FLAC__metadata_object_delete(to); - return 0; - } - break; - default: - if (!copy_bytes_(&to->data.unknown.data, object->data.unknown.data, object->length)) { - FLAC__metadata_object_delete(to); - return 0; - } - break; - } - } - - return to; -} - -void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object) -{ - FLAC__ASSERT(object != NULL); - - switch(object->type) { - case FLAC__METADATA_TYPE_STREAMINFO: - case FLAC__METADATA_TYPE_PADDING: - break; - case FLAC__METADATA_TYPE_APPLICATION: - if (object->data.application.data != NULL) { - free(object->data.application.data); - object->data.application.data = NULL; - } - break; - case FLAC__METADATA_TYPE_SEEKTABLE: - if (object->data.seek_table.points != NULL) { - free(object->data.seek_table.points); - object->data.seek_table.points = NULL; - } - break; - case FLAC__METADATA_TYPE_VORBIS_COMMENT: - if (object->data.vorbis_comment.vendor_string.entry != NULL) { - free(object->data.vorbis_comment.vendor_string.entry); - object->data.vorbis_comment.vendor_string.entry = 0; - } - if (object->data.vorbis_comment.comments != NULL) { - FLAC__ASSERT(object->data.vorbis_comment.num_comments > 0); - vorbiscomment_entry_array_delete_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments); - object->data.vorbis_comment.comments = NULL; - object->data.vorbis_comment.num_comments = 0; - } - break; - case FLAC__METADATA_TYPE_CUESHEET: - if (object->data.cue_sheet.tracks != NULL) { - FLAC__ASSERT(object->data.cue_sheet.num_tracks > 0); - cuesheet_track_array_delete_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks); - object->data.cue_sheet.tracks = NULL; - object->data.cue_sheet.num_tracks = 0; - } - break; - case FLAC__METADATA_TYPE_PICTURE: - if (object->data.picture.mime_type != NULL) { - free(object->data.picture.mime_type); - object->data.picture.mime_type = NULL; - } - if (object->data.picture.description != NULL) { - free(object->data.picture.description); - object->data.picture.description = NULL; - } - if (object->data.picture.data != NULL) { - free(object->data.picture.data); - object->data.picture.data = NULL; - } - break; - default: - if (object->data.unknown.data != NULL) { - free(object->data.unknown.data); - object->data.unknown.data = NULL; - } - break; - } -} - -FLAC_API void FLAC__metadata_object_delete(FLAC__StreamMetadata *object) -{ - FLAC__metadata_object_delete_data(object); - free(object); -} - -static FLAC__bool compare_block_data_streaminfo_(const FLAC__StreamMetadata_StreamInfo *block1, const FLAC__StreamMetadata_StreamInfo *block2) -{ - if (block1->min_blocksize != block2->min_blocksize) - return false; - if (block1->max_blocksize != block2->max_blocksize) - return false; - if (block1->min_framesize != block2->min_framesize) - return false; - if (block1->max_framesize != block2->max_framesize) - return false; - if (block1->sample_rate != block2->sample_rate) - return false; - if (block1->channels != block2->channels) - return false; - if (block1->bits_per_sample != block2->bits_per_sample) - return false; - if (block1->total_samples != block2->total_samples) - return false; - if (memcmp(block1->md5sum, block2->md5sum, 16) != 0) - return false; - return true; -} - -static FLAC__bool compare_block_data_application_(const FLAC__StreamMetadata_Application *block1, const FLAC__StreamMetadata_Application *block2, uint32_t block_length) -{ - FLAC__ASSERT(block1 != NULL); - FLAC__ASSERT(block2 != NULL); - FLAC__ASSERT(block_length >= sizeof(block1->id)); - - if (memcmp(block1->id, block2->id, sizeof(block1->id)) != 0) - return false; - if (block1->data != NULL && block2->data != NULL) - return memcmp(block1->data, block2->data, block_length - sizeof(block1->id)) == 0; - else - return block1->data == block2->data; -} - -static FLAC__bool compare_block_data_seektable_(const FLAC__StreamMetadata_SeekTable *block1, const FLAC__StreamMetadata_SeekTable *block2) -{ - uint32_t i; - - FLAC__ASSERT(block1 != NULL); - FLAC__ASSERT(block2 != NULL); - - if (block1->num_points != block2->num_points) - return false; - - if (block1->points != NULL && block2->points != NULL) { - for (i = 0; i < block1->num_points; i++) { - if (block1->points[i].sample_number != block2->points[i].sample_number) - return false; - if (block1->points[i].stream_offset != block2->points[i].stream_offset) - return false; - if (block1->points[i].frame_samples != block2->points[i].frame_samples) - return false; - } - return true; - } - else - return block1->points == block2->points; -} - -static FLAC__bool compare_block_data_vorbiscomment_(const FLAC__StreamMetadata_VorbisComment *block1, const FLAC__StreamMetadata_VorbisComment *block2) -{ - uint32_t i; - - if (block1->vendor_string.length != block2->vendor_string.length) - return false; - - if (block1->vendor_string.entry != NULL && block2->vendor_string.entry != NULL) { - if (memcmp(block1->vendor_string.entry, block2->vendor_string.entry, block1->vendor_string.length) != 0) - return false; - } - else if (block1->vendor_string.entry != block2->vendor_string.entry) - return false; - - if (block1->num_comments != block2->num_comments) - return false; - - for (i = 0; i < block1->num_comments; i++) { - if (block1->comments[i].entry != NULL && block2->comments[i].entry != NULL) { - if (memcmp(block1->comments[i].entry, block2->comments[i].entry, block1->comments[i].length) != 0) - return false; - } - else if (block1->comments[i].entry != block2->comments[i].entry) - return false; - } - return true; -} - -static FLAC__bool compare_block_data_cuesheet_(const FLAC__StreamMetadata_CueSheet *block1, const FLAC__StreamMetadata_CueSheet *block2) -{ - uint32_t i, j; - - if (strcmp(block1->media_catalog_number, block2->media_catalog_number) != 0) - return false; - - if (block1->lead_in != block2->lead_in) - return false; - - if (block1->is_cd != block2->is_cd) - return false; - - if (block1->num_tracks != block2->num_tracks) - return false; - - if (block1->tracks != NULL && block2->tracks != NULL) { - FLAC__ASSERT(block1->num_tracks > 0); - for (i = 0; i < block1->num_tracks; i++) { - if (block1->tracks[i].offset != block2->tracks[i].offset) - return false; - if (block1->tracks[i].number != block2->tracks[i].number) - return false; - if (memcmp(block1->tracks[i].isrc, block2->tracks[i].isrc, sizeof(block1->tracks[i].isrc)) != 0) - return false; - if (block1->tracks[i].type != block2->tracks[i].type) - return false; - if (block1->tracks[i].pre_emphasis != block2->tracks[i].pre_emphasis) - return false; - if (block1->tracks[i].num_indices != block2->tracks[i].num_indices) - return false; - if (block1->tracks[i].indices != NULL && block2->tracks[i].indices != NULL) { - FLAC__ASSERT(block1->tracks[i].num_indices > 0); - for (j = 0; j < block1->tracks[i].num_indices; j++) { - if (block1->tracks[i].indices[j].offset != block2->tracks[i].indices[j].offset) - return false; - if (block1->tracks[i].indices[j].number != block2->tracks[i].indices[j].number) - return false; - } - } - else if (block1->tracks[i].indices != block2->tracks[i].indices) - return false; - } - } - else if (block1->tracks != block2->tracks) - return false; - return true; -} - -static FLAC__bool compare_block_data_picture_(const FLAC__StreamMetadata_Picture *block1, const FLAC__StreamMetadata_Picture *block2) -{ - if (block1->type != block2->type) - return false; - if (block1->mime_type != block2->mime_type && (block1->mime_type == 0 || block2->mime_type == 0 || strcmp(block1->mime_type, block2->mime_type))) - return false; - if (block1->description != block2->description && (block1->description == 0 || block2->description == 0 || strcmp((const char *)block1->description, (const char *)block2->description))) - return false; - if (block1->width != block2->width) - return false; - if (block1->height != block2->height) - return false; - if (block1->depth != block2->depth) - return false; - if (block1->colors != block2->colors) - return false; - if (block1->data_length != block2->data_length) - return false; - if (block1->data != block2->data && (block1->data == NULL || block2->data == NULL || memcmp(block1->data, block2->data, block1->data_length))) - return false; - return true; -} - -static FLAC__bool compare_block_data_unknown_(const FLAC__StreamMetadata_Unknown *block1, const FLAC__StreamMetadata_Unknown *block2, uint32_t block_length) -{ - FLAC__ASSERT(block1 != NULL); - FLAC__ASSERT(block2 != NULL); - - if (block1->data != NULL && block2->data != NULL) - return memcmp(block1->data, block2->data, block_length) == 0; - else - return block1->data == block2->data; -} - -FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *block1, const FLAC__StreamMetadata *block2) -{ - FLAC__ASSERT(block1 != NULL); - FLAC__ASSERT(block2 != NULL); - - if (block1->type != block2->type) { - return false; - } - if (block1->is_last != block2->is_last) { - return false; - } - if (block1->length != block2->length) { - return false; - } - switch(block1->type) { - case FLAC__METADATA_TYPE_STREAMINFO: - return compare_block_data_streaminfo_(&block1->data.stream_info, &block2->data.stream_info); - case FLAC__METADATA_TYPE_PADDING: - return true; /* we don't compare the padding guts */ - case FLAC__METADATA_TYPE_APPLICATION: - return compare_block_data_application_(&block1->data.application, &block2->data.application, block1->length); - case FLAC__METADATA_TYPE_SEEKTABLE: - return compare_block_data_seektable_(&block1->data.seek_table, &block2->data.seek_table); - case FLAC__METADATA_TYPE_VORBIS_COMMENT: - return compare_block_data_vorbiscomment_(&block1->data.vorbis_comment, &block2->data.vorbis_comment); - case FLAC__METADATA_TYPE_CUESHEET: - return compare_block_data_cuesheet_(&block1->data.cue_sheet, &block2->data.cue_sheet); - case FLAC__METADATA_TYPE_PICTURE: - return compare_block_data_picture_(&block1->data.picture, &block2->data.picture); - default: - return compare_block_data_unknown_(&block1->data.unknown, &block2->data.unknown, block1->length); - } -} - -FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, uint32_t length, FLAC__bool copy) -{ - FLAC__byte *save; - - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_APPLICATION); - FLAC__ASSERT((data != NULL && length > 0) || (data == NULL && length == 0 && copy == false)); - - save = object->data.application.data; - - /* do the copy first so that if we fail we leave the object untouched */ - if (copy) { - if (!copy_bytes_(&object->data.application.data, data, length)) - return false; - } - else { - object->data.application.data = data; - } - - free(save); - - object->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8 + length; - return true; -} - -FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMetadata *object, uint32_t new_num_points) -{ - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); - - if (object->data.seek_table.points == 0) { - FLAC__ASSERT(object->data.seek_table.num_points == 0); - if (new_num_points == 0) - return true; - else if ((object->data.seek_table.points = seekpoint_array_new_(new_num_points)) == 0) - return false; - } - else { - const size_t old_size = object->data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint); - const size_t new_size = new_num_points * sizeof(FLAC__StreamMetadata_SeekPoint); - - /* overflow check */ - if (new_num_points > UINT32_MAX / sizeof(FLAC__StreamMetadata_SeekPoint)) - return false; - - FLAC__ASSERT(object->data.seek_table.num_points > 0); - - if (new_size == 0) { - free(object->data.seek_table.points); - object->data.seek_table.points = 0; - } - else if ((object->data.seek_table.points = safe_realloc_(object->data.seek_table.points, new_size)) == NULL) - return false; - - /* if growing, set new elements to placeholders */ - if (new_size > old_size) { - uint32_t i; - for (i = object->data.seek_table.num_points; i < new_num_points; i++) { - object->data.seek_table.points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER; - object->data.seek_table.points[i].stream_offset = 0; - object->data.seek_table.points[i].frame_samples = 0; - } - } - } - - object->data.seek_table.num_points = new_num_points; - - seektable_calculate_length_(object); - return true; -} - -FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point) -{ - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); - FLAC__ASSERT(point_num < object->data.seek_table.num_points); - - object->data.seek_table.points[point_num] = point; -} - -FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point) -{ - int i; - - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); - FLAC__ASSERT(point_num <= object->data.seek_table.num_points); - - if (!FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points+1)) - return false; - - /* move all points >= point_num forward one space */ - for (i = (int)object->data.seek_table.num_points-1; i > (int)point_num; i--) - object->data.seek_table.points[i] = object->data.seek_table.points[i-1]; - - FLAC__metadata_object_seektable_set_point(object, point_num, point); - seektable_calculate_length_(object); - return true; -} - -FLAC_API FLAC__bool FLAC__metadata_object_seektable_delete_point(FLAC__StreamMetadata *object, uint32_t point_num) -{ - uint32_t i; - - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); - FLAC__ASSERT(point_num < object->data.seek_table.num_points); - - /* move all points > point_num backward one space */ - for (i = point_num; i < object->data.seek_table.num_points-1; i++) - object->data.seek_table.points[i] = object->data.seek_table.points[i+1]; - - return FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points-1); -} - -FLAC_API FLAC__bool FLAC__metadata_object_seektable_is_legal(const FLAC__StreamMetadata *object) -{ - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); - - return FLAC__format_seektable_is_legal(&object->data.seek_table); -} - -FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_placeholders(FLAC__StreamMetadata *object, uint32_t num) -{ - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); - - if (num > 0) - /* WATCHOUT: we rely on the fact that growing the array adds PLACEHOLDERS at the end */ - return FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points + num); - else - return true; -} - -FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_point(FLAC__StreamMetadata *object, FLAC__uint64 sample_number) -{ - FLAC__StreamMetadata_SeekTable *seek_table; - - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); - - seek_table = &object->data.seek_table; - - if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + 1)) - return false; - - seek_table->points[seek_table->num_points - 1].sample_number = sample_number; - seek_table->points[seek_table->num_points - 1].stream_offset = 0; - seek_table->points[seek_table->num_points - 1].frame_samples = 0; - - return true; -} - -FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC__StreamMetadata *object, FLAC__uint64 sample_numbers[], uint32_t num) -{ - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); - FLAC__ASSERT(sample_numbers != 0 || num == 0); - - if (num > 0) { - FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table; - uint32_t i, j; - - i = seek_table->num_points; - - if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + num)) - return false; - - for (j = 0; j < num; i++, j++) { - seek_table->points[i].sample_number = sample_numbers[j]; - seek_table->points[i].stream_offset = 0; - seek_table->points[i].frame_samples = 0; - } - } - - return true; -} - -FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points(FLAC__StreamMetadata *object, uint32_t num, FLAC__uint64 total_samples) -{ - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); - FLAC__ASSERT(total_samples > 0); - - if (num > 0 && total_samples > 0) { - FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table; - uint32_t i, j; - - i = seek_table->num_points; - - if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + num)) - return false; - - for (j = 0; j < num; i++, j++) { - seek_table->points[i].sample_number = total_samples * (FLAC__uint64)j / (FLAC__uint64)num; - seek_table->points[i].stream_offset = 0; - seek_table->points[i].frame_samples = 0; - } - } - - return true; -} - -FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(FLAC__StreamMetadata *object, uint32_t samples, FLAC__uint64 total_samples) -{ - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); - FLAC__ASSERT(samples > 0); - FLAC__ASSERT(total_samples > 0); - - if (samples > 0 && total_samples > 0) { - FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table; - uint32_t i, j; - FLAC__uint64 num, sample; - - num = 1 + total_samples / samples; /* 1+ for the first sample at 0 */ - /* now account for the fact that we don't place a seekpoint at "total_samples" since samples are number from 0: */ - if (total_samples % samples == 0) - num--; - - /* Put a strict upper bound on the number of allowed seek points. */ - if (num > 32768) { - /* Set the bound and recalculate samples accordingly. */ - num = 32768; - samples = total_samples / num; - } - - i = seek_table->num_points; - - if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + (uint32_t)num)) - return false; - - sample = 0; - for (j = 0; j < num; i++, j++, sample += samples) { - seek_table->points[i].sample_number = sample; - seek_table->points[i].stream_offset = 0; - seek_table->points[i].frame_samples = 0; - } - } - - return true; -} - -FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_sort(FLAC__StreamMetadata *object, FLAC__bool compact) -{ - uint32_t unique; - - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); - - unique = FLAC__format_seektable_sort(&object->data.seek_table); - - return !compact || FLAC__metadata_object_seektable_resize_points(object, unique); -} - -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_vendor_string(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy) -{ - if (!FLAC__format_vorbiscomment_entry_value_is_legal(entry.entry, entry.length)) - return false; - return vorbiscomment_set_entry_(object, &object->data.vorbis_comment.vendor_string, &entry, copy); -} - -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__StreamMetadata *object, uint32_t new_num_comments) -{ - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); - - if (object->data.vorbis_comment.comments == NULL) { - FLAC__ASSERT(object->data.vorbis_comment.num_comments == 0); - if (new_num_comments == 0) - return true; - else if ((object->data.vorbis_comment.comments = vorbiscomment_entry_array_new_(new_num_comments)) == NULL) - return false; - } - else { - const size_t old_size = object->data.vorbis_comment.num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry); - const size_t new_size = new_num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry); - - /* overflow check */ - if (new_num_comments > UINT32_MAX / sizeof(FLAC__StreamMetadata_VorbisComment_Entry)) - return false; - - FLAC__ASSERT(object->data.vorbis_comment.num_comments > 0); - - /* if shrinking, free the truncated entries */ - if (new_num_comments < object->data.vorbis_comment.num_comments) { - uint32_t i; - for (i = new_num_comments; i < object->data.vorbis_comment.num_comments; i++) - if (object->data.vorbis_comment.comments[i].entry != NULL) - free(object->data.vorbis_comment.comments[i].entry); - } - - if (new_size == 0) { - free(object->data.vorbis_comment.comments); - object->data.vorbis_comment.comments = 0; - } - else { - FLAC__StreamMetadata_VorbisComment_Entry *oldptr = object->data.vorbis_comment.comments; - if ((object->data.vorbis_comment.comments = realloc(object->data.vorbis_comment.comments, new_size)) == NULL) { - vorbiscomment_entry_array_delete_(oldptr, object->data.vorbis_comment.num_comments); - object->data.vorbis_comment.num_comments = 0; - return false; - } - } - - /* if growing, zero all the length/pointers of new elements */ - if (new_size > old_size) - memset(object->data.vorbis_comment.comments + object->data.vorbis_comment.num_comments, 0, new_size - old_size); - } - - object->data.vorbis_comment.num_comments = new_num_comments; - - vorbiscomment_calculate_length_(object); - return true; -} - -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__StreamMetadata *object, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy) -{ - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(comment_num < object->data.vorbis_comment.num_comments); - - if (!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length)) - return false; - return vorbiscomment_set_entry_(object, &object->data.vorbis_comment.comments[comment_num], &entry, copy); -} - -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__StreamMetadata *object, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy) -{ - FLAC__StreamMetadata_VorbisComment *vc; - - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); - FLAC__ASSERT(comment_num <= object->data.vorbis_comment.num_comments); - - if (!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length)) - return false; - - vc = &object->data.vorbis_comment; - - if (!FLAC__metadata_object_vorbiscomment_resize_comments(object, vc->num_comments+1)) - return false; - - /* move all comments >= comment_num forward one space */ - memmove(&vc->comments[comment_num+1], &vc->comments[comment_num], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(vc->num_comments-1-comment_num)); - vc->comments[comment_num].length = 0; - vc->comments[comment_num].entry = 0; - - return FLAC__metadata_object_vorbiscomment_set_comment(object, comment_num, entry, copy); -} - -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_append_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy) -{ - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); - return FLAC__metadata_object_vorbiscomment_insert_comment(object, object->data.vorbis_comment.num_comments, entry, copy); -} - -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_replace_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool all, FLAC__bool copy) -{ - FLAC__ASSERT(entry.entry != NULL && entry.length > 0); - - if (!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length)) - return false; - - { - int i; - size_t field_name_length; - const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length); - - if (eq == NULL) - return false; /* double protection */ - - field_name_length = eq-entry.entry; - - i = vorbiscomment_find_entry_from_(object, 0, (const char *)entry.entry, field_name_length); - if (i >= 0) { - uint32_t indx = (uint32_t)i; - if (!FLAC__metadata_object_vorbiscomment_set_comment(object, indx, entry, copy)) - return false; - entry = object->data.vorbis_comment.comments[indx]; - indx++; /* skip over replaced comment */ - if (all && indx < object->data.vorbis_comment.num_comments) { - i = vorbiscomment_find_entry_from_(object, indx, (const char *)entry.entry, field_name_length); - while (i >= 0) { - indx = (uint32_t)i; - if (!FLAC__metadata_object_vorbiscomment_delete_comment(object, indx)) - return false; - if (indx < object->data.vorbis_comment.num_comments) - i = vorbiscomment_find_entry_from_(object, indx, (const char *)entry.entry, field_name_length); - else - i = -1; - } - } - return true; - } - else - return FLAC__metadata_object_vorbiscomment_append_comment(object, entry, copy); - } -} - -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, uint32_t comment_num) -{ - FLAC__StreamMetadata_VorbisComment *vc; - - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); - FLAC__ASSERT(comment_num < object->data.vorbis_comment.num_comments); - - vc = &object->data.vorbis_comment; - - /* free the comment at comment_num */ - free(vc->comments[comment_num].entry); - - /* move all comments > comment_num backward one space */ - memmove(&vc->comments[comment_num], &vc->comments[comment_num+1], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(vc->num_comments-comment_num-1)); - vc->comments[vc->num_comments-1].length = 0; - vc->comments[vc->num_comments-1].entry = 0; - - return FLAC__metadata_object_vorbiscomment_resize_comments(object, vc->num_comments-1); -} - -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, const char *field_value) -{ - FLAC__ASSERT(entry != NULL); - FLAC__ASSERT(field_name != NULL); - FLAC__ASSERT(field_value != NULL); - - if (!FLAC__format_vorbiscomment_entry_name_is_legal(field_name)) - return false; - if (!FLAC__format_vorbiscomment_entry_value_is_legal((const FLAC__byte *)field_value, (uint32_t)(-1))) - return false; - - { - const size_t nn = strlen(field_name); - const size_t nv = strlen(field_value); - entry->length = nn + 1 /*=*/ + nv; - if ((entry->entry = safe_malloc_add_4op_(nn, /*+*/1, /*+*/nv, /*+*/1)) == NULL) - return false; - memcpy(entry->entry, field_name, nn); - entry->entry[nn] = '='; - memcpy(entry->entry+nn+1, field_value, nv); - entry->entry[entry->length] = '\0'; - } - - return true; -} - -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(const FLAC__StreamMetadata_VorbisComment_Entry entry, char **field_name, char **field_value) -{ - FLAC__ASSERT(entry.entry != NULL && entry.length > 0); - FLAC__ASSERT(field_name != NULL); - FLAC__ASSERT(field_value != NULL); - - if (!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length)) - return false; - - { - const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length); - const size_t nn = eq-entry.entry; - const size_t nv = entry.length-nn-1; /* -1 for the '=' */ - - if (eq == NULL) - return false; /* double protection */ - if ((*field_name = safe_malloc_add_2op_(nn, /*+*/1)) == NULL) - return false; - if ((*field_value = safe_malloc_add_2op_(nv, /*+*/1)) == NULL) { - free(*field_name); - return false; - } - memcpy(*field_name, entry.entry, nn); - memcpy(*field_value, entry.entry+nn+1, nv); - (*field_name)[nn] = '\0'; - (*field_value)[nv] = '\0'; - } - - return true; -} - -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry entry, const char *field_name, uint32_t field_name_length) -{ - FLAC__ASSERT(entry.entry != NULL && entry.length > 0); - { - const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length); - return (eq != NULL && (uint32_t)(eq-entry.entry) == field_name_length && FLAC__STRNCASECMP(field_name, (const char *)entry.entry, field_name_length) == 0); - } -} - -FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, uint32_t offset, const char *field_name) -{ - FLAC__ASSERT(field_name != NULL); - - return vorbiscomment_find_entry_from_(object, offset, field_name, strlen(field_name)); -} - -FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entry_matching(FLAC__StreamMetadata *object, const char *field_name) -{ - const uint32_t field_name_length = strlen(field_name); - uint32_t i; - - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); - - for (i = 0; i < object->data.vorbis_comment.num_comments; i++) { - if (FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) { - if (!FLAC__metadata_object_vorbiscomment_delete_comment(object, i)) - return -1; - else - return 1; - } - } - - return 0; -} - -FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__StreamMetadata *object, const char *field_name) -{ - FLAC__bool ok = true; - uint32_t matching = 0; - const uint32_t field_name_length = strlen(field_name); - int i; - - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); - - /* must delete from end to start otherwise it will interfere with our iteration */ - for (i = (int)object->data.vorbis_comment.num_comments - 1; ok && i >= 0; i--) { - if (FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) { - matching++; - ok &= FLAC__metadata_object_vorbiscomment_delete_comment(object, (uint32_t)i); - } - } - - return ok? (int)matching : -1; -} - -FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new(void) -{ - return calloc(1, sizeof(FLAC__StreamMetadata_CueSheet_Track)); -} - -FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_clone(const FLAC__StreamMetadata_CueSheet_Track *object) -{ - FLAC__StreamMetadata_CueSheet_Track *to; - - FLAC__ASSERT(object != NULL); - - if ((to = FLAC__metadata_object_cuesheet_track_new()) != NULL) { - if (!copy_track_(to, object)) { - FLAC__metadata_object_cuesheet_track_delete(to); - return 0; - } - } - - return to; -} - -void FLAC__metadata_object_cuesheet_track_delete_data(FLAC__StreamMetadata_CueSheet_Track *object) -{ - FLAC__ASSERT(object != NULL); - - if (object->indices != NULL) { - FLAC__ASSERT(object->num_indices > 0); - free(object->indices); - } -} - -FLAC_API void FLAC__metadata_object_cuesheet_track_delete(FLAC__StreamMetadata_CueSheet_Track *object) -{ - FLAC__metadata_object_cuesheet_track_delete_data(object); - free(object); -} - -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t new_num_indices) -{ - FLAC__StreamMetadata_CueSheet_Track *track; - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); - FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks); - - track = &object->data.cue_sheet.tracks[track_num]; - - if (track->indices == NULL) { - FLAC__ASSERT(track->num_indices == 0); - if (new_num_indices == 0) - return true; - else if ((track->indices = cuesheet_track_index_array_new_(new_num_indices)) == NULL) - return false; - } - else { - const size_t old_size = track->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index); - const size_t new_size = new_num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index); - - /* overflow check */ - if (new_num_indices > UINT32_MAX / sizeof(FLAC__StreamMetadata_CueSheet_Index)) - return false; - - FLAC__ASSERT(track->num_indices > 0); - - if (new_size == 0) { - free(track->indices); - track->indices = 0; - } - else if ((track->indices = safe_realloc_(track->indices, new_size)) == NULL) - return false; - - /* if growing, zero all the lengths/pointers of new elements */ - if (new_size > old_size) - memset(track->indices + track->num_indices, 0, new_size - old_size); - } - - track->num_indices = new_num_indices; - - cuesheet_calculate_length_(object); - return true; -} - -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num, FLAC__StreamMetadata_CueSheet_Index indx) -{ - FLAC__StreamMetadata_CueSheet_Track *track; - - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); - FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks); - FLAC__ASSERT(index_num <= object->data.cue_sheet.tracks[track_num].num_indices); - - track = &object->data.cue_sheet.tracks[track_num]; - - if (!FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices+1)) - return false; - - /* move all indices >= index_num forward one space */ - memmove(&track->indices[index_num+1], &track->indices[index_num], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(track->num_indices-1-index_num)); - - track->indices[index_num] = indx; - cuesheet_calculate_length_(object); - return true; -} - -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num) -{ - FLAC__StreamMetadata_CueSheet_Index indx; - memset(&indx, 0, sizeof(indx)); - return FLAC__metadata_object_cuesheet_track_insert_index(object, track_num, index_num, indx); -} - -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num) -{ - FLAC__StreamMetadata_CueSheet_Track *track; - - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); - FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks); - FLAC__ASSERT(index_num < object->data.cue_sheet.tracks[track_num].num_indices); - - track = &object->data.cue_sheet.tracks[track_num]; - - /* move all indices > index_num backward one space */ - memmove(&track->indices[index_num], &track->indices[index_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(track->num_indices-index_num-1)); - - FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices-1); - cuesheet_calculate_length_(object); - return true; -} - -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, uint32_t new_num_tracks) -{ - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); - - if (object->data.cue_sheet.tracks == NULL) { - FLAC__ASSERT(object->data.cue_sheet.num_tracks == 0); - if (new_num_tracks == 0) - return true; - else if ((object->data.cue_sheet.tracks = cuesheet_track_array_new_(new_num_tracks)) == NULL) - return false; - } - else { - const size_t old_size = object->data.cue_sheet.num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track); - const size_t new_size = new_num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track); - - /* overflow check */ - if (new_num_tracks > UINT32_MAX / sizeof(FLAC__StreamMetadata_CueSheet_Track)) - return false; - - FLAC__ASSERT(object->data.cue_sheet.num_tracks > 0); - - /* if shrinking, free the truncated entries */ - if (new_num_tracks < object->data.cue_sheet.num_tracks) { - uint32_t i; - for (i = new_num_tracks; i < object->data.cue_sheet.num_tracks; i++) - free(object->data.cue_sheet.tracks[i].indices); - } - - if (new_size == 0) { - free(object->data.cue_sheet.tracks); - object->data.cue_sheet.tracks = 0; - } - else if ((object->data.cue_sheet.tracks = safe_realloc_(object->data.cue_sheet.tracks, new_size)) == NULL) - return false; - - /* if growing, zero all the lengths/pointers of new elements */ - if (new_size > old_size) - memset(object->data.cue_sheet.tracks + object->data.cue_sheet.num_tracks, 0, new_size - old_size); - } - - object->data.cue_sheet.num_tracks = new_num_tracks; - - cuesheet_calculate_length_(object); - return true; -} - -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadata *object, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy) -{ - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks); - - return cuesheet_set_track_(object, object->data.cue_sheet.tracks + track_num, track, copy); -} - -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy) -{ - FLAC__StreamMetadata_CueSheet *cs; - - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); - FLAC__ASSERT(track_num <= object->data.cue_sheet.num_tracks); - - cs = &object->data.cue_sheet; - - if (!FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks+1)) - return false; - - /* move all tracks >= track_num forward one space */ - memmove(&cs->tracks[track_num+1], &cs->tracks[track_num], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-1-track_num)); - cs->tracks[track_num].num_indices = 0; - cs->tracks[track_num].indices = 0; - - return FLAC__metadata_object_cuesheet_set_track(object, track_num, track, copy); -} - -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, uint32_t track_num) -{ - FLAC__StreamMetadata_CueSheet_Track track; - memset(&track, 0, sizeof(track)); - return FLAC__metadata_object_cuesheet_insert_track(object, track_num, &track, /*copy=*/false); -} - -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, uint32_t track_num) -{ - FLAC__StreamMetadata_CueSheet *cs; - - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); - FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks); - - cs = &object->data.cue_sheet; - - /* free the track at track_num */ - free(cs->tracks[track_num].indices); - - /* move all tracks > track_num backward one space */ - memmove(&cs->tracks[track_num], &cs->tracks[track_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-track_num-1)); - cs->tracks[cs->num_tracks-1].num_indices = 0; - cs->tracks[cs->num_tracks-1].indices = 0; - - return FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks-1); -} - -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_is_legal(const FLAC__StreamMetadata *object, FLAC__bool check_cd_da_subset, const char **violation) -{ - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); - - return FLAC__format_cuesheet_is_legal(&object->data.cue_sheet, check_cd_da_subset, violation); -} - -static FLAC__uint64 get_index_01_offset_(const FLAC__StreamMetadata_CueSheet *cs, uint32_t track) -{ - if (track >= (cs->num_tracks-1) || cs->tracks[track].num_indices < 1) - return 0; - else if (cs->tracks[track].indices[0].number == 1) - return cs->tracks[track].indices[0].offset + cs->tracks[track].offset + cs->lead_in; - else if (cs->tracks[track].num_indices < 2) - return 0; - else if (cs->tracks[track].indices[1].number == 1) - return cs->tracks[track].indices[1].offset + cs->tracks[track].offset + cs->lead_in; - else - return 0; -} - -static FLAC__uint32 cddb_add_digits_(FLAC__uint32 x) -{ - FLAC__uint32 n = 0; - while (x) { - n += (x%10); - x /= 10; - } - return n; -} - -/*@@@@add to tests*/ -FLAC_API FLAC__uint32 FLAC__metadata_object_cuesheet_calculate_cddb_id(const FLAC__StreamMetadata *object) -{ - const FLAC__StreamMetadata_CueSheet *cs; - - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); - - cs = &object->data.cue_sheet; - - if (cs->num_tracks < 2) /* need at least one real track and the lead-out track */ - return 0; - - { - FLAC__uint32 i, length, sum = 0; - for (i = 0; i < (cs->num_tracks-1); i++) /* -1 to avoid counting the lead-out */ - sum += cddb_add_digits_((FLAC__uint32)(get_index_01_offset_(cs, i) / 44100)); - length = (FLAC__uint32)((cs->tracks[cs->num_tracks-1].offset+cs->lead_in) / 44100) - (FLAC__uint32)(get_index_01_offset_(cs, 0) / 44100); - - return (sum % 0xFF) << 24 | length << 8 | (FLAC__uint32)(cs->num_tracks-1); - } -} - -FLAC_API FLAC__bool FLAC__metadata_object_picture_set_mime_type(FLAC__StreamMetadata *object, char *mime_type, FLAC__bool copy) -{ - char *old; - size_t old_length, new_length; - - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE); - FLAC__ASSERT(mime_type != NULL); - - old = object->data.picture.mime_type; - old_length = old? strlen(old) : 0; - new_length = strlen(mime_type); - - /* do the copy first so that if we fail we leave the object untouched */ - if (copy) { - if (new_length >= SIZE_MAX) /* overflow check */ - return false; - if (!copy_bytes_((FLAC__byte**)(&object->data.picture.mime_type), (FLAC__byte*)mime_type, new_length+1)) - return false; - } - else { - object->data.picture.mime_type = mime_type; - } - - free(old); - - object->length -= old_length; - object->length += new_length; - return true; -} - -FLAC_API FLAC__bool FLAC__metadata_object_picture_set_description(FLAC__StreamMetadata *object, FLAC__byte *description, FLAC__bool copy) -{ - FLAC__byte *old; - size_t old_length, new_length; - - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE); - FLAC__ASSERT(description != NULL); - - old = object->data.picture.description; - old_length = old? strlen((const char *)old) : 0; - new_length = strlen((const char *)description); - - /* do the copy first so that if we fail we leave the object untouched */ - if (copy) { - if (new_length >= SIZE_MAX) /* overflow check */ - return false; - if (!copy_bytes_(&object->data.picture.description, description, new_length+1)) - return false; - } - else { - object->data.picture.description = description; - } - - free(old); - - object->length -= old_length; - object->length += new_length; - return true; -} - -FLAC_API FLAC__bool FLAC__metadata_object_picture_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, FLAC__uint32 length, FLAC__bool copy) -{ - FLAC__byte *old; - - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE); - FLAC__ASSERT((data != NULL && length > 0) || (data == NULL && length == 0 && copy == false)); - - old = object->data.picture.data; - - /* do the copy first so that if we fail we leave the object untouched */ - if (copy) { - if (!copy_bytes_(&object->data.picture.data, data, length)) - return false; - } - else { - object->data.picture.data = data; - } - - free(old); - - object->length -= object->data.picture.data_length; - object->data.picture.data_length = length; - object->length += length; - return true; -} - -FLAC_API FLAC__bool FLAC__metadata_object_picture_is_legal(const FLAC__StreamMetadata *object, const char **violation) -{ - FLAC__ASSERT(object != NULL); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE); - - return FLAC__format_picture_is_legal(&object->data.picture, violation); -} diff --git a/lib/flac/src/stream_decoder.c b/lib/flac/src/stream_decoder.c deleted file mode 100644 index db1f320..0000000 --- a/lib/flac/src/stream_decoder.c +++ /dev/null @@ -1,3404 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include /* for malloc() */ -#include /* for memset/memcpy() */ -#include /* for stat() */ -#include /* for off_t */ -#include "share/compat.h" -#include "FLAC/assert.h" -#include "share/alloc.h" -#include "protected/stream_decoder.h" -#include "private/bitreader.h" -#include "private/bitmath.h" -#include "private/cpu.h" -#include "private/crc.h" -#include "private/fixed.h" -#include "private/format.h" -#include "private/lpc.h" -#include "private/md5.h" -#include "private/memory.h" -#include "private/macros.h" - - -/* technically this should be in an "export.c" but this is convenient enough */ -FLAC_API int FLAC_API_SUPPORTS_OGG_FLAC = FLAC__HAS_OGG; - - -/*********************************************************************** - * - * Private static data - * - ***********************************************************************/ - -static const FLAC__byte ID3V2_TAG_[3] = { 'I', 'D', '3' }; - -/*********************************************************************** - * - * Private class method prototypes - * - ***********************************************************************/ - -static void set_defaults_(FLAC__StreamDecoder *decoder); -static FILE *get_binary_stdin_(void); -static FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, uint32_t size, uint32_t channels); -static FLAC__bool has_id_filtered_(FLAC__StreamDecoder *decoder, FLAC__byte *id); -static FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder); -static FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder); -static FLAC__bool read_metadata_streaminfo_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, uint32_t length); -static FLAC__bool read_metadata_seektable_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, uint32_t length); -static FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj, uint32_t length); -static FLAC__bool read_metadata_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_CueSheet *obj); -static FLAC__bool read_metadata_picture_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_Picture *obj); -static FLAC__bool skip_id3v2_tag_(FLAC__StreamDecoder *decoder); -static FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder); -static FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FLAC__bool do_full_decode); -static FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder); -static FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode); -static FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode); -static FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, const uint32_t order, FLAC__bool do_full_decode); -static FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, const uint32_t order, FLAC__bool do_full_decode); -static FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode); -static FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, uint32_t predictor_order, uint32_t partition_order, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, FLAC__int32 *residual, FLAC__bool is_extended); -static FLAC__bool read_zero_padding_(FLAC__StreamDecoder *decoder); -static FLAC__bool read_callback_(FLAC__byte buffer[], size_t *bytes, void *client_data); -#if FLAC__HAS_OGG -static FLAC__StreamDecoderReadStatus read_callback_ogg_aspect_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes); -static FLAC__OggDecoderAspectReadStatus read_callback_proxy_(const void *void_decoder, FLAC__byte buffer[], size_t *bytes, void *client_data); -#endif -static FLAC__StreamDecoderWriteStatus write_audio_frame_to_client_(FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]); -static void send_error_to_client_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status); -static FLAC__bool seek_to_absolute_sample_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample); -#if FLAC__HAS_OGG -static FLAC__bool seek_to_absolute_sample_ogg_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample); -#endif -static FLAC__StreamDecoderReadStatus file_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data); -static FLAC__StreamDecoderSeekStatus file_seek_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data); -static FLAC__StreamDecoderTellStatus file_tell_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data); -static FLAC__StreamDecoderLengthStatus file_length_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data); -static FLAC__bool file_eof_callback_(const FLAC__StreamDecoder *decoder, void *client_data); - -/*********************************************************************** - * - * Private class data - * - ***********************************************************************/ - -typedef struct FLAC__StreamDecoderPrivate { - FLAC__bool is_ogg; - FLAC__StreamDecoderReadCallback read_callback; - FLAC__StreamDecoderSeekCallback seek_callback; - FLAC__StreamDecoderTellCallback tell_callback; - FLAC__StreamDecoderLengthCallback length_callback; - FLAC__StreamDecoderEofCallback eof_callback; - FLAC__StreamDecoderWriteCallback write_callback; - FLAC__StreamDecoderMetadataCallback metadata_callback; - FLAC__StreamDecoderErrorCallback error_callback; - /* generic 32-bit datapath: */ - void (*local_lpc_restore_signal)(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]); - /* generic 64-bit datapath: */ - void (*local_lpc_restore_signal_64bit)(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]); - /* for use when the signal is <= 16 bits-per-sample, or <= 15 bits-per-sample on a side channel (which requires 1 extra bit): */ - void (*local_lpc_restore_signal_16bit)(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]); - void *client_data; - FILE *file; /* only used if FLAC__stream_decoder_init_file()/FLAC__stream_decoder_init_file() called, else NULL */ - FLAC__BitReader *input; - FLAC__int32 *output[FLAC__MAX_CHANNELS]; - FLAC__int32 *residual[FLAC__MAX_CHANNELS]; /* WATCHOUT: these are the aligned pointers; the real pointers that should be free()'d are residual_unaligned[] below */ - FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents[FLAC__MAX_CHANNELS]; - uint32_t output_capacity, output_channels; - FLAC__uint32 fixed_block_size, next_fixed_block_size; - FLAC__uint64 samples_decoded; - FLAC__bool has_stream_info, has_seek_table; - FLAC__StreamMetadata stream_info; - FLAC__StreamMetadata seek_table; - FLAC__bool metadata_filter[128]; /* MAGIC number 128 == total number of metadata block types == 1 << 7 */ - FLAC__byte *metadata_filter_ids; - size_t metadata_filter_ids_count, metadata_filter_ids_capacity; /* units for both are IDs, not bytes */ - FLAC__Frame frame; - FLAC__bool cached; /* true if there is a byte in lookahead */ - FLAC__CPUInfo cpuinfo; - FLAC__byte header_warmup[2]; /* contains the sync code and reserved bits */ - FLAC__byte lookahead; /* temp storage when we need to look ahead one byte in the stream */ - /* unaligned (original) pointers to allocated data */ - FLAC__int32 *residual_unaligned[FLAC__MAX_CHANNELS]; - FLAC__bool do_md5_checking; /* initially gets protected_->md5_checking but is turned off after a seek or if the metadata has a zero MD5 */ - FLAC__bool internal_reset_hack; /* used only during init() so we can call reset to set up the decoder without rewinding the input */ - FLAC__bool is_seeking; - FLAC__MD5Context md5context; - FLAC__byte computed_md5sum[16]; /* this is the sum we computed from the decoded data */ - /* (the rest of these are only used for seeking) */ - FLAC__Frame last_frame; /* holds the info of the last frame we seeked to */ - FLAC__uint64 first_frame_offset; /* hint to the seek routine of where in the stream the first audio frame starts */ - FLAC__uint64 target_sample; - uint32_t unparseable_frame_count; /* used to tell whether we're decoding a future version of FLAC or just got a bad sync */ - FLAC__bool got_a_frame; /* hack needed in Ogg FLAC seek routine to check when process_single() actually writes a frame */ -} FLAC__StreamDecoderPrivate; - -/*********************************************************************** - * - * Public static class data - * - ***********************************************************************/ - -FLAC_API const char * const FLAC__StreamDecoderStateString[] = { - "FLAC__STREAM_DECODER_SEARCH_FOR_METADATA", - "FLAC__STREAM_DECODER_READ_METADATA", - "FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC", - "FLAC__STREAM_DECODER_READ_FRAME", - "FLAC__STREAM_DECODER_END_OF_STREAM", - "FLAC__STREAM_DECODER_OGG_ERROR", - "FLAC__STREAM_DECODER_SEEK_ERROR", - "FLAC__STREAM_DECODER_ABORTED", - "FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR", - "FLAC__STREAM_DECODER_UNINITIALIZED" -}; - -FLAC_API const char * const FLAC__StreamDecoderInitStatusString[] = { - "FLAC__STREAM_DECODER_INIT_STATUS_OK", - "FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER", - "FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS", - "FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR", - "FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE", - "FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED" -}; - -FLAC_API const char * const FLAC__StreamDecoderReadStatusString[] = { - "FLAC__STREAM_DECODER_READ_STATUS_CONTINUE", - "FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM", - "FLAC__STREAM_DECODER_READ_STATUS_ABORT" -}; - -FLAC_API const char * const FLAC__StreamDecoderSeekStatusString[] = { - "FLAC__STREAM_DECODER_SEEK_STATUS_OK", - "FLAC__STREAM_DECODER_SEEK_STATUS_ERROR", - "FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED" -}; - -FLAC_API const char * const FLAC__StreamDecoderTellStatusString[] = { - "FLAC__STREAM_DECODER_TELL_STATUS_OK", - "FLAC__STREAM_DECODER_TELL_STATUS_ERROR", - "FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED" -}; - -FLAC_API const char * const FLAC__StreamDecoderLengthStatusString[] = { - "FLAC__STREAM_DECODER_LENGTH_STATUS_OK", - "FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR", - "FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED" -}; - -FLAC_API const char * const FLAC__StreamDecoderWriteStatusString[] = { - "FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE", - "FLAC__STREAM_DECODER_WRITE_STATUS_ABORT" -}; - -FLAC_API const char * const FLAC__StreamDecoderErrorStatusString[] = { - "FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC", - "FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER", - "FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH", - "FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM" -}; - -/*********************************************************************** - * - * Class constructor/destructor - * - ***********************************************************************/ -FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new(void) -{ - FLAC__StreamDecoder *decoder; - uint32_t i; - - FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */ - - decoder = calloc(1, sizeof(FLAC__StreamDecoder)); - if(decoder == 0) { - return 0; - } - - decoder->protected_ = calloc(1, sizeof(FLAC__StreamDecoderProtected)); - if(decoder->protected_ == 0) { - free(decoder); - return 0; - } - - decoder->private_ = calloc(1, sizeof(FLAC__StreamDecoderPrivate)); - if(decoder->private_ == 0) { - free(decoder->protected_); - free(decoder); - return 0; - } - - decoder->private_->input = FLAC__bitreader_new(); - if(decoder->private_->input == 0) { - free(decoder->private_); - free(decoder->protected_); - free(decoder); - return 0; - } - - decoder->private_->metadata_filter_ids_capacity = 16; - if(0 == (decoder->private_->metadata_filter_ids = malloc((FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) * decoder->private_->metadata_filter_ids_capacity))) { - FLAC__bitreader_delete(decoder->private_->input); - free(decoder->private_); - free(decoder->protected_); - free(decoder); - return 0; - } - - for(i = 0; i < FLAC__MAX_CHANNELS; i++) { - decoder->private_->output[i] = 0; - decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0; - } - - decoder->private_->output_capacity = 0; - decoder->private_->output_channels = 0; - decoder->private_->has_seek_table = false; - - for(i = 0; i < FLAC__MAX_CHANNELS; i++) - FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&decoder->private_->partitioned_rice_contents[i]); - - decoder->private_->file = 0; - - set_defaults_(decoder); - - decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED; - - return decoder; -} - -FLAC_API void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder) -{ - uint32_t i; - - if (decoder == NULL) - return ; - - FLAC__ASSERT(0 != decoder->protected_); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->private_->input); - - (void)FLAC__stream_decoder_finish(decoder); - - if(0 != decoder->private_->metadata_filter_ids) - free(decoder->private_->metadata_filter_ids); - - FLAC__bitreader_delete(decoder->private_->input); - - for(i = 0; i < FLAC__MAX_CHANNELS; i++) - FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&decoder->private_->partitioned_rice_contents[i]); - - free(decoder->private_); - free(decoder->protected_); - free(decoder); -} - -/*********************************************************************** - * - * Public class methods - * - ***********************************************************************/ - -static FLAC__StreamDecoderInitStatus init_stream_internal_( - FLAC__StreamDecoder *decoder, - FLAC__StreamDecoderReadCallback read_callback, - FLAC__StreamDecoderSeekCallback seek_callback, - FLAC__StreamDecoderTellCallback tell_callback, - FLAC__StreamDecoderLengthCallback length_callback, - FLAC__StreamDecoderEofCallback eof_callback, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data, - FLAC__bool is_ogg -) -{ - FLAC__ASSERT(0 != decoder); - - if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) - return FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED; - - if(FLAC__HAS_OGG == 0 && is_ogg) - return FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER; - - if( - 0 == read_callback || - 0 == write_callback || - 0 == error_callback || - (seek_callback && (0 == tell_callback || 0 == length_callback || 0 == eof_callback)) - ) - return FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS; - -#if FLAC__HAS_OGG - decoder->private_->is_ogg = is_ogg; - if(is_ogg && !FLAC__ogg_decoder_aspect_init(&decoder->protected_->ogg_decoder_aspect)) - return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE; -#endif - - /* - * get the CPU info and set the function pointers - */ - FLAC__cpu_info(&decoder->private_->cpuinfo); - /* first default to the non-asm routines */ - decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal; - decoder->private_->local_lpc_restore_signal_64bit = FLAC__lpc_restore_signal_wide; - decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal; - /* now override with asm where appropriate */ -#ifndef FLAC__NO_ASM - if(decoder->private_->cpuinfo.use_asm) { -#ifdef FLAC__CPU_IA32 - FLAC__ASSERT(decoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_IA32); -#ifdef FLAC__HAS_NASM - decoder->private_->local_lpc_restore_signal_64bit = FLAC__lpc_restore_signal_wide_asm_ia32; /* OPT_IA32: was really necessary for GCC < 4.9 */ - if (decoder->private_->cpuinfo.x86.mmx) { - decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal_asm_ia32; - decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal_asm_ia32_mmx; - } - else { - decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal_asm_ia32; - decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal_asm_ia32; - } -#endif -#if FLAC__HAS_X86INTRIN && ! defined FLAC__INTEGER_ONLY_LIBRARY -# if defined FLAC__SSE4_1_SUPPORTED - if (decoder->private_->cpuinfo.x86.sse41) { -# if !defined FLAC__HAS_NASM /* these are not undoubtedly faster than their MMX ASM counterparts */ - decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal_intrin_sse41; - decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal_16_intrin_sse41; -# endif - decoder->private_->local_lpc_restore_signal_64bit = FLAC__lpc_restore_signal_wide_intrin_sse41; - } -# endif -#endif -#elif defined FLAC__CPU_X86_64 - FLAC__ASSERT(decoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_X86_64); - /* No useful SSE optimizations yet */ -#endif - } -#endif - - /* from here on, errors are fatal */ - - if(!FLAC__bitreader_init(decoder->private_->input, read_callback_, decoder)) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR; - } - - decoder->private_->read_callback = read_callback; - decoder->private_->seek_callback = seek_callback; - decoder->private_->tell_callback = tell_callback; - decoder->private_->length_callback = length_callback; - decoder->private_->eof_callback = eof_callback; - decoder->private_->write_callback = write_callback; - decoder->private_->metadata_callback = metadata_callback; - decoder->private_->error_callback = error_callback; - decoder->private_->client_data = client_data; - decoder->private_->fixed_block_size = decoder->private_->next_fixed_block_size = 0; - decoder->private_->samples_decoded = 0; - decoder->private_->has_stream_info = false; - decoder->private_->cached = false; - - decoder->private_->do_md5_checking = decoder->protected_->md5_checking; - decoder->private_->is_seeking = false; - - decoder->private_->internal_reset_hack = true; /* so the following reset does not try to rewind the input */ - if(!FLAC__stream_decoder_reset(decoder)) { - /* above call sets the state for us */ - return FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR; - } - - return FLAC__STREAM_DECODER_INIT_STATUS_OK; -} - -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_stream( - FLAC__StreamDecoder *decoder, - FLAC__StreamDecoderReadCallback read_callback, - FLAC__StreamDecoderSeekCallback seek_callback, - FLAC__StreamDecoderTellCallback tell_callback, - FLAC__StreamDecoderLengthCallback length_callback, - FLAC__StreamDecoderEofCallback eof_callback, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -) -{ - return init_stream_internal_( - decoder, - read_callback, - seek_callback, - tell_callback, - length_callback, - eof_callback, - write_callback, - metadata_callback, - error_callback, - client_data, - /*is_ogg=*/false - ); -} - -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_stream( - FLAC__StreamDecoder *decoder, - FLAC__StreamDecoderReadCallback read_callback, - FLAC__StreamDecoderSeekCallback seek_callback, - FLAC__StreamDecoderTellCallback tell_callback, - FLAC__StreamDecoderLengthCallback length_callback, - FLAC__StreamDecoderEofCallback eof_callback, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -) -{ - return init_stream_internal_( - decoder, - read_callback, - seek_callback, - tell_callback, - length_callback, - eof_callback, - write_callback, - metadata_callback, - error_callback, - client_data, - /*is_ogg=*/true - ); -} - -static FLAC__StreamDecoderInitStatus init_FILE_internal_( - FLAC__StreamDecoder *decoder, - FILE *file, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data, - FLAC__bool is_ogg -) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != file); - - if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) - return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED; - - if(0 == write_callback || 0 == error_callback) - return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS; - - /* - * To make sure that our file does not go unclosed after an error, we - * must assign the FILE pointer before any further error can occur in - * this routine. - */ - if(file == stdin) - file = get_binary_stdin_(); /* just to be safe */ - - decoder->private_->file = file; - - return init_stream_internal_( - decoder, - file_read_callback_, - decoder->private_->file == stdin? 0: file_seek_callback_, - decoder->private_->file == stdin? 0: file_tell_callback_, - decoder->private_->file == stdin? 0: file_length_callback_, - file_eof_callback_, - write_callback, - metadata_callback, - error_callback, - client_data, - is_ogg - ); -} - -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_FILE( - FLAC__StreamDecoder *decoder, - FILE *file, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -) -{ - return init_FILE_internal_(decoder, file, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/false); -} - -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_FILE( - FLAC__StreamDecoder *decoder, - FILE *file, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -) -{ - return init_FILE_internal_(decoder, file, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/true); -} - -static FLAC__StreamDecoderInitStatus init_file_internal_( - FLAC__StreamDecoder *decoder, - const char *filename, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data, - FLAC__bool is_ogg -) -{ - FILE *file; - - FLAC__ASSERT(0 != decoder); - - /* - * To make sure that our file does not go unclosed after an error, we - * have to do the same entrance checks here that are later performed - * in FLAC__stream_decoder_init_FILE() before the FILE* is assigned. - */ - if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) - return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED; - - if(0 == write_callback || 0 == error_callback) - return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS; - - file = filename? flac_fopen(filename, "rb") : stdin; - - if(0 == file) - return FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE; - - return init_FILE_internal_(decoder, file, write_callback, metadata_callback, error_callback, client_data, is_ogg); -} - -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_file( - FLAC__StreamDecoder *decoder, - const char *filename, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -) -{ - return init_file_internal_(decoder, filename, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/false); -} - -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_file( - FLAC__StreamDecoder *decoder, - const char *filename, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -) -{ - return init_file_internal_(decoder, filename, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/true); -} - -FLAC_API FLAC__bool FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder) -{ - FLAC__bool md5_failed = false; - uint32_t i; - - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - - if(decoder->protected_->state == FLAC__STREAM_DECODER_UNINITIALIZED) - return true; - - /* see the comment in FLAC__stream_decoder_reset() as to why we - * always call FLAC__MD5Final() - */ - FLAC__MD5Final(decoder->private_->computed_md5sum, &decoder->private_->md5context); - - free(decoder->private_->seek_table.data.seek_table.points); - decoder->private_->seek_table.data.seek_table.points = 0; - decoder->private_->has_seek_table = false; - - FLAC__bitreader_free(decoder->private_->input); - for(i = 0; i < FLAC__MAX_CHANNELS; i++) { - /* WATCHOUT: - * FLAC__lpc_restore_signal_asm_ia32_mmx() and ..._intrin_sseN() - * require that the output arrays have a buffer of up to 3 zeroes - * in front (at negative indices) for alignment purposes; - * we use 4 to keep the data well-aligned. - */ - if(0 != decoder->private_->output[i]) { - free(decoder->private_->output[i]-4); - decoder->private_->output[i] = 0; - } - if(0 != decoder->private_->residual_unaligned[i]) { - free(decoder->private_->residual_unaligned[i]); - decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0; - } - } - decoder->private_->output_capacity = 0; - decoder->private_->output_channels = 0; - -#if FLAC__HAS_OGG - if(decoder->private_->is_ogg) - FLAC__ogg_decoder_aspect_finish(&decoder->protected_->ogg_decoder_aspect); -#endif - - if(0 != decoder->private_->file) { - if(decoder->private_->file != stdin) - fclose(decoder->private_->file); - decoder->private_->file = 0; - } - - if(decoder->private_->do_md5_checking) { - if(memcmp(decoder->private_->stream_info.data.stream_info.md5sum, decoder->private_->computed_md5sum, 16)) - md5_failed = true; - } - decoder->private_->is_seeking = false; - - set_defaults_(decoder); - - decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED; - - return !md5_failed; -} - -FLAC_API FLAC__bool FLAC__stream_decoder_set_ogg_serial_number(FLAC__StreamDecoder *decoder, long value) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) - return false; -#if FLAC__HAS_OGG - /* can't check decoder->private_->is_ogg since that's not set until init time */ - FLAC__ogg_decoder_aspect_set_serial_number(&decoder->protected_->ogg_decoder_aspect, value); - return true; -#else - (void)value; - return false; -#endif -} - -FLAC_API FLAC__bool FLAC__stream_decoder_set_md5_checking(FLAC__StreamDecoder *decoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) - return false; - decoder->protected_->md5_checking = value; - return true; -} - -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond(FLAC__StreamDecoder *decoder, FLAC__MetadataType type) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - FLAC__ASSERT((uint32_t)type <= FLAC__MAX_METADATA_TYPE_CODE); - /* double protection */ - if((uint32_t)type > FLAC__MAX_METADATA_TYPE_CODE) - return false; - if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) - return false; - decoder->private_->metadata_filter[type] = true; - if(type == FLAC__METADATA_TYPE_APPLICATION) - decoder->private_->metadata_filter_ids_count = 0; - return true; -} - -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - FLAC__ASSERT(0 != id); - if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) - return false; - - if(decoder->private_->metadata_filter[FLAC__METADATA_TYPE_APPLICATION]) - return true; - - FLAC__ASSERT(0 != decoder->private_->metadata_filter_ids); - - if(decoder->private_->metadata_filter_ids_count == decoder->private_->metadata_filter_ids_capacity) { - if(0 == (decoder->private_->metadata_filter_ids = safe_realloc_mul_2op_(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity, /*times*/2))) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - decoder->private_->metadata_filter_ids_capacity *= 2; - } - - memcpy(decoder->private_->metadata_filter_ids + decoder->private_->metadata_filter_ids_count * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8)); - decoder->private_->metadata_filter_ids_count++; - - return true; -} - -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_all(FLAC__StreamDecoder *decoder) -{ - uint32_t i; - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) - return false; - for(i = 0; i < sizeof(decoder->private_->metadata_filter) / sizeof(decoder->private_->metadata_filter[0]); i++) - decoder->private_->metadata_filter[i] = true; - decoder->private_->metadata_filter_ids_count = 0; - return true; -} - -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore(FLAC__StreamDecoder *decoder, FLAC__MetadataType type) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - FLAC__ASSERT((uint32_t)type <= FLAC__MAX_METADATA_TYPE_CODE); - /* double protection */ - if((uint32_t)type > FLAC__MAX_METADATA_TYPE_CODE) - return false; - if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) - return false; - decoder->private_->metadata_filter[type] = false; - if(type == FLAC__METADATA_TYPE_APPLICATION) - decoder->private_->metadata_filter_ids_count = 0; - return true; -} - -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - FLAC__ASSERT(0 != id); - if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) - return false; - - if(!decoder->private_->metadata_filter[FLAC__METADATA_TYPE_APPLICATION]) - return true; - - FLAC__ASSERT(0 != decoder->private_->metadata_filter_ids); - - if(decoder->private_->metadata_filter_ids_count == decoder->private_->metadata_filter_ids_capacity) { - if(0 == (decoder->private_->metadata_filter_ids = safe_realloc_mul_2op_(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity, /*times*/2))) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - decoder->private_->metadata_filter_ids_capacity *= 2; - } - - memcpy(decoder->private_->metadata_filter_ids + decoder->private_->metadata_filter_ids_count * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8)); - decoder->private_->metadata_filter_ids_count++; - - return true; -} - -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_all(FLAC__StreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) - return false; - memset(decoder->private_->metadata_filter, 0, sizeof(decoder->private_->metadata_filter)); - decoder->private_->metadata_filter_ids_count = 0; - return true; -} - -FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__StreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - return decoder->protected_->state; -} - -FLAC_API const char *FLAC__stream_decoder_get_resolved_state_string(const FLAC__StreamDecoder *decoder) -{ - return FLAC__StreamDecoderStateString[decoder->protected_->state]; -} - -FLAC_API FLAC__bool FLAC__stream_decoder_get_md5_checking(const FLAC__StreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - return decoder->protected_->md5_checking; -} - -FLAC_API FLAC__uint64 FLAC__stream_decoder_get_total_samples(const FLAC__StreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - return decoder->private_->has_stream_info? decoder->private_->stream_info.data.stream_info.total_samples : 0; -} - -FLAC_API uint32_t FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - return decoder->protected_->channels; -} - -FLAC_API FLAC__ChannelAssignment FLAC__stream_decoder_get_channel_assignment(const FLAC__StreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - return decoder->protected_->channel_assignment; -} - -FLAC_API uint32_t FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - return decoder->protected_->bits_per_sample; -} - -FLAC_API uint32_t FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - return decoder->protected_->sample_rate; -} - -FLAC_API uint32_t FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - return decoder->protected_->blocksize; -} - -FLAC_API FLAC__bool FLAC__stream_decoder_get_decode_position(const FLAC__StreamDecoder *decoder, FLAC__uint64 *position) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != position); - - if(FLAC__HAS_OGG && decoder->private_->is_ogg) - return false; - - if(0 == decoder->private_->tell_callback) - return false; - if(decoder->private_->tell_callback(decoder, position, decoder->private_->client_data) != FLAC__STREAM_DECODER_TELL_STATUS_OK) - return false; - /* should never happen since all FLAC frames and metadata blocks are byte aligned, but check just in case */ - if(!FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)) - return false; - FLAC__ASSERT(*position >= FLAC__stream_decoder_get_input_bytes_unconsumed(decoder)); - *position -= FLAC__stream_decoder_get_input_bytes_unconsumed(decoder); - return true; -} - -FLAC_API FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - - if(!decoder->private_->internal_reset_hack && decoder->protected_->state == FLAC__STREAM_DECODER_UNINITIALIZED) - return false; - - decoder->private_->samples_decoded = 0; - decoder->private_->do_md5_checking = false; - -#if FLAC__HAS_OGG - if(decoder->private_->is_ogg) - FLAC__ogg_decoder_aspect_flush(&decoder->protected_->ogg_decoder_aspect); -#endif - - if(!FLAC__bitreader_clear(decoder->private_->input)) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - - return true; -} - -FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - - if(!FLAC__stream_decoder_flush(decoder)) { - /* above call sets the state for us */ - return false; - } - -#if FLAC__HAS_OGG - /*@@@ could go in !internal_reset_hack block below */ - if(decoder->private_->is_ogg) - FLAC__ogg_decoder_aspect_reset(&decoder->protected_->ogg_decoder_aspect); -#endif - - /* Rewind if necessary. If FLAC__stream_decoder_init() is calling us, - * (internal_reset_hack) don't try to rewind since we are already at - * the beginning of the stream and don't want to fail if the input is - * not seekable. - */ - if(!decoder->private_->internal_reset_hack) { - if(decoder->private_->file == stdin) - return false; /* can't rewind stdin, reset fails */ - if(decoder->private_->seek_callback && decoder->private_->seek_callback(decoder, 0, decoder->private_->client_data) == FLAC__STREAM_DECODER_SEEK_STATUS_ERROR) - return false; /* seekable and seek fails, reset fails */ - } - else - decoder->private_->internal_reset_hack = false; - - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_METADATA; - - decoder->private_->has_stream_info = false; - - free(decoder->private_->seek_table.data.seek_table.points); - decoder->private_->seek_table.data.seek_table.points = 0; - decoder->private_->has_seek_table = false; - - decoder->private_->do_md5_checking = decoder->protected_->md5_checking; - /* - * This goes in reset() and not flush() because according to the spec, a - * fixed-blocksize stream must stay that way through the whole stream. - */ - decoder->private_->fixed_block_size = decoder->private_->next_fixed_block_size = 0; - - /* We initialize the FLAC__MD5Context even though we may never use it. This - * is because md5 checking may be turned on to start and then turned off if - * a seek occurs. So we init the context here and finalize it in - * FLAC__stream_decoder_finish() to make sure things are always cleaned up - * properly. - */ - FLAC__MD5Init(&decoder->private_->md5context); - - decoder->private_->first_frame_offset = 0; - decoder->private_->unparseable_frame_count = 0; - - return true; -} - -FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *decoder) -{ - FLAC__bool got_a_frame; - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - - while(1) { - switch(decoder->protected_->state) { - case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA: - if(!find_metadata_(decoder)) - return false; /* above function sets the status for us */ - break; - case FLAC__STREAM_DECODER_READ_METADATA: - if(!read_metadata_(decoder)) - return false; /* above function sets the status for us */ - else - return true; - case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC: - if(!frame_sync_(decoder)) - return true; /* above function sets the status for us */ - break; - case FLAC__STREAM_DECODER_READ_FRAME: - if(!read_frame_(decoder, &got_a_frame, /*do_full_decode=*/true)) - return false; /* above function sets the status for us */ - if(got_a_frame) - return true; /* above function sets the status for us */ - break; - case FLAC__STREAM_DECODER_END_OF_STREAM: - case FLAC__STREAM_DECODER_ABORTED: - return true; - default: - FLAC__ASSERT(0); - return false; - } - } -} - -FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__StreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - - while(1) { - switch(decoder->protected_->state) { - case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA: - if(!find_metadata_(decoder)) - return false; /* above function sets the status for us */ - break; - case FLAC__STREAM_DECODER_READ_METADATA: - if(!read_metadata_(decoder)) - return false; /* above function sets the status for us */ - break; - case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC: - case FLAC__STREAM_DECODER_READ_FRAME: - case FLAC__STREAM_DECODER_END_OF_STREAM: - case FLAC__STREAM_DECODER_ABORTED: - return true; - default: - FLAC__ASSERT(0); - return false; - } - } -} - -FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder) -{ - FLAC__bool dummy; - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - - while(1) { - switch(decoder->protected_->state) { - case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA: - if(!find_metadata_(decoder)) - return false; /* above function sets the status for us */ - break; - case FLAC__STREAM_DECODER_READ_METADATA: - if(!read_metadata_(decoder)) - return false; /* above function sets the status for us */ - break; - case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC: - if(!frame_sync_(decoder)) - return true; /* above function sets the status for us */ - break; - case FLAC__STREAM_DECODER_READ_FRAME: - if(!read_frame_(decoder, &dummy, /*do_full_decode=*/true)) - return false; /* above function sets the status for us */ - break; - case FLAC__STREAM_DECODER_END_OF_STREAM: - case FLAC__STREAM_DECODER_ABORTED: - return true; - default: - FLAC__ASSERT(0); - return false; - } - } -} - -FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder *decoder) -{ - FLAC__bool got_a_frame; - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - - while(1) { - switch(decoder->protected_->state) { - case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA: - case FLAC__STREAM_DECODER_READ_METADATA: - return false; /* above function sets the status for us */ - case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC: - if(!frame_sync_(decoder)) - return true; /* above function sets the status for us */ - break; - case FLAC__STREAM_DECODER_READ_FRAME: - if(!read_frame_(decoder, &got_a_frame, /*do_full_decode=*/false)) - return false; /* above function sets the status for us */ - if(got_a_frame) - return true; /* above function sets the status for us */ - break; - case FLAC__STREAM_DECODER_END_OF_STREAM: - case FLAC__STREAM_DECODER_ABORTED: - return true; - default: - FLAC__ASSERT(0); - return false; - } - } -} - -FLAC_API FLAC__bool FLAC__stream_decoder_seek_absolute(FLAC__StreamDecoder *decoder, FLAC__uint64 sample) -{ - FLAC__uint64 length; - - FLAC__ASSERT(0 != decoder); - - if( - decoder->protected_->state != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA && - decoder->protected_->state != FLAC__STREAM_DECODER_READ_METADATA && - decoder->protected_->state != FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC && - decoder->protected_->state != FLAC__STREAM_DECODER_READ_FRAME && - decoder->protected_->state != FLAC__STREAM_DECODER_END_OF_STREAM - ) - return false; - - if(0 == decoder->private_->seek_callback) - return false; - - FLAC__ASSERT(decoder->private_->seek_callback); - FLAC__ASSERT(decoder->private_->tell_callback); - FLAC__ASSERT(decoder->private_->length_callback); - FLAC__ASSERT(decoder->private_->eof_callback); - - if(FLAC__stream_decoder_get_total_samples(decoder) > 0 && sample >= FLAC__stream_decoder_get_total_samples(decoder)) - return false; - - decoder->private_->is_seeking = true; - - /* turn off md5 checking if a seek is attempted */ - decoder->private_->do_md5_checking = false; - - /* get the file length (currently our algorithm needs to know the length so it's also an error to get FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED) */ - if(decoder->private_->length_callback(decoder, &length, decoder->private_->client_data) != FLAC__STREAM_DECODER_LENGTH_STATUS_OK) { - decoder->private_->is_seeking = false; - return false; - } - - /* if we haven't finished processing the metadata yet, do that so we have the STREAMINFO, SEEK_TABLE, and first_frame_offset */ - if( - decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_METADATA || - decoder->protected_->state == FLAC__STREAM_DECODER_READ_METADATA - ) { - if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder)) { - /* above call sets the state for us */ - decoder->private_->is_seeking = false; - return false; - } - /* check this again in case we didn't know total_samples the first time */ - if(FLAC__stream_decoder_get_total_samples(decoder) > 0 && sample >= FLAC__stream_decoder_get_total_samples(decoder)) { - decoder->private_->is_seeking = false; - return false; - } - } - - { - const FLAC__bool ok = -#if FLAC__HAS_OGG - decoder->private_->is_ogg? - seek_to_absolute_sample_ogg_(decoder, length, sample) : -#endif - seek_to_absolute_sample_(decoder, length, sample) - ; - decoder->private_->is_seeking = false; - return ok; - } -} - -/*********************************************************************** - * - * Protected class methods - * - ***********************************************************************/ - -uint32_t FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); - FLAC__ASSERT(!(FLAC__bitreader_get_input_bits_unconsumed(decoder->private_->input) & 7)); - return FLAC__bitreader_get_input_bits_unconsumed(decoder->private_->input) / 8; -} - -/*********************************************************************** - * - * Private class methods - * - ***********************************************************************/ - -void set_defaults_(FLAC__StreamDecoder *decoder) -{ - decoder->private_->is_ogg = false; - decoder->private_->read_callback = 0; - decoder->private_->seek_callback = 0; - decoder->private_->tell_callback = 0; - decoder->private_->length_callback = 0; - decoder->private_->eof_callback = 0; - decoder->private_->write_callback = 0; - decoder->private_->metadata_callback = 0; - decoder->private_->error_callback = 0; - decoder->private_->client_data = 0; - - memset(decoder->private_->metadata_filter, 0, sizeof(decoder->private_->metadata_filter)); - decoder->private_->metadata_filter[FLAC__METADATA_TYPE_STREAMINFO] = true; - decoder->private_->metadata_filter_ids_count = 0; - - decoder->protected_->md5_checking = false; - -#if FLAC__HAS_OGG - FLAC__ogg_decoder_aspect_set_defaults(&decoder->protected_->ogg_decoder_aspect); -#endif -} - -/* - * This will forcibly set stdin to binary mode (for OSes that require it) - */ -FILE *get_binary_stdin_(void) -{ - /* if something breaks here it is probably due to the presence or - * absence of an underscore before the identifiers 'setmode', - * 'fileno', and/or 'O_BINARY'; check your system header files. - */ -#if defined _MSC_VER || defined __MINGW32__ - _setmode(_fileno(stdin), _O_BINARY); -#elif defined __EMX__ - setmode(fileno(stdin), O_BINARY); -#endif - - return stdin; -} - -FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, uint32_t size, uint32_t channels) -{ - uint32_t i; - FLAC__int32 *tmp; - - if(size <= decoder->private_->output_capacity && channels <= decoder->private_->output_channels) - return true; - - /* simply using realloc() is not practical because the number of channels may change mid-stream */ - - for(i = 0; i < FLAC__MAX_CHANNELS; i++) { - if(0 != decoder->private_->output[i]) { - free(decoder->private_->output[i]-4); - decoder->private_->output[i] = 0; - } - if(0 != decoder->private_->residual_unaligned[i]) { - free(decoder->private_->residual_unaligned[i]); - decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0; - } - } - - for(i = 0; i < channels; i++) { - /* WATCHOUT: - * FLAC__lpc_restore_signal_asm_ia32_mmx() and ..._intrin_sseN() - * require that the output arrays have a buffer of up to 3 zeroes - * in front (at negative indices) for alignment purposes; - * we use 4 to keep the data well-aligned. - */ - tmp = safe_malloc_muladd2_(sizeof(FLAC__int32), /*times (*/size, /*+*/4/*)*/); - if(tmp == 0) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - memset(tmp, 0, sizeof(FLAC__int32)*4); - decoder->private_->output[i] = tmp + 4; - - if(!FLAC__memory_alloc_aligned_int32_array(size, &decoder->private_->residual_unaligned[i], &decoder->private_->residual[i])) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - } - - decoder->private_->output_capacity = size; - decoder->private_->output_channels = channels; - - return true; -} - -FLAC__bool has_id_filtered_(FLAC__StreamDecoder *decoder, FLAC__byte *id) -{ - size_t i; - - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - - for(i = 0; i < decoder->private_->metadata_filter_ids_count; i++) - if(0 == memcmp(decoder->private_->metadata_filter_ids + i * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8))) - return true; - - return false; -} - -FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder) -{ - FLAC__uint32 x; - uint32_t i, id; - FLAC__bool first = true; - - FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); - - for(i = id = 0; i < 4; ) { - if(decoder->private_->cached) { - x = (FLAC__uint32)decoder->private_->lookahead; - decoder->private_->cached = false; - } - else { - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) - return false; /* read_callback_ sets the state for us */ - } - if(x == FLAC__STREAM_SYNC_STRING[i]) { - first = true; - i++; - id = 0; - continue; - } - - if(id >= 3) - return false; - - if(x == ID3V2_TAG_[id]) { - id++; - i = 0; - if(id == 3) { - if(!skip_id3v2_tag_(decoder)) - return false; /* skip_id3v2_tag_ sets the state for us */ - } - continue; - } - id = 0; - if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */ - decoder->private_->header_warmup[0] = (FLAC__byte)x; - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) - return false; /* read_callback_ sets the state for us */ - - /* we have to check if we just read two 0xff's in a row; the second may actually be the beginning of the sync code */ - /* else we have to check if the second byte is the end of a sync code */ - if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */ - decoder->private_->lookahead = (FLAC__byte)x; - decoder->private_->cached = true; - } - else if(x >> 1 == 0x7c) { /* MAGIC NUMBER for the last 6 sync bits and reserved 7th bit */ - decoder->private_->header_warmup[1] = (FLAC__byte)x; - decoder->protected_->state = FLAC__STREAM_DECODER_READ_FRAME; - return true; - } - } - i = 0; - if(first) { - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); - first = false; - } - } - - decoder->protected_->state = FLAC__STREAM_DECODER_READ_METADATA; - return true; -} - -FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder) -{ - FLAC__bool is_last; - FLAC__uint32 i, x, type, length; - - FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); - - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_IS_LAST_LEN)) - return false; /* read_callback_ sets the state for us */ - is_last = x? true : false; - - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &type, FLAC__STREAM_METADATA_TYPE_LEN)) - return false; /* read_callback_ sets the state for us */ - - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &length, FLAC__STREAM_METADATA_LENGTH_LEN)) - return false; /* read_callback_ sets the state for us */ - - if(type == FLAC__METADATA_TYPE_STREAMINFO) { - if(!read_metadata_streaminfo_(decoder, is_last, length)) - return false; - - decoder->private_->has_stream_info = true; - if(0 == memcmp(decoder->private_->stream_info.data.stream_info.md5sum, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16)) - decoder->private_->do_md5_checking = false; - if(!decoder->private_->is_seeking && decoder->private_->metadata_filter[FLAC__METADATA_TYPE_STREAMINFO] && decoder->private_->metadata_callback) - decoder->private_->metadata_callback(decoder, &decoder->private_->stream_info, decoder->private_->client_data); - } - else if(type == FLAC__METADATA_TYPE_SEEKTABLE) { - /* just in case we already have a seek table, and reading the next one fails: */ - decoder->private_->has_seek_table = false; - - if(!read_metadata_seektable_(decoder, is_last, length)) - return false; - - decoder->private_->has_seek_table = true; - if(!decoder->private_->is_seeking && decoder->private_->metadata_filter[FLAC__METADATA_TYPE_SEEKTABLE] && decoder->private_->metadata_callback) - decoder->private_->metadata_callback(decoder, &decoder->private_->seek_table, decoder->private_->client_data); - } - else { - FLAC__bool skip_it = !decoder->private_->metadata_filter[type]; - uint32_t real_length = length; - FLAC__StreamMetadata block; - - memset(&block, 0, sizeof(block)); - block.is_last = is_last; - block.type = (FLAC__MetadataType)type; - block.length = length; - - if(type == FLAC__METADATA_TYPE_APPLICATION) { - if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8)) - return false; /* read_callback_ sets the state for us */ - - if(real_length < FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) { /* underflow check */ - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;/*@@@@@@ maybe wrong error? need to resync?*/ - return false; - } - - real_length -= FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8; - - if(decoder->private_->metadata_filter_ids_count > 0 && has_id_filtered_(decoder, block.data.application.id)) - skip_it = !skip_it; - } - - if(skip_it) { - if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, real_length)) - return false; /* read_callback_ sets the state for us */ - } - else { - FLAC__bool ok = true; - switch(type) { - case FLAC__METADATA_TYPE_PADDING: - /* skip the padding bytes */ - if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, real_length)) - ok = false; /* read_callback_ sets the state for us */ - break; - case FLAC__METADATA_TYPE_APPLICATION: - /* remember, we read the ID already */ - if(real_length > 0) { - if(0 == (block.data.application.data = malloc(real_length))) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - ok = false; - } - else if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.application.data, real_length)) - ok = false; /* read_callback_ sets the state for us */ - } - else - block.data.application.data = 0; - break; - case FLAC__METADATA_TYPE_VORBIS_COMMENT: - if(!read_metadata_vorbiscomment_(decoder, &block.data.vorbis_comment, real_length)) - ok = false; - break; - case FLAC__METADATA_TYPE_CUESHEET: - if(!read_metadata_cuesheet_(decoder, &block.data.cue_sheet)) - ok = false; - break; - case FLAC__METADATA_TYPE_PICTURE: - if(!read_metadata_picture_(decoder, &block.data.picture)) - ok = false; - break; - case FLAC__METADATA_TYPE_STREAMINFO: - case FLAC__METADATA_TYPE_SEEKTABLE: - FLAC__ASSERT(0); - break; - default: - if(real_length > 0) { - if(0 == (block.data.unknown.data = malloc(real_length))) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - ok = false; - } - else if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.unknown.data, real_length)) - ok = false; /* read_callback_ sets the state for us */ - } - else - block.data.unknown.data = 0; - break; - } - if(ok && !decoder->private_->is_seeking && decoder->private_->metadata_callback) - decoder->private_->metadata_callback(decoder, &block, decoder->private_->client_data); - - /* now we have to free any malloc()ed data in the block */ - switch(type) { - case FLAC__METADATA_TYPE_PADDING: - break; - case FLAC__METADATA_TYPE_APPLICATION: - if(0 != block.data.application.data) - free(block.data.application.data); - break; - case FLAC__METADATA_TYPE_VORBIS_COMMENT: - if(0 != block.data.vorbis_comment.vendor_string.entry) - free(block.data.vorbis_comment.vendor_string.entry); - if(block.data.vorbis_comment.num_comments > 0) - for(i = 0; i < block.data.vorbis_comment.num_comments; i++) - if(0 != block.data.vorbis_comment.comments[i].entry) - free(block.data.vorbis_comment.comments[i].entry); - if(0 != block.data.vorbis_comment.comments) - free(block.data.vorbis_comment.comments); - break; - case FLAC__METADATA_TYPE_CUESHEET: - if(block.data.cue_sheet.num_tracks > 0) - for(i = 0; i < block.data.cue_sheet.num_tracks; i++) - if(0 != block.data.cue_sheet.tracks[i].indices) - free(block.data.cue_sheet.tracks[i].indices); - if(0 != block.data.cue_sheet.tracks) - free(block.data.cue_sheet.tracks); - break; - case FLAC__METADATA_TYPE_PICTURE: - if(0 != block.data.picture.mime_type) - free(block.data.picture.mime_type); - if(0 != block.data.picture.description) - free(block.data.picture.description); - if(0 != block.data.picture.data) - free(block.data.picture.data); - break; - case FLAC__METADATA_TYPE_STREAMINFO: - case FLAC__METADATA_TYPE_SEEKTABLE: - FLAC__ASSERT(0); - default: - if(0 != block.data.unknown.data) - free(block.data.unknown.data); - break; - } - - if(!ok) /* anything that unsets "ok" should also make sure decoder->protected_->state is updated */ - return false; - } - } - - if(is_last) { - /* if this fails, it's OK, it's just a hint for the seek routine */ - if(!FLAC__stream_decoder_get_decode_position(decoder, &decoder->private_->first_frame_offset)) - decoder->private_->first_frame_offset = 0; - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - } - - return true; -} - -FLAC__bool read_metadata_streaminfo_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, uint32_t length) -{ - FLAC__uint32 x; - uint32_t bits, used_bits = 0; - - FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); - - decoder->private_->stream_info.type = FLAC__METADATA_TYPE_STREAMINFO; - decoder->private_->stream_info.is_last = is_last; - decoder->private_->stream_info.length = length; - - bits = FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN; - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, bits)) - return false; /* read_callback_ sets the state for us */ - decoder->private_->stream_info.data.stream_info.min_blocksize = x; - used_bits += bits; - - bits = FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN; - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN)) - return false; /* read_callback_ sets the state for us */ - decoder->private_->stream_info.data.stream_info.max_blocksize = x; - used_bits += bits; - - bits = FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN; - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN)) - return false; /* read_callback_ sets the state for us */ - decoder->private_->stream_info.data.stream_info.min_framesize = x; - used_bits += bits; - - bits = FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN; - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN)) - return false; /* read_callback_ sets the state for us */ - decoder->private_->stream_info.data.stream_info.max_framesize = x; - used_bits += bits; - - bits = FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN; - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN)) - return false; /* read_callback_ sets the state for us */ - decoder->private_->stream_info.data.stream_info.sample_rate = x; - used_bits += bits; - - bits = FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN; - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN)) - return false; /* read_callback_ sets the state for us */ - decoder->private_->stream_info.data.stream_info.channels = x+1; - used_bits += bits; - - bits = FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN; - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN)) - return false; /* read_callback_ sets the state for us */ - decoder->private_->stream_info.data.stream_info.bits_per_sample = x+1; - used_bits += bits; - - bits = FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN; - if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &decoder->private_->stream_info.data.stream_info.total_samples, FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN)) - return false; /* read_callback_ sets the state for us */ - used_bits += bits; - - if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, decoder->private_->stream_info.data.stream_info.md5sum, 16)) - return false; /* read_callback_ sets the state for us */ - used_bits += 16*8; - - /* skip the rest of the block */ - FLAC__ASSERT(used_bits % 8 == 0); - length -= (used_bits / 8); - if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, length)) - return false; /* read_callback_ sets the state for us */ - - return true; -} - -FLAC__bool read_metadata_seektable_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, uint32_t length) -{ - FLAC__uint32 i, x; - FLAC__uint64 xx; - - FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); - - decoder->private_->seek_table.type = FLAC__METADATA_TYPE_SEEKTABLE; - decoder->private_->seek_table.is_last = is_last; - decoder->private_->seek_table.length = length; - - decoder->private_->seek_table.data.seek_table.num_points = length / FLAC__STREAM_METADATA_SEEKPOINT_LENGTH; - - /* use realloc since we may pass through here several times (e.g. after seeking) */ - if(0 == (decoder->private_->seek_table.data.seek_table.points = safe_realloc_mul_2op_(decoder->private_->seek_table.data.seek_table.points, decoder->private_->seek_table.data.seek_table.num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint)))) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - for(i = 0; i < decoder->private_->seek_table.data.seek_table.num_points; i++) { - if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &xx, FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN)) - return false; /* read_callback_ sets the state for us */ - decoder->private_->seek_table.data.seek_table.points[i].sample_number = xx; - - if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &xx, FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN)) - return false; /* read_callback_ sets the state for us */ - decoder->private_->seek_table.data.seek_table.points[i].stream_offset = xx; - - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN)) - return false; /* read_callback_ sets the state for us */ - decoder->private_->seek_table.data.seek_table.points[i].frame_samples = x; - } - length -= (decoder->private_->seek_table.data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH); - /* if there is a partial point left, skip over it */ - if(length > 0) { - /*@@@ do a send_error_to_client_() here? there's an argument for either way */ - if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, length)) - return false; /* read_callback_ sets the state for us */ - } - - return true; -} - -FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj, uint32_t length) -{ - FLAC__uint32 i; - - FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); - - /* read vendor string */ - if (length >= 8) { - length -= 8; /* vendor string length + num comments entries alone take 8 bytes */ - FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN == 32); - if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->vendor_string.length)) - return false; /* read_callback_ sets the state for us */ - if (obj->vendor_string.length > 0) { - if (length < obj->vendor_string.length) { - obj->vendor_string.length = 0; - obj->vendor_string.entry = 0; - goto skip; - } - else - length -= obj->vendor_string.length; - if (0 == (obj->vendor_string.entry = safe_malloc_add_2op_(obj->vendor_string.length, /*+*/1))) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - if (!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->vendor_string.entry, obj->vendor_string.length)) - return false; /* read_callback_ sets the state for us */ - obj->vendor_string.entry[obj->vendor_string.length] = '\0'; - } - else - obj->vendor_string.entry = 0; - - /* read num comments */ - FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN == 32); - if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->num_comments)) - return false; /* read_callback_ sets the state for us */ - - /* read comments */ - if (obj->num_comments > 100000) { - /* Possibly malicious file. */ - obj->num_comments = 0; - return false; - } - if (obj->num_comments > 0) { - if (0 == (obj->comments = safe_malloc_mul_2op_p(obj->num_comments, /*times*/sizeof(FLAC__StreamMetadata_VorbisComment_Entry)))) { - obj->num_comments = 0; - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - for (i = 0; i < obj->num_comments; i++) { - /* Initialize here just to make sure. */ - obj->comments[i].length = 0; - obj->comments[i].entry = 0; - - FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN == 32); - if (length < 4) { - obj->num_comments = i; - goto skip; - } - else - length -= 4; - if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->comments[i].length)) { - obj->num_comments = i; - return false; /* read_callback_ sets the state for us */ - } - if (obj->comments[i].length > 0) { - if (length < obj->comments[i].length) { - obj->num_comments = i; - goto skip; - } - else - length -= obj->comments[i].length; - if (0 == (obj->comments[i].entry = safe_malloc_add_2op_(obj->comments[i].length, /*+*/1))) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - obj->num_comments = i; - return false; - } - memset (obj->comments[i].entry, 0, obj->comments[i].length) ; - if (!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->comments[i].entry, obj->comments[i].length)) { - /* Current i-th entry is bad, so we delete it. */ - free (obj->comments[i].entry) ; - obj->comments[i].entry = NULL ; - obj->num_comments = i; - goto skip; - } - obj->comments[i].entry[obj->comments[i].length] = '\0'; - } - else - obj->comments[i].entry = 0; - } - } - } - - skip: - if (length > 0) { - /* length > 0 can only happen on files with invalid data in comments */ - if(obj->num_comments < 1) { - free(obj->comments); - obj->comments = NULL; - } - if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, length)) - return false; /* read_callback_ sets the state for us */ - } - - return true; -} - -FLAC__bool read_metadata_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_CueSheet *obj) -{ - FLAC__uint32 i, j, x; - - FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); - - memset(obj, 0, sizeof(FLAC__StreamMetadata_CueSheet)); - - FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0); - if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)obj->media_catalog_number, FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN/8)) - return false; /* read_callback_ sets the state for us */ - - if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &obj->lead_in, FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN)) - return false; /* read_callback_ sets the state for us */ - - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN)) - return false; /* read_callback_ sets the state for us */ - obj->is_cd = x? true : false; - - if(!FLAC__bitreader_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN)) - return false; /* read_callback_ sets the state for us */ - - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN)) - return false; /* read_callback_ sets the state for us */ - obj->num_tracks = x; - - if(obj->num_tracks > 0) { - if(0 == (obj->tracks = safe_calloc_(obj->num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track)))) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - for(i = 0; i < obj->num_tracks; i++) { - FLAC__StreamMetadata_CueSheet_Track *track = &obj->tracks[i]; - if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &track->offset, FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN)) - return false; /* read_callback_ sets the state for us */ - - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN)) - return false; /* read_callback_ sets the state for us */ - track->number = (FLAC__byte)x; - - FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0); - if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)track->isrc, FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN/8)) - return false; /* read_callback_ sets the state for us */ - - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN)) - return false; /* read_callback_ sets the state for us */ - track->type = x; - - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN)) - return false; /* read_callback_ sets the state for us */ - track->pre_emphasis = x; - - if(!FLAC__bitreader_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN)) - return false; /* read_callback_ sets the state for us */ - - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN)) - return false; /* read_callback_ sets the state for us */ - track->num_indices = (FLAC__byte)x; - - if(track->num_indices > 0) { - if(0 == (track->indices = safe_calloc_(track->num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index)))) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - for(j = 0; j < track->num_indices; j++) { - FLAC__StreamMetadata_CueSheet_Index *indx = &track->indices[j]; - if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &indx->offset, FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN)) - return false; /* read_callback_ sets the state for us */ - - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN)) - return false; /* read_callback_ sets the state for us */ - indx->number = (FLAC__byte)x; - - if(!FLAC__bitreader_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN)) - return false; /* read_callback_ sets the state for us */ - } - } - } - } - - return true; -} - -FLAC__bool read_metadata_picture_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_Picture *obj) -{ - FLAC__uint32 x; - - FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); - - /* read type */ - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_PICTURE_TYPE_LEN)) - return false; /* read_callback_ sets the state for us */ - obj->type = x; - - /* read MIME type */ - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN)) - return false; /* read_callback_ sets the state for us */ - if(0 == (obj->mime_type = safe_malloc_add_2op_(x, /*+*/1))) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - if(x > 0) { - if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)obj->mime_type, x)) - return false; /* read_callback_ sets the state for us */ - } - obj->mime_type[x] = '\0'; - - /* read description */ - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN)) - return false; /* read_callback_ sets the state for us */ - if(0 == (obj->description = safe_malloc_add_2op_(x, /*+*/1))) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - if(x > 0) { - if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->description, x)) - return false; /* read_callback_ sets the state for us */ - } - obj->description[x] = '\0'; - - /* read width */ - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->width, FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN)) - return false; /* read_callback_ sets the state for us */ - - /* read height */ - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->height, FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN)) - return false; /* read_callback_ sets the state for us */ - - /* read depth */ - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->depth, FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN)) - return false; /* read_callback_ sets the state for us */ - - /* read colors */ - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->colors, FLAC__STREAM_METADATA_PICTURE_COLORS_LEN)) - return false; /* read_callback_ sets the state for us */ - - /* read data */ - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &(obj->data_length), FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN)) - return false; /* read_callback_ sets the state for us */ - if(0 == (obj->data = safe_malloc_(obj->data_length))) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - if(obj->data_length > 0) { - if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->data, obj->data_length)) - return false; /* read_callback_ sets the state for us */ - } - - return true; -} - -FLAC__bool skip_id3v2_tag_(FLAC__StreamDecoder *decoder) -{ - FLAC__uint32 x; - uint32_t i, skip; - - /* skip the version and flags bytes */ - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 24)) - return false; /* read_callback_ sets the state for us */ - /* get the size (in bytes) to skip */ - skip = 0; - for(i = 0; i < 4; i++) { - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) - return false; /* read_callback_ sets the state for us */ - skip <<= 7; - skip |= (x & 0x7f); - } - /* skip the rest of the tag */ - if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, skip)) - return false; /* read_callback_ sets the state for us */ - return true; -} - -FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder) -{ - FLAC__uint32 x; - FLAC__bool first = true; - - /* If we know the total number of samples in the stream, stop if we've read that many. */ - /* This will stop us, for example, from wasting time trying to sync on an ID3V1 tag. */ - if(FLAC__stream_decoder_get_total_samples(decoder) > 0) { - if(decoder->private_->samples_decoded >= FLAC__stream_decoder_get_total_samples(decoder)) { - decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM; - return true; - } - } - - /* make sure we're byte aligned */ - if(!FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)) { - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__bitreader_bits_left_for_byte_alignment(decoder->private_->input))) - return false; /* read_callback_ sets the state for us */ - } - - while(1) { - if(decoder->private_->cached) { - x = (FLAC__uint32)decoder->private_->lookahead; - decoder->private_->cached = false; - } - else { - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) - return false; /* read_callback_ sets the state for us */ - } - if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */ - decoder->private_->header_warmup[0] = (FLAC__byte)x; - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) - return false; /* read_callback_ sets the state for us */ - - /* we have to check if we just read two 0xff's in a row; the second may actually be the beginning of the sync code */ - /* else we have to check if the second byte is the end of a sync code */ - if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */ - decoder->private_->lookahead = (FLAC__byte)x; - decoder->private_->cached = true; - } - else if(x >> 1 == 0x7c) { /* MAGIC NUMBER for the last 6 sync bits and reserved 7th bit */ - decoder->private_->header_warmup[1] = (FLAC__byte)x; - decoder->protected_->state = FLAC__STREAM_DECODER_READ_FRAME; - return true; - } - } - if(first) { - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); - first = false; - } - } - - return true; -} - -FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FLAC__bool do_full_decode) -{ - uint32_t channel; - uint32_t i; - FLAC__int32 mid, side; - uint32_t frame_crc; /* the one we calculate from the input stream */ - FLAC__uint32 x; - - *got_a_frame = false; - - /* init the CRC */ - frame_crc = 0; - frame_crc = FLAC__CRC16_UPDATE(decoder->private_->header_warmup[0], frame_crc); - frame_crc = FLAC__CRC16_UPDATE(decoder->private_->header_warmup[1], frame_crc); - FLAC__bitreader_reset_read_crc16(decoder->private_->input, (FLAC__uint16)frame_crc); - - if(!read_frame_header_(decoder)) - return false; - if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means we didn't sync on a valid header */ - return true; - if(!allocate_output_(decoder, decoder->private_->frame.header.blocksize, decoder->private_->frame.header.channels)) - return false; - for(channel = 0; channel < decoder->private_->frame.header.channels; channel++) { - /* - * first figure the correct bits-per-sample of the subframe - */ - uint32_t bps = decoder->private_->frame.header.bits_per_sample; - switch(decoder->private_->frame.header.channel_assignment) { - case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT: - /* no adjustment needed */ - break; - case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE: - FLAC__ASSERT(decoder->private_->frame.header.channels == 2); - if(channel == 1) - bps++; - break; - case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE: - FLAC__ASSERT(decoder->private_->frame.header.channels == 2); - if(channel == 0) - bps++; - break; - case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE: - FLAC__ASSERT(decoder->private_->frame.header.channels == 2); - if(channel == 1) - bps++; - break; - default: - FLAC__ASSERT(0); - } - /* - * now read it - */ - if(!read_subframe_(decoder, channel, bps, do_full_decode)) - return false; - if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption */ - return true; - } - if(!read_zero_padding_(decoder)) - return false; - if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption (i.e. "zero bits" were not all zeroes) */ - return true; - - /* - * Read the frame CRC-16 from the footer and check - */ - frame_crc = FLAC__bitreader_get_read_crc16(decoder->private_->input); - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__FRAME_FOOTER_CRC_LEN)) - return false; /* read_callback_ sets the state for us */ - if(frame_crc == x) { - if(do_full_decode) { - /* Undo any special channel coding */ - switch(decoder->private_->frame.header.channel_assignment) { - case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT: - /* do nothing */ - break; - case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE: - FLAC__ASSERT(decoder->private_->frame.header.channels == 2); - for(i = 0; i < decoder->private_->frame.header.blocksize; i++) - decoder->private_->output[1][i] = decoder->private_->output[0][i] - decoder->private_->output[1][i]; - break; - case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE: - FLAC__ASSERT(decoder->private_->frame.header.channels == 2); - for(i = 0; i < decoder->private_->frame.header.blocksize; i++) - decoder->private_->output[0][i] += decoder->private_->output[1][i]; - break; - case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE: - FLAC__ASSERT(decoder->private_->frame.header.channels == 2); - for(i = 0; i < decoder->private_->frame.header.blocksize; i++) { -#if 1 - mid = decoder->private_->output[0][i]; - side = decoder->private_->output[1][i]; - mid = ((uint32_t) mid) << 1; - mid |= (side & 1); /* i.e. if 'side' is odd... */ - decoder->private_->output[0][i] = (mid + side) >> 1; - decoder->private_->output[1][i] = (mid - side) >> 1; -#else - /* OPT: without 'side' temp variable */ - mid = (decoder->private_->output[0][i] << 1) | (decoder->private_->output[1][i] & 1); /* i.e. if 'side' is odd... */ - decoder->private_->output[0][i] = (mid + decoder->private_->output[1][i]) >> 1; - decoder->private_->output[1][i] = (mid - decoder->private_->output[1][i]) >> 1; -#endif - } - break; - default: - FLAC__ASSERT(0); - break; - } - } - } - else { - /* Bad frame, emit error and zero the output signal */ - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH); - if(do_full_decode) { - for(channel = 0; channel < decoder->private_->frame.header.channels; channel++) { - memset(decoder->private_->output[channel], 0, sizeof(FLAC__int32) * decoder->private_->frame.header.blocksize); - } - } - } - - *got_a_frame = true; - - /* we wait to update fixed_block_size until here, when we're sure we've got a proper frame and hence a correct blocksize */ - if(decoder->private_->next_fixed_block_size) - decoder->private_->fixed_block_size = decoder->private_->next_fixed_block_size; - - /* put the latest values into the public section of the decoder instance */ - decoder->protected_->channels = decoder->private_->frame.header.channels; - decoder->protected_->channel_assignment = decoder->private_->frame.header.channel_assignment; - decoder->protected_->bits_per_sample = decoder->private_->frame.header.bits_per_sample; - decoder->protected_->sample_rate = decoder->private_->frame.header.sample_rate; - decoder->protected_->blocksize = decoder->private_->frame.header.blocksize; - - FLAC__ASSERT(decoder->private_->frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); - decoder->private_->samples_decoded = decoder->private_->frame.header.number.sample_number + decoder->private_->frame.header.blocksize; - - /* write it */ - if(do_full_decode) { - if(write_audio_frame_to_client_(decoder, &decoder->private_->frame, (const FLAC__int32 * const *)decoder->private_->output) != FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE) { - decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED; - return false; - } - } - - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; -} - -FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder) -{ - FLAC__uint32 x; - FLAC__uint64 xx; - uint32_t i, blocksize_hint = 0, sample_rate_hint = 0; - FLAC__byte crc8, raw_header[16]; /* MAGIC NUMBER based on the maximum frame header size, including CRC */ - uint32_t raw_header_len; - FLAC__bool is_unparseable = false; - - FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); - - /* init the raw header with the saved bits from synchronization */ - raw_header[0] = decoder->private_->header_warmup[0]; - raw_header[1] = decoder->private_->header_warmup[1]; - raw_header_len = 2; - - /* check to make sure that reserved bit is 0 */ - if(raw_header[1] & 0x02) /* MAGIC NUMBER */ - is_unparseable = true; - - /* - * Note that along the way as we read the header, we look for a sync - * code inside. If we find one it would indicate that our original - * sync was bad since there cannot be a sync code in a valid header. - * - * Three kinds of things can go wrong when reading the frame header: - * 1) We may have sync'ed incorrectly and not landed on a frame header. - * If we don't find a sync code, it can end up looking like we read - * a valid but unparseable header, until getting to the frame header - * CRC. Even then we could get a false positive on the CRC. - * 2) We may have sync'ed correctly but on an unparseable frame (from a - * future encoder). - * 3) We may be on a damaged frame which appears valid but unparseable. - * - * For all these reasons, we try and read a complete frame header as - * long as it seems valid, even if unparseable, up until the frame - * header CRC. - */ - - /* - * read in the raw header as bytes so we can CRC it, and parse it on the way - */ - for(i = 0; i < 2; i++) { - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) - return false; /* read_callback_ sets the state for us */ - if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */ - /* if we get here it means our original sync was erroneous since the sync code cannot appear in the header */ - decoder->private_->lookahead = (FLAC__byte)x; - decoder->private_->cached = true; - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - raw_header[raw_header_len++] = (FLAC__byte)x; - } - - switch(x = raw_header[2] >> 4) { - case 0: - is_unparseable = true; - break; - case 1: - decoder->private_->frame.header.blocksize = 192; - break; - case 2: - case 3: - case 4: - case 5: - decoder->private_->frame.header.blocksize = 576 << (x-2); - break; - case 6: - case 7: - blocksize_hint = x; - break; - case 8: - case 9: - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: - decoder->private_->frame.header.blocksize = 256 << (x-8); - break; - default: - FLAC__ASSERT(0); - break; - } - - switch(x = raw_header[2] & 0x0f) { - case 0: - if(decoder->private_->has_stream_info) - decoder->private_->frame.header.sample_rate = decoder->private_->stream_info.data.stream_info.sample_rate; - else - is_unparseable = true; - break; - case 1: - decoder->private_->frame.header.sample_rate = 88200; - break; - case 2: - decoder->private_->frame.header.sample_rate = 176400; - break; - case 3: - decoder->private_->frame.header.sample_rate = 192000; - break; - case 4: - decoder->private_->frame.header.sample_rate = 8000; - break; - case 5: - decoder->private_->frame.header.sample_rate = 16000; - break; - case 6: - decoder->private_->frame.header.sample_rate = 22050; - break; - case 7: - decoder->private_->frame.header.sample_rate = 24000; - break; - case 8: - decoder->private_->frame.header.sample_rate = 32000; - break; - case 9: - decoder->private_->frame.header.sample_rate = 44100; - break; - case 10: - decoder->private_->frame.header.sample_rate = 48000; - break; - case 11: - decoder->private_->frame.header.sample_rate = 96000; - break; - case 12: - case 13: - case 14: - sample_rate_hint = x; - break; - case 15: - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - default: - FLAC__ASSERT(0); - } - - x = (uint32_t)(raw_header[3] >> 4); - if(x & 8) { - decoder->private_->frame.header.channels = 2; - switch(x & 7) { - case 0: - decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE; - break; - case 1: - decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE; - break; - case 2: - decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_MID_SIDE; - break; - default: - is_unparseable = true; - break; - } - } - else { - decoder->private_->frame.header.channels = (uint32_t)x + 1; - decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT; - } - - switch(x = (uint32_t)(raw_header[3] & 0x0e) >> 1) { - case 0: - if(decoder->private_->has_stream_info) - decoder->private_->frame.header.bits_per_sample = decoder->private_->stream_info.data.stream_info.bits_per_sample; - else - is_unparseable = true; - break; - case 1: - decoder->private_->frame.header.bits_per_sample = 8; - break; - case 2: - decoder->private_->frame.header.bits_per_sample = 12; - break; - case 4: - decoder->private_->frame.header.bits_per_sample = 16; - break; - case 5: - decoder->private_->frame.header.bits_per_sample = 20; - break; - case 6: - decoder->private_->frame.header.bits_per_sample = 24; - break; - case 3: - case 7: - is_unparseable = true; - break; - default: - FLAC__ASSERT(0); - break; - } - - /* check to make sure that reserved bit is 0 */ - if(raw_header[3] & 0x01) /* MAGIC NUMBER */ - is_unparseable = true; - - /* read the frame's starting sample number (or frame number as the case may be) */ - if( - raw_header[1] & 0x01 || - /*@@@ this clause is a concession to the old way of doing variable blocksize; the only known implementation is flake and can probably be removed without inconveniencing anyone */ - (decoder->private_->has_stream_info && decoder->private_->stream_info.data.stream_info.min_blocksize != decoder->private_->stream_info.data.stream_info.max_blocksize) - ) { /* variable blocksize */ - if(!FLAC__bitreader_read_utf8_uint64(decoder->private_->input, &xx, raw_header, &raw_header_len)) - return false; /* read_callback_ sets the state for us */ - if(xx == FLAC__U64L(0xffffffffffffffff)) { /* i.e. non-UTF8 code... */ - decoder->private_->lookahead = raw_header[raw_header_len-1]; /* back up as much as we can */ - decoder->private_->cached = true; - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - decoder->private_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER; - decoder->private_->frame.header.number.sample_number = xx; - } - else { /* fixed blocksize */ - if(!FLAC__bitreader_read_utf8_uint32(decoder->private_->input, &x, raw_header, &raw_header_len)) - return false; /* read_callback_ sets the state for us */ - if(x == 0xffffffff) { /* i.e. non-UTF8 code... */ - decoder->private_->lookahead = raw_header[raw_header_len-1]; /* back up as much as we can */ - decoder->private_->cached = true; - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - decoder->private_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER; - decoder->private_->frame.header.number.frame_number = x; - } - - if(blocksize_hint) { - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) - return false; /* read_callback_ sets the state for us */ - raw_header[raw_header_len++] = (FLAC__byte)x; - if(blocksize_hint == 7) { - FLAC__uint32 _x; - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &_x, 8)) - return false; /* read_callback_ sets the state for us */ - raw_header[raw_header_len++] = (FLAC__byte)_x; - x = (x << 8) | _x; - } - decoder->private_->frame.header.blocksize = x+1; - } - - if(sample_rate_hint) { - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) - return false; /* read_callback_ sets the state for us */ - raw_header[raw_header_len++] = (FLAC__byte)x; - if(sample_rate_hint != 12) { - FLAC__uint32 _x; - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &_x, 8)) - return false; /* read_callback_ sets the state for us */ - raw_header[raw_header_len++] = (FLAC__byte)_x; - x = (x << 8) | _x; - } - if(sample_rate_hint == 12) - decoder->private_->frame.header.sample_rate = x*1000; - else if(sample_rate_hint == 13) - decoder->private_->frame.header.sample_rate = x; - else - decoder->private_->frame.header.sample_rate = x*10; - } - - /* read the CRC-8 byte */ - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) - return false; /* read_callback_ sets the state for us */ - crc8 = (FLAC__byte)x; - - if(FLAC__crc8(raw_header, raw_header_len) != crc8) { - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - - /* calculate the sample number from the frame number if needed */ - decoder->private_->next_fixed_block_size = 0; - if(decoder->private_->frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER) { - x = decoder->private_->frame.header.number.frame_number; - decoder->private_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER; - if(decoder->private_->fixed_block_size) - decoder->private_->frame.header.number.sample_number = (FLAC__uint64)decoder->private_->fixed_block_size * (FLAC__uint64)x; - else if(decoder->private_->has_stream_info) { - if(decoder->private_->stream_info.data.stream_info.min_blocksize == decoder->private_->stream_info.data.stream_info.max_blocksize) { - decoder->private_->frame.header.number.sample_number = (FLAC__uint64)decoder->private_->stream_info.data.stream_info.min_blocksize * (FLAC__uint64)x; - decoder->private_->next_fixed_block_size = decoder->private_->stream_info.data.stream_info.max_blocksize; - } - else - is_unparseable = true; - } - else if(x == 0) { - decoder->private_->frame.header.number.sample_number = 0; - decoder->private_->next_fixed_block_size = decoder->private_->frame.header.blocksize; - } - else { - /* can only get here if the stream has invalid frame numbering and no STREAMINFO, so assume it's not the last (possibly short) frame */ - decoder->private_->frame.header.number.sample_number = (FLAC__uint64)decoder->private_->frame.header.blocksize * (FLAC__uint64)x; - } - } - - if(is_unparseable) { - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - - return true; -} - -FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode) -{ - FLAC__uint32 x; - FLAC__bool wasted_bits; - uint32_t i; - - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) /* MAGIC NUMBER */ - return false; /* read_callback_ sets the state for us */ - - wasted_bits = (x & 1); - x &= 0xfe; - - if(wasted_bits) { - uint32_t u; - if(!FLAC__bitreader_read_unary_unsigned(decoder->private_->input, &u)) - return false; /* read_callback_ sets the state for us */ - decoder->private_->frame.subframes[channel].wasted_bits = u+1; - if (decoder->private_->frame.subframes[channel].wasted_bits >= bps) - return false; - bps -= decoder->private_->frame.subframes[channel].wasted_bits; - } - else - decoder->private_->frame.subframes[channel].wasted_bits = 0; - - /* - * Lots of magic numbers here - */ - if(x & 0x80) { - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - else if(x == 0) { - if(!read_subframe_constant_(decoder, channel, bps, do_full_decode)) - return false; - } - else if(x == 2) { - if(!read_subframe_verbatim_(decoder, channel, bps, do_full_decode)) - return false; - } - else if(x < 16) { - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - else if(x <= 24) { - if(!read_subframe_fixed_(decoder, channel, bps, (x>>1)&7, do_full_decode)) - return false; - if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption */ - return true; - } - else if(x < 64) { - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - else { - if(!read_subframe_lpc_(decoder, channel, bps, ((x>>1)&31)+1, do_full_decode)) - return false; - if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption */ - return true; - } - - if(wasted_bits && do_full_decode) { - x = decoder->private_->frame.subframes[channel].wasted_bits; - for(i = 0; i < decoder->private_->frame.header.blocksize; i++) { - uint32_t val = decoder->private_->output[channel][i]; - decoder->private_->output[channel][i] = (val << x); - } - } - - return true; -} - -FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode) -{ - FLAC__Subframe_Constant *subframe = &decoder->private_->frame.subframes[channel].data.constant; - FLAC__int32 x; - uint32_t i; - FLAC__int32 *output = decoder->private_->output[channel]; - - decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_CONSTANT; - - if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &x, bps)) - return false; /* read_callback_ sets the state for us */ - - subframe->value = x; - - /* decode the subframe */ - if(do_full_decode) { - for(i = 0; i < decoder->private_->frame.header.blocksize; i++) - output[i] = x; - } - - return true; -} - -FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, const uint32_t order, FLAC__bool do_full_decode) -{ - FLAC__Subframe_Fixed *subframe = &decoder->private_->frame.subframes[channel].data.fixed; - FLAC__int32 i32; - FLAC__uint32 u32; - uint32_t u; - - decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_FIXED; - - subframe->residual = decoder->private_->residual[channel]; - subframe->order = order; - - /* read warm-up samples */ - for(u = 0; u < order; u++) { - if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, bps)) - return false; /* read_callback_ sets the state for us */ - subframe->warmup[u] = i32; - } - - /* read entropy coding method info */ - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN)) - return false; /* read_callback_ sets the state for us */ - subframe->entropy_coding_method.type = (FLAC__EntropyCodingMethodType)u32; - switch(subframe->entropy_coding_method.type) { - case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: - case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2: - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN)) - return false; /* read_callback_ sets the state for us */ - if(decoder->private_->frame.header.blocksize >> u32 < order) { - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - subframe->entropy_coding_method.data.partitioned_rice.order = u32; - subframe->entropy_coding_method.data.partitioned_rice.contents = &decoder->private_->partitioned_rice_contents[channel]; - break; - default: - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - - /* read residual */ - switch(subframe->entropy_coding_method.type) { - case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: - case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2: - if(!read_residual_partitioned_rice_(decoder, order, subframe->entropy_coding_method.data.partitioned_rice.order, &decoder->private_->partitioned_rice_contents[channel], decoder->private_->residual[channel], /*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2)) - return false; - break; - default: - FLAC__ASSERT(0); - } - - /* decode the subframe */ - if(do_full_decode) { - memcpy(decoder->private_->output[channel], subframe->warmup, sizeof(FLAC__int32) * order); - FLAC__fixed_restore_signal(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, order, decoder->private_->output[channel]+order); - } - - return true; -} - -FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, const uint32_t order, FLAC__bool do_full_decode) -{ - FLAC__Subframe_LPC *subframe = &decoder->private_->frame.subframes[channel].data.lpc; - FLAC__int32 i32; - FLAC__uint32 u32; - uint32_t u; - - decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_LPC; - - subframe->residual = decoder->private_->residual[channel]; - subframe->order = order; - - /* read warm-up samples */ - for(u = 0; u < order; u++) { - if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, bps)) - return false; /* read_callback_ sets the state for us */ - subframe->warmup[u] = i32; - } - - /* read qlp coeff precision */ - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN)) - return false; /* read_callback_ sets the state for us */ - if(u32 == (1u << FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN) - 1) { - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - subframe->qlp_coeff_precision = u32+1; - - /* read qlp shift */ - if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN)) - return false; /* read_callback_ sets the state for us */ - if(i32 < 0) { - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - subframe->quantization_level = i32; - - /* read quantized lp coefficiencts */ - for(u = 0; u < order; u++) { - if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, subframe->qlp_coeff_precision)) - return false; /* read_callback_ sets the state for us */ - subframe->qlp_coeff[u] = i32; - } - - /* read entropy coding method info */ - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN)) - return false; /* read_callback_ sets the state for us */ - subframe->entropy_coding_method.type = (FLAC__EntropyCodingMethodType)u32; - switch(subframe->entropy_coding_method.type) { - case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: - case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2: - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN)) - return false; /* read_callback_ sets the state for us */ - if(decoder->private_->frame.header.blocksize >> u32 < order) { - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - subframe->entropy_coding_method.data.partitioned_rice.order = u32; - subframe->entropy_coding_method.data.partitioned_rice.contents = &decoder->private_->partitioned_rice_contents[channel]; - break; - default: - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - - /* read residual */ - switch(subframe->entropy_coding_method.type) { - case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: - case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2: - if(!read_residual_partitioned_rice_(decoder, order, subframe->entropy_coding_method.data.partitioned_rice.order, &decoder->private_->partitioned_rice_contents[channel], decoder->private_->residual[channel], /*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2)) - return false; - break; - default: - FLAC__ASSERT(0); - } - - /* decode the subframe */ - if(do_full_decode) { - memcpy(decoder->private_->output[channel], subframe->warmup, sizeof(FLAC__int32) * order); - if(bps + subframe->qlp_coeff_precision + FLAC__bitmath_ilog2(order) <= 32) - if(bps <= 16 && subframe->qlp_coeff_precision <= 16) - decoder->private_->local_lpc_restore_signal_16bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order); - else - decoder->private_->local_lpc_restore_signal(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order); - else - decoder->private_->local_lpc_restore_signal_64bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order); - } - - return true; -} - -FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode) -{ - FLAC__Subframe_Verbatim *subframe = &decoder->private_->frame.subframes[channel].data.verbatim; - FLAC__int32 x, *residual = decoder->private_->residual[channel]; - uint32_t i; - - decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_VERBATIM; - - subframe->data = residual; - - for(i = 0; i < decoder->private_->frame.header.blocksize; i++) { - if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &x, bps)) - return false; /* read_callback_ sets the state for us */ - residual[i] = x; - } - - /* decode the subframe */ - if(do_full_decode) - memcpy(decoder->private_->output[channel], subframe->data, sizeof(FLAC__int32) * decoder->private_->frame.header.blocksize); - - return true; -} - -FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, uint32_t predictor_order, uint32_t partition_order, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, FLAC__int32 *residual, FLAC__bool is_extended) -{ - FLAC__uint32 rice_parameter; - int i; - uint32_t partition, sample, u; - const uint32_t partitions = 1u << partition_order; - const uint32_t partition_samples = partition_order > 0? decoder->private_->frame.header.blocksize >> partition_order : decoder->private_->frame.header.blocksize - predictor_order; - const uint32_t plen = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; - const uint32_t pesc = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER; - - /* invalid predictor and partition orders mush be handled in the callers */ - FLAC__ASSERT(partition_order > 0? partition_samples >= predictor_order : decoder->private_->frame.header.blocksize >= predictor_order); - - if(!FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(partitioned_rice_contents, flac_max(6u, partition_order))) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - - sample = 0; - for(partition = 0; partition < partitions; partition++) { - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &rice_parameter, plen)) - return false; /* read_callback_ sets the state for us */ - partitioned_rice_contents->parameters[partition] = rice_parameter; - if(rice_parameter < pesc) { - partitioned_rice_contents->raw_bits[partition] = 0; - u = (partition_order == 0 || partition > 0)? partition_samples : partition_samples - predictor_order; - if(!FLAC__bitreader_read_rice_signed_block(decoder->private_->input, residual + sample, u, rice_parameter)) - return false; /* read_callback_ sets the state for us */ - sample += u; - } - else { - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN)) - return false; /* read_callback_ sets the state for us */ - partitioned_rice_contents->raw_bits[partition] = rice_parameter; - for(u = (partition_order == 0 || partition > 0)? 0 : predictor_order; u < partition_samples; u++, sample++) { - if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i, rice_parameter)) - return false; /* read_callback_ sets the state for us */ - residual[sample] = i; - } - } - } - - return true; -} - -FLAC__bool read_zero_padding_(FLAC__StreamDecoder *decoder) -{ - if(!FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)) { - FLAC__uint32 zero = 0; - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &zero, FLAC__bitreader_bits_left_for_byte_alignment(decoder->private_->input))) - return false; /* read_callback_ sets the state for us */ - if(zero != 0) { - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - } - } - return true; -} - -FLAC__bool read_callback_(FLAC__byte buffer[], size_t *bytes, void *client_data) -{ - FLAC__StreamDecoder *decoder = (FLAC__StreamDecoder *)client_data; - - if( -#if FLAC__HAS_OGG - /* see [1] HACK NOTE below for why we don't call the eof_callback when decoding Ogg FLAC */ - !decoder->private_->is_ogg && -#endif - decoder->private_->eof_callback && decoder->private_->eof_callback(decoder, decoder->private_->client_data) - ) { - *bytes = 0; - decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM; - return false; - } - else if(*bytes > 0) { - /* While seeking, it is possible for our seek to land in the - * middle of audio data that looks exactly like a frame header - * from a future version of an encoder. When that happens, our - * error callback will get an - * FLAC__STREAM_DECODER_UNPARSEABLE_STREAM and increment its - * unparseable_frame_count. But there is a remote possibility - * that it is properly synced at such a "future-codec frame", - * so to make sure, we wait to see many "unparseable" errors in - * a row before bailing out. - */ - if(decoder->private_->is_seeking && decoder->private_->unparseable_frame_count > 20) { - decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED; - return false; - } - else { - const FLAC__StreamDecoderReadStatus status = -#if FLAC__HAS_OGG - decoder->private_->is_ogg? - read_callback_ogg_aspect_(decoder, buffer, bytes) : -#endif - decoder->private_->read_callback(decoder, buffer, bytes, decoder->private_->client_data) - ; - if(status == FLAC__STREAM_DECODER_READ_STATUS_ABORT) { - decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED; - return false; - } - else if(*bytes == 0) { - if( - status == FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM || - ( -#if FLAC__HAS_OGG - /* see [1] HACK NOTE below for why we don't call the eof_callback when decoding Ogg FLAC */ - !decoder->private_->is_ogg && -#endif - decoder->private_->eof_callback && decoder->private_->eof_callback(decoder, decoder->private_->client_data) - ) - ) { - decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM; - return false; - } - else - return true; - } - else - return true; - } - } - else { - /* abort to avoid a deadlock */ - decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED; - return false; - } - /* [1] @@@ HACK NOTE: The end-of-stream checking has to be hacked around - * for Ogg FLAC. This is because the ogg decoder aspect can lose sync - * and at the same time hit the end of the stream (for example, seeking - * to a point that is after the beginning of the last Ogg page). There - * is no way to report an Ogg sync loss through the callbacks (see note - * in read_callback_ogg_aspect_()) so it returns CONTINUE with *bytes==0. - * So to keep the decoder from stopping at this point we gate the call - * to the eof_callback and let the Ogg decoder aspect set the - * end-of-stream state when it is needed. - */ -} - -#if FLAC__HAS_OGG -FLAC__StreamDecoderReadStatus read_callback_ogg_aspect_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes) -{ - switch(FLAC__ogg_decoder_aspect_read_callback_wrapper(&decoder->protected_->ogg_decoder_aspect, buffer, bytes, read_callback_proxy_, decoder, decoder->private_->client_data)) { - case FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK: - return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; - /* we don't really have a way to handle lost sync via read - * callback so we'll let it pass and let the underlying - * FLAC decoder catch the error - */ - case FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC: - return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; - case FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM: - return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; - case FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC: - case FLAC__OGG_DECODER_ASPECT_READ_STATUS_UNSUPPORTED_MAPPING_VERSION: - case FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT: - case FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR: - case FLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR: - return FLAC__STREAM_DECODER_READ_STATUS_ABORT; - default: - FLAC__ASSERT(0); - /* double protection */ - return FLAC__STREAM_DECODER_READ_STATUS_ABORT; - } -} - -FLAC__OggDecoderAspectReadStatus read_callback_proxy_(const void *void_decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) -{ - FLAC__StreamDecoder *decoder = (FLAC__StreamDecoder*)void_decoder; - - switch(decoder->private_->read_callback(decoder, buffer, bytes, client_data)) { - case FLAC__STREAM_DECODER_READ_STATUS_CONTINUE: - return FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK; - case FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM: - return FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM; - case FLAC__STREAM_DECODER_READ_STATUS_ABORT: - return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT; - default: - /* double protection: */ - FLAC__ASSERT(0); - return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT; - } -} -#endif - -FLAC__StreamDecoderWriteStatus write_audio_frame_to_client_(FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]) -{ - if(decoder->private_->is_seeking) { - FLAC__uint64 this_frame_sample = frame->header.number.sample_number; - FLAC__uint64 next_frame_sample = this_frame_sample + (FLAC__uint64)frame->header.blocksize; - FLAC__uint64 target_sample = decoder->private_->target_sample; - - FLAC__ASSERT(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); - -#if FLAC__HAS_OGG - decoder->private_->got_a_frame = true; -#endif - decoder->private_->last_frame = *frame; /* save the frame */ - if(this_frame_sample <= target_sample && target_sample < next_frame_sample) { /* we hit our target frame */ - uint32_t delta = (uint32_t)(target_sample - this_frame_sample); - /* kick out of seek mode */ - decoder->private_->is_seeking = false; - /* shift out the samples before target_sample */ - if(delta > 0) { - uint32_t channel; - const FLAC__int32 *newbuffer[FLAC__MAX_CHANNELS]; - for(channel = 0; channel < frame->header.channels; channel++) - newbuffer[channel] = buffer[channel] + delta; - decoder->private_->last_frame.header.blocksize -= delta; - decoder->private_->last_frame.header.number.sample_number += (FLAC__uint64)delta; - /* write the relevant samples */ - return decoder->private_->write_callback(decoder, &decoder->private_->last_frame, newbuffer, decoder->private_->client_data); - } - else { - /* write the relevant samples */ - return decoder->private_->write_callback(decoder, frame, buffer, decoder->private_->client_data); - } - } - else { - return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; - } - } - else { - /* - * If we never got STREAMINFO, turn off MD5 checking to save - * cycles since we don't have a sum to compare to anyway - */ - if(!decoder->private_->has_stream_info) - decoder->private_->do_md5_checking = false; - if(decoder->private_->do_md5_checking) { - if(!FLAC__MD5Accumulate(&decoder->private_->md5context, buffer, frame->header.channels, frame->header.blocksize, (frame->header.bits_per_sample+7) / 8)) - return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; - } - return decoder->private_->write_callback(decoder, frame, buffer, decoder->private_->client_data); - } -} - -void send_error_to_client_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status) -{ - if(!decoder->private_->is_seeking) - decoder->private_->error_callback(decoder, status, decoder->private_->client_data); - else if(status == FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM) - decoder->private_->unparseable_frame_count++; -} - -FLAC__bool seek_to_absolute_sample_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample) -{ - FLAC__uint64 first_frame_offset = decoder->private_->first_frame_offset, lower_bound, upper_bound, lower_bound_sample, upper_bound_sample, this_frame_sample; - FLAC__int64 pos = -1; - int i; - uint32_t approx_bytes_per_frame; - FLAC__bool first_seek = true; - const FLAC__uint64 total_samples = FLAC__stream_decoder_get_total_samples(decoder); - const uint32_t min_blocksize = decoder->private_->stream_info.data.stream_info.min_blocksize; - const uint32_t max_blocksize = decoder->private_->stream_info.data.stream_info.max_blocksize; - const uint32_t max_framesize = decoder->private_->stream_info.data.stream_info.max_framesize; - const uint32_t min_framesize = decoder->private_->stream_info.data.stream_info.min_framesize; - /* take these from the current frame in case they've changed mid-stream */ - uint32_t channels = FLAC__stream_decoder_get_channels(decoder); - uint32_t bps = FLAC__stream_decoder_get_bits_per_sample(decoder); - const FLAC__StreamMetadata_SeekTable *seek_table = decoder->private_->has_seek_table? &decoder->private_->seek_table.data.seek_table : 0; - - /* use values from stream info if we didn't decode a frame */ - if(channels == 0) - channels = decoder->private_->stream_info.data.stream_info.channels; - if(bps == 0) - bps = decoder->private_->stream_info.data.stream_info.bits_per_sample; - - /* we are just guessing here */ - if(max_framesize > 0) - approx_bytes_per_frame = (max_framesize + min_framesize) / 2 + 1; - /* - * Check if it's a known fixed-blocksize stream. Note that though - * the spec doesn't allow zeroes in the STREAMINFO block, we may - * never get a STREAMINFO block when decoding so the value of - * min_blocksize might be zero. - */ - else if(min_blocksize == max_blocksize && min_blocksize > 0) { - /* note there are no () around 'bps/8' to keep precision up since it's an integer calculation */ - approx_bytes_per_frame = min_blocksize * channels * bps/8 + 64; - } - else - approx_bytes_per_frame = 4096 * channels * bps/8 + 64; - - /* - * First, we set an upper and lower bound on where in the - * stream we will search. For now we assume the worst case - * scenario, which is our best guess at the beginning of - * the first frame and end of the stream. - */ - lower_bound = first_frame_offset; - lower_bound_sample = 0; - upper_bound = stream_length; - upper_bound_sample = total_samples > 0 ? total_samples : target_sample /*estimate it*/; - - /* - * Now we refine the bounds if we have a seektable with - * suitable points. Note that according to the spec they - * must be ordered by ascending sample number. - * - * Note: to protect against invalid seek tables we will ignore points - * that have frame_samples==0 or sample_number>=total_samples - */ - if(seek_table) { - FLAC__uint64 new_lower_bound = lower_bound; - FLAC__uint64 new_upper_bound = upper_bound; - FLAC__uint64 new_lower_bound_sample = lower_bound_sample; - FLAC__uint64 new_upper_bound_sample = upper_bound_sample; - - /* find the closest seek point <= target_sample, if it exists */ - for(i = (int)seek_table->num_points - 1; i >= 0; i--) { - if( - seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER && - seek_table->points[i].frame_samples > 0 && /* defense against bad seekpoints */ - (total_samples <= 0 || seek_table->points[i].sample_number < total_samples) && /* defense against bad seekpoints */ - seek_table->points[i].sample_number <= target_sample - ) - break; - } - if(i >= 0) { /* i.e. we found a suitable seek point... */ - new_lower_bound = first_frame_offset + seek_table->points[i].stream_offset; - new_lower_bound_sample = seek_table->points[i].sample_number; - } - - /* find the closest seek point > target_sample, if it exists */ - for(i = 0; i < (int)seek_table->num_points; i++) { - if( - seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER && - seek_table->points[i].frame_samples > 0 && /* defense against bad seekpoints */ - (total_samples <= 0 || seek_table->points[i].sample_number < total_samples) && /* defense against bad seekpoints */ - seek_table->points[i].sample_number > target_sample - ) - break; - } - if(i < (int)seek_table->num_points) { /* i.e. we found a suitable seek point... */ - new_upper_bound = first_frame_offset + seek_table->points[i].stream_offset; - new_upper_bound_sample = seek_table->points[i].sample_number; - } - /* final protection against unsorted seek tables; keep original values if bogus */ - if(new_upper_bound >= new_lower_bound) { - lower_bound = new_lower_bound; - upper_bound = new_upper_bound; - lower_bound_sample = new_lower_bound_sample; - upper_bound_sample = new_upper_bound_sample; - } - } - - FLAC__ASSERT(upper_bound_sample >= lower_bound_sample); - /* there are 2 insidious ways that the following equality occurs, which - * we need to fix: - * 1) total_samples is 0 (unknown) and target_sample is 0 - * 2) total_samples is 0 (unknown) and target_sample happens to be - * exactly equal to the last seek point in the seek table; this - * means there is no seek point above it, and upper_bound_samples - * remains equal to the estimate (of target_samples) we made above - * in either case it does not hurt to move upper_bound_sample up by 1 - */ - if(upper_bound_sample == lower_bound_sample) - upper_bound_sample++; - - decoder->private_->target_sample = target_sample; - while(1) { - /* check if the bounds are still ok */ - if (lower_bound_sample >= upper_bound_sample || lower_bound > upper_bound) { - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } -#ifndef FLAC__INTEGER_ONLY_LIBRARY - pos = (FLAC__int64)lower_bound + (FLAC__int64)((double)(target_sample - lower_bound_sample) / (double)(upper_bound_sample - lower_bound_sample) * (double)(upper_bound - lower_bound)) - approx_bytes_per_frame; -#else - /* a little less accurate: */ - if(upper_bound - lower_bound < 0xffffffff) - pos = (FLAC__int64)lower_bound + (FLAC__int64)(((target_sample - lower_bound_sample) * (upper_bound - lower_bound)) / (upper_bound_sample - lower_bound_sample)) - approx_bytes_per_frame; - else /* @@@ WATCHOUT, ~2TB limit */ - pos = (FLAC__int64)lower_bound + (FLAC__int64)((((target_sample - lower_bound_sample)>>8) * ((upper_bound - lower_bound)>>8)) / ((upper_bound_sample - lower_bound_sample)>>16)) - approx_bytes_per_frame; -#endif - if(pos >= (FLAC__int64)upper_bound) - pos = (FLAC__int64)upper_bound - 1; - if(pos < (FLAC__int64)lower_bound) - pos = (FLAC__int64)lower_bound; - if(decoder->private_->seek_callback(decoder, (FLAC__uint64)pos, decoder->private_->client_data) != FLAC__STREAM_DECODER_SEEK_STATUS_OK) { - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - if(!FLAC__stream_decoder_flush(decoder)) { - /* above call sets the state for us */ - return false; - } - /* Now we need to get a frame. First we need to reset our - * unparseable_frame_count; if we get too many unparseable - * frames in a row, the read callback will return - * FLAC__STREAM_DECODER_READ_STATUS_ABORT, causing - * FLAC__stream_decoder_process_single() to return false. - */ - decoder->private_->unparseable_frame_count = 0; - if(!FLAC__stream_decoder_process_single(decoder) || - decoder->protected_->state == FLAC__STREAM_DECODER_ABORTED) { - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - /* our write callback will change the state when it gets to the target frame */ - /* actually, we could have got_a_frame if our decoder is at FLAC__STREAM_DECODER_END_OF_STREAM so we need to check for that also */ -#if 0 - /*@@@@@@ used to be the following; not clear if the check for end of stream is needed anymore */ - if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_SEEKING && decoder->protected_->state != FLAC__STREAM_DECODER_END_OF_STREAM) - break; -#endif - if(!decoder->private_->is_seeking) - break; - - FLAC__ASSERT(decoder->private_->last_frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); - this_frame_sample = decoder->private_->last_frame.header.number.sample_number; - - if (0 == decoder->private_->samples_decoded || (this_frame_sample + decoder->private_->last_frame.header.blocksize >= upper_bound_sample && !first_seek)) { - if (pos == (FLAC__int64)lower_bound) { - /* can't move back any more than the first frame, something is fatally wrong */ - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - /* our last move backwards wasn't big enough, try again */ - approx_bytes_per_frame = approx_bytes_per_frame? approx_bytes_per_frame * 2 : 16; - continue; - } - /* allow one seek over upper bound, so we can get a correct upper_bound_sample for streams with unknown total_samples */ - first_seek = false; - - /* make sure we are not seeking in corrupted stream */ - if (this_frame_sample < lower_bound_sample) { - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - - /* we need to narrow the search */ - if(target_sample < this_frame_sample) { - upper_bound_sample = this_frame_sample + decoder->private_->last_frame.header.blocksize; -/*@@@@@@ what will decode position be if at end of stream? */ - if(!FLAC__stream_decoder_get_decode_position(decoder, &upper_bound)) { - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - approx_bytes_per_frame = (uint32_t)(2 * (upper_bound - pos) / 3 + 16); - } - else { /* target_sample >= this_frame_sample + this frame's blocksize */ - lower_bound_sample = this_frame_sample + decoder->private_->last_frame.header.blocksize; - if(!FLAC__stream_decoder_get_decode_position(decoder, &lower_bound)) { - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - approx_bytes_per_frame = (uint32_t)(2 * (lower_bound - pos) / 3 + 16); - } - } - - return true; -} - -#if FLAC__HAS_OGG -FLAC__bool seek_to_absolute_sample_ogg_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample) -{ - FLAC__uint64 left_pos = 0, right_pos = stream_length; - FLAC__uint64 left_sample = 0, right_sample = FLAC__stream_decoder_get_total_samples(decoder); - FLAC__uint64 this_frame_sample = (FLAC__uint64)0 - 1; - FLAC__uint64 pos = 0; /* only initialized to avoid compiler warning */ - FLAC__bool did_a_seek; - uint32_t iteration = 0; - - /* In the first iterations, we will calculate the target byte position - * by the distance from the target sample to left_sample and - * right_sample (let's call it "proportional search"). After that, we - * will switch to binary search. - */ - uint32_t BINARY_SEARCH_AFTER_ITERATION = 2; - - /* We will switch to a linear search once our current sample is less - * than this number of samples ahead of the target sample - */ - static const FLAC__uint64 LINEAR_SEARCH_WITHIN_SAMPLES = FLAC__MAX_BLOCK_SIZE * 2; - - /* If the total number of samples is unknown, use a large value, and - * force binary search immediately. - */ - if(right_sample == 0) { - right_sample = (FLAC__uint64)(-1); - BINARY_SEARCH_AFTER_ITERATION = 0; - } - - decoder->private_->target_sample = target_sample; - for( ; ; iteration++) { - if (iteration == 0 || this_frame_sample > target_sample || target_sample - this_frame_sample > LINEAR_SEARCH_WITHIN_SAMPLES) { - if (iteration >= BINARY_SEARCH_AFTER_ITERATION) { - pos = (right_pos + left_pos) / 2; - } - else { -#ifndef FLAC__INTEGER_ONLY_LIBRARY - pos = (FLAC__uint64)((double)(target_sample - left_sample) / (double)(right_sample - left_sample) * (double)(right_pos - left_pos)); -#else - /* a little less accurate: */ - if ((target_sample-left_sample <= 0xffffffff) && (right_pos-left_pos <= 0xffffffff)) - pos = (FLAC__int64)(((target_sample-left_sample) * (right_pos-left_pos)) / (right_sample-left_sample)); - else /* @@@ WATCHOUT, ~2TB limit */ - pos = (FLAC__int64)((((target_sample-left_sample)>>8) * ((right_pos-left_pos)>>8)) / ((right_sample-left_sample)>>16)); -#endif - /* @@@ TODO: might want to limit pos to some distance - * before EOF, to make sure we land before the last frame, - * thereby getting a this_frame_sample and so having a better - * estimate. - */ - } - - /* physical seek */ - if(decoder->private_->seek_callback((FLAC__StreamDecoder*)decoder, (FLAC__uint64)pos, decoder->private_->client_data) != FLAC__STREAM_DECODER_SEEK_STATUS_OK) { - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - if(!FLAC__stream_decoder_flush(decoder)) { - /* above call sets the state for us */ - return false; - } - did_a_seek = true; - } - else - did_a_seek = false; - - decoder->private_->got_a_frame = false; - if(!FLAC__stream_decoder_process_single(decoder) || - decoder->protected_->state == FLAC__STREAM_DECODER_ABORTED) { - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - if(!decoder->private_->got_a_frame) { - if(did_a_seek) { - /* this can happen if we seek to a point after the last frame; we drop - * to binary search right away in this case to avoid any wasted - * iterations of proportional search. - */ - right_pos = pos; - BINARY_SEARCH_AFTER_ITERATION = 0; - } - else { - /* this can probably only happen if total_samples is unknown and the - * target_sample is past the end of the stream - */ - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - } - /* our write callback will change the state when it gets to the target frame */ - else if(!decoder->private_->is_seeking) { - break; - } - else { - this_frame_sample = decoder->private_->last_frame.header.number.sample_number; - FLAC__ASSERT(decoder->private_->last_frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); - - if (did_a_seek) { - if (this_frame_sample <= target_sample) { - /* The 'equal' case should not happen, since - * FLAC__stream_decoder_process_single() - * should recognize that it has hit the - * target sample and we would exit through - * the 'break' above. - */ - FLAC__ASSERT(this_frame_sample != target_sample); - - left_sample = this_frame_sample; - /* sanity check to avoid infinite loop */ - if (left_pos == pos) { - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - left_pos = pos; - } - else if(this_frame_sample > target_sample) { - right_sample = this_frame_sample; - /* sanity check to avoid infinite loop */ - if (right_pos == pos) { - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - right_pos = pos; - } - } - } - } - - return true; -} -#endif - -FLAC__StreamDecoderReadStatus file_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) -{ - (void)client_data; - - if(*bytes > 0) { - *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, decoder->private_->file); - if(ferror(decoder->private_->file)) - return FLAC__STREAM_DECODER_READ_STATUS_ABORT; - else if(*bytes == 0) - return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; - else - return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; - } - else - return FLAC__STREAM_DECODER_READ_STATUS_ABORT; /* abort to avoid a deadlock */ -} - -FLAC__StreamDecoderSeekStatus file_seek_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data) -{ - (void)client_data; - - if(decoder->private_->file == stdin) - return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED; - else if(fseeko(decoder->private_->file, (FLAC__off_t)absolute_byte_offset, SEEK_SET) < 0) - return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; - else - return FLAC__STREAM_DECODER_SEEK_STATUS_OK; -} - -FLAC__StreamDecoderTellStatus file_tell_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) -{ - FLAC__off_t pos; - (void)client_data; - - if(decoder->private_->file == stdin) - return FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED; - else if((pos = ftello(decoder->private_->file)) < 0) - return FLAC__STREAM_DECODER_TELL_STATUS_ERROR; - else { - *absolute_byte_offset = (FLAC__uint64)pos; - return FLAC__STREAM_DECODER_TELL_STATUS_OK; - } -} - -FLAC__StreamDecoderLengthStatus file_length_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data) -{ - struct flac_stat_s filestats; - (void)client_data; - - if(decoder->private_->file == stdin) - return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED; - else if(flac_fstat(fileno(decoder->private_->file), &filestats) != 0) - return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR; - else { - *stream_length = (FLAC__uint64)filestats.st_size; - return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; - } -} - -FLAC__bool file_eof_callback_(const FLAC__StreamDecoder *decoder, void *client_data) -{ - (void)client_data; - - return feof(decoder->private_->file)? true : false; -} - -void *get_client_data_from_decoder(FLAC__StreamDecoder *decoder) -{ - return decoder->private_->client_data; -} diff --git a/lib/flac/src/stream_encoder.c b/lib/flac/src/stream_encoder.c deleted file mode 100644 index 74387ec..0000000 --- a/lib/flac/src/stream_encoder.c +++ /dev/null @@ -1,4578 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include /* for malloc() */ -#include /* for memcpy() */ -#include /* for off_t */ -#ifdef _WIN32 -#include /* for GetFileType() */ -#include /* for _get_osfhandle() */ -#endif -#include "share/compat.h" -#include "FLAC/assert.h" -#include "FLAC/stream_decoder.h" -#include "protected/stream_encoder.h" -#include "private/bitwriter.h" -#include "private/bitmath.h" -#include "private/crc.h" -#include "private/cpu.h" -#include "private/fixed.h" -#include "private/format.h" -#include "private/lpc.h" -#include "private/md5.h" -#include "private/memory.h" -#include "private/macros.h" -#if FLAC__HAS_OGG -#include "private/ogg_helper.h" -#include "private/ogg_mapping.h" -#endif -#include "private/stream_encoder.h" -#include "private/stream_encoder_framing.h" -#include "private/window.h" -#include "share/alloc.h" -#include "share/private.h" - - -/* Exact Rice codeword length calculation is off by default. The simple - * (and fast) estimation (of how many bits a residual value will be - * encoded with) in this encoder is very good, almost always yielding - * compression within 0.1% of exact calculation. - */ -#undef EXACT_RICE_BITS_CALCULATION -/* Rice parameter searching is off by default. The simple (and fast) - * parameter estimation in this encoder is very good, almost always - * yielding compression within 0.1% of the optimal parameters. - */ -#undef ENABLE_RICE_PARAMETER_SEARCH - - -typedef struct { - FLAC__int32 *data[FLAC__MAX_CHANNELS]; - uint32_t size; /* of each data[] in samples */ - uint32_t tail; -} verify_input_fifo; - -typedef struct { - const FLAC__byte *data; - uint32_t capacity; - uint32_t bytes; -} verify_output; - -typedef enum { - ENCODER_IN_MAGIC = 0, - ENCODER_IN_METADATA = 1, - ENCODER_IN_AUDIO = 2 -} EncoderStateHint; - -static const struct CompressionLevels { - FLAC__bool do_mid_side_stereo; - FLAC__bool loose_mid_side_stereo; - uint32_t max_lpc_order; - uint32_t qlp_coeff_precision; - FLAC__bool do_qlp_coeff_prec_search; - FLAC__bool do_escape_coding; - FLAC__bool do_exhaustive_model_search; - uint32_t min_residual_partition_order; - uint32_t max_residual_partition_order; - uint32_t rice_parameter_search_dist; - const char *apodization; -} compression_levels_[] = { - { false, false, 0, 0, false, false, false, 0, 3, 0, "tukey(5e-1)" }, - { true , true , 0, 0, false, false, false, 0, 3, 0, "tukey(5e-1)" }, - { true , false, 0, 0, false, false, false, 0, 3, 0, "tukey(5e-1)" }, - { false, false, 6, 0, false, false, false, 0, 4, 0, "tukey(5e-1)" }, - { true , true , 8, 0, false, false, false, 0, 4, 0, "tukey(5e-1)" }, - { true , false, 8, 0, false, false, false, 0, 5, 0, "tukey(5e-1)" }, - { true , false, 8, 0, false, false, false, 0, 6, 0, "tukey(5e-1);partial_tukey(2)" }, - { true , false, 12, 0, false, false, false, 0, 6, 0, "tukey(5e-1);partial_tukey(2)" }, - { true , false, 12, 0, false, false, false, 0, 6, 0, "tukey(5e-1);partial_tukey(2);punchout_tukey(3)" } - /* here we use locale-independent 5e-1 instead of 0.5 or 0,5 */ -}; - - -/*********************************************************************** - * - * Private class method prototypes - * - ***********************************************************************/ - -static void set_defaults_(FLAC__StreamEncoder *encoder); -static void free_(FLAC__StreamEncoder *encoder); -static FLAC__bool resize_buffers_(FLAC__StreamEncoder *encoder, uint32_t new_blocksize); -static FLAC__bool write_bitbuffer_(FLAC__StreamEncoder *encoder, uint32_t samples, FLAC__bool is_last_block); -static FLAC__StreamEncoderWriteStatus write_frame_(FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, FLAC__bool is_last_block); -static void update_metadata_(const FLAC__StreamEncoder *encoder); -#if FLAC__HAS_OGG -static void update_ogg_metadata_(FLAC__StreamEncoder *encoder); -#endif -static FLAC__bool process_frame_(FLAC__StreamEncoder *encoder, FLAC__bool is_fractional_block, FLAC__bool is_last_block); -static FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_fractional_block); - -static FLAC__bool process_subframe_( - FLAC__StreamEncoder *encoder, - uint32_t min_partition_order, - uint32_t max_partition_order, - const FLAC__FrameHeader *frame_header, - uint32_t subframe_bps, - const FLAC__int32 integer_signal[], - FLAC__Subframe *subframe[2], - FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents[2], - FLAC__int32 *residual[2], - uint32_t *best_subframe, - uint32_t *best_bits -); - -static FLAC__bool add_subframe_( - FLAC__StreamEncoder *encoder, - uint32_t blocksize, - uint32_t subframe_bps, - const FLAC__Subframe *subframe, - FLAC__BitWriter *frame -); - -static uint32_t evaluate_constant_subframe_( - FLAC__StreamEncoder *encoder, - const FLAC__int32 signal, - uint32_t blocksize, - uint32_t subframe_bps, - FLAC__Subframe *subframe -); - -static uint32_t evaluate_fixed_subframe_( - FLAC__StreamEncoder *encoder, - const FLAC__int32 signal[], - FLAC__int32 residual[], - FLAC__uint64 abs_residual_partition_sums[], - uint32_t raw_bits_per_partition[], - uint32_t blocksize, - uint32_t subframe_bps, - uint32_t order, - uint32_t rice_parameter, - uint32_t rice_parameter_limit, - uint32_t min_partition_order, - uint32_t max_partition_order, - FLAC__bool do_escape_coding, - uint32_t rice_parameter_search_dist, - FLAC__Subframe *subframe, - FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents -); - -#ifndef FLAC__INTEGER_ONLY_LIBRARY -static uint32_t evaluate_lpc_subframe_( - FLAC__StreamEncoder *encoder, - const FLAC__int32 signal[], - FLAC__int32 residual[], - FLAC__uint64 abs_residual_partition_sums[], - uint32_t raw_bits_per_partition[], - const FLAC__real lp_coeff[], - uint32_t blocksize, - uint32_t subframe_bps, - uint32_t order, - uint32_t qlp_coeff_precision, - uint32_t rice_parameter, - uint32_t rice_parameter_limit, - uint32_t min_partition_order, - uint32_t max_partition_order, - FLAC__bool do_escape_coding, - uint32_t rice_parameter_search_dist, - FLAC__Subframe *subframe, - FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents -); -#endif - -static uint32_t evaluate_verbatim_subframe_( - FLAC__StreamEncoder *encoder, - const FLAC__int32 signal[], - uint32_t blocksize, - uint32_t subframe_bps, - FLAC__Subframe *subframe -); - -static uint32_t find_best_partition_order_( - struct FLAC__StreamEncoderPrivate *private_, - const FLAC__int32 residual[], - FLAC__uint64 abs_residual_partition_sums[], - uint32_t raw_bits_per_partition[], - uint32_t residual_samples, - uint32_t predictor_order, - uint32_t rice_parameter, - uint32_t rice_parameter_limit, - uint32_t min_partition_order, - uint32_t max_partition_order, - uint32_t bps, - FLAC__bool do_escape_coding, - uint32_t rice_parameter_search_dist, - FLAC__EntropyCodingMethod *best_ecm -); - -static void precompute_partition_info_sums_( - const FLAC__int32 residual[], - FLAC__uint64 abs_residual_partition_sums[], - uint32_t residual_samples, - uint32_t predictor_order, - uint32_t min_partition_order, - uint32_t max_partition_order, - uint32_t bps -); - -static void precompute_partition_info_escapes_( - const FLAC__int32 residual[], - uint32_t raw_bits_per_partition[], - uint32_t residual_samples, - uint32_t predictor_order, - uint32_t min_partition_order, - uint32_t max_partition_order -); - -static FLAC__bool set_partitioned_rice_( -#ifdef EXACT_RICE_BITS_CALCULATION - const FLAC__int32 residual[], -#endif - const FLAC__uint64 abs_residual_partition_sums[], - const uint32_t raw_bits_per_partition[], - const uint32_t residual_samples, - const uint32_t predictor_order, - const uint32_t suggested_rice_parameter, - const uint32_t rice_parameter_limit, - const uint32_t rice_parameter_search_dist, - const uint32_t partition_order, - const FLAC__bool search_for_escapes, - FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, - uint32_t *bits -); - -static uint32_t get_wasted_bits_(FLAC__int32 signal[], uint32_t samples); - -/* verify-related routines: */ -static void append_to_verify_fifo_( - verify_input_fifo *fifo, - const FLAC__int32 * const input[], - uint32_t input_offset, - uint32_t channels, - uint32_t wide_samples -); - -static void append_to_verify_fifo_interleaved_( - verify_input_fifo *fifo, - const FLAC__int32 input[], - uint32_t input_offset, - uint32_t channels, - uint32_t wide_samples -); - -static FLAC__StreamDecoderReadStatus verify_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data); -static FLAC__StreamDecoderWriteStatus verify_write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); -static void verify_metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); -static void verify_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); - -static FLAC__StreamEncoderReadStatus file_read_callback_(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data); -static FLAC__StreamEncoderSeekStatus file_seek_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data); -static FLAC__StreamEncoderTellStatus file_tell_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data); -static FLAC__StreamEncoderWriteStatus file_write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, void *client_data); -static FILE *get_binary_stdout_(void); - - -/*********************************************************************** - * - * Private class data - * - ***********************************************************************/ - -typedef struct FLAC__StreamEncoderPrivate { - uint32_t input_capacity; /* current size (in samples) of the signal and residual buffers */ - FLAC__int32 *integer_signal[FLAC__MAX_CHANNELS]; /* the integer version of the input signal */ - FLAC__int32 *integer_signal_mid_side[2]; /* the integer version of the mid-side input signal (stereo only) */ -#ifndef FLAC__INTEGER_ONLY_LIBRARY - FLAC__real *real_signal[FLAC__MAX_CHANNELS]; /* (@@@ currently unused) the floating-point version of the input signal */ - FLAC__real *real_signal_mid_side[2]; /* (@@@ currently unused) the floating-point version of the mid-side input signal (stereo only) */ - FLAC__real *window[FLAC__MAX_APODIZATION_FUNCTIONS]; /* the pre-computed floating-point window for each apodization function */ - FLAC__real *windowed_signal; /* the integer_signal[] * current window[] */ -#endif - uint32_t subframe_bps[FLAC__MAX_CHANNELS]; /* the effective bits per sample of the input signal (stream bps - wasted bits) */ - uint32_t subframe_bps_mid_side[2]; /* the effective bits per sample of the mid-side input signal (stream bps - wasted bits + 0/1) */ - FLAC__int32 *residual_workspace[FLAC__MAX_CHANNELS][2]; /* each channel has a candidate and best workspace where the subframe residual signals will be stored */ - FLAC__int32 *residual_workspace_mid_side[2][2]; - FLAC__Subframe subframe_workspace[FLAC__MAX_CHANNELS][2]; - FLAC__Subframe subframe_workspace_mid_side[2][2]; - FLAC__Subframe *subframe_workspace_ptr[FLAC__MAX_CHANNELS][2]; - FLAC__Subframe *subframe_workspace_ptr_mid_side[2][2]; - FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents_workspace[FLAC__MAX_CHANNELS][2]; - FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents_workspace_mid_side[FLAC__MAX_CHANNELS][2]; - FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents_workspace_ptr[FLAC__MAX_CHANNELS][2]; - FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents_workspace_ptr_mid_side[FLAC__MAX_CHANNELS][2]; - uint32_t best_subframe[FLAC__MAX_CHANNELS]; /* index (0 or 1) into 2nd dimension of the above workspaces */ - uint32_t best_subframe_mid_side[2]; - uint32_t best_subframe_bits[FLAC__MAX_CHANNELS]; /* size in bits of the best subframe for each channel */ - uint32_t best_subframe_bits_mid_side[2]; - FLAC__uint64 *abs_residual_partition_sums; /* workspace where the sum of abs(candidate residual) for each partition is stored */ - uint32_t *raw_bits_per_partition; /* workspace where the sum of silog2(candidate residual) for each partition is stored */ - FLAC__BitWriter *frame; /* the current frame being worked on */ - uint32_t loose_mid_side_stereo_frames; /* rounded number of frames the encoder will use before trying both independent and mid/side frames again */ - uint32_t loose_mid_side_stereo_frame_count; /* number of frames using the current channel assignment */ - FLAC__ChannelAssignment last_channel_assignment; - FLAC__StreamMetadata streaminfo; /* scratchpad for STREAMINFO as it is built */ - FLAC__StreamMetadata_SeekTable *seek_table; /* pointer into encoder->protected_->metadata_ where the seek table is */ - uint32_t current_sample_number; - uint32_t current_frame_number; - FLAC__MD5Context md5context; - FLAC__CPUInfo cpuinfo; - void (*local_precompute_partition_info_sums)(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[], uint32_t residual_samples, uint32_t predictor_order, uint32_t min_partition_order, uint32_t max_partition_order, uint32_t bps); -#ifndef FLAC__INTEGER_ONLY_LIBRARY - uint32_t (*local_fixed_compute_best_predictor)(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); - uint32_t (*local_fixed_compute_best_predictor_wide)(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); -#else - uint32_t (*local_fixed_compute_best_predictor)(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); - uint32_t (*local_fixed_compute_best_predictor_wide)(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); -#endif -#ifndef FLAC__INTEGER_ONLY_LIBRARY - void (*local_lpc_compute_autocorrelation)(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]); - void (*local_lpc_compute_residual_from_qlp_coefficients)(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); - void (*local_lpc_compute_residual_from_qlp_coefficients_64bit)(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); - void (*local_lpc_compute_residual_from_qlp_coefficients_16bit)(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); -#endif - FLAC__bool disable_constant_subframes; - FLAC__bool disable_fixed_subframes; - FLAC__bool disable_verbatim_subframes; - FLAC__bool is_ogg; - FLAC__StreamEncoderReadCallback read_callback; /* currently only needed for Ogg FLAC */ - FLAC__StreamEncoderSeekCallback seek_callback; - FLAC__StreamEncoderTellCallback tell_callback; - FLAC__StreamEncoderWriteCallback write_callback; - FLAC__StreamEncoderMetadataCallback metadata_callback; - FLAC__StreamEncoderProgressCallback progress_callback; - void *client_data; - uint32_t first_seekpoint_to_check; - FILE *file; /* only used when encoding to a file */ - FLAC__uint64 bytes_written; - FLAC__uint64 samples_written; - uint32_t frames_written; - uint32_t total_frames_estimate; - /* unaligned (original) pointers to allocated data */ - FLAC__int32 *integer_signal_unaligned[FLAC__MAX_CHANNELS]; - FLAC__int32 *integer_signal_mid_side_unaligned[2]; -#ifndef FLAC__INTEGER_ONLY_LIBRARY - FLAC__real *real_signal_unaligned[FLAC__MAX_CHANNELS]; /* (@@@ currently unused) */ - FLAC__real *real_signal_mid_side_unaligned[2]; /* (@@@ currently unused) */ - FLAC__real *window_unaligned[FLAC__MAX_APODIZATION_FUNCTIONS]; - FLAC__real *windowed_signal_unaligned; -#endif - FLAC__int32 *residual_workspace_unaligned[FLAC__MAX_CHANNELS][2]; - FLAC__int32 *residual_workspace_mid_side_unaligned[2][2]; - FLAC__uint64 *abs_residual_partition_sums_unaligned; - uint32_t *raw_bits_per_partition_unaligned; - /* - * These fields have been moved here from private function local - * declarations merely to save stack space during encoding. - */ -#ifndef FLAC__INTEGER_ONLY_LIBRARY - FLAC__real lp_coeff[FLAC__MAX_LPC_ORDER][FLAC__MAX_LPC_ORDER]; /* from process_subframe_() */ -#endif - FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents_extra[2]; /* from find_best_partition_order_() */ - /* - * The data for the verify section - */ - struct { - FLAC__StreamDecoder *decoder; - EncoderStateHint state_hint; - FLAC__bool needs_magic_hack; - verify_input_fifo input_fifo; - verify_output output; - struct { - FLAC__uint64 absolute_sample; - uint32_t frame_number; - uint32_t channel; - uint32_t sample; - FLAC__int32 expected; - FLAC__int32 got; - } error_stats; - } verify; - FLAC__bool is_being_deleted; /* if true, call to ..._finish() from ..._delete() will not call the callbacks */ -} FLAC__StreamEncoderPrivate; - -/*********************************************************************** - * - * Public static class data - * - ***********************************************************************/ - -FLAC_API const char * const FLAC__StreamEncoderStateString[] = { - "FLAC__STREAM_ENCODER_OK", - "FLAC__STREAM_ENCODER_UNINITIALIZED", - "FLAC__STREAM_ENCODER_OGG_ERROR", - "FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR", - "FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA", - "FLAC__STREAM_ENCODER_CLIENT_ERROR", - "FLAC__STREAM_ENCODER_IO_ERROR", - "FLAC__STREAM_ENCODER_FRAMING_ERROR", - "FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR" -}; - -FLAC_API const char * const FLAC__StreamEncoderInitStatusString[] = { - "FLAC__STREAM_ENCODER_INIT_STATUS_OK", - "FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR", - "FLAC__STREAM_ENCODER_INIT_STATUS_UNSUPPORTED_CONTAINER", - "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_CALLBACKS", - "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_NUMBER_OF_CHANNELS", - "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BITS_PER_SAMPLE", - "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_SAMPLE_RATE", - "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BLOCK_SIZE", - "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_MAX_LPC_ORDER", - "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_QLP_COEFF_PRECISION", - "FLAC__STREAM_ENCODER_INIT_STATUS_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER", - "FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE", - "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA", - "FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED" -}; - -FLAC_API const char * const FLAC__StreamEncoderReadStatusString[] = { - "FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE", - "FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM", - "FLAC__STREAM_ENCODER_READ_STATUS_ABORT", - "FLAC__STREAM_ENCODER_READ_STATUS_UNSUPPORTED" -}; - -FLAC_API const char * const FLAC__StreamEncoderWriteStatusString[] = { - "FLAC__STREAM_ENCODER_WRITE_STATUS_OK", - "FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR" -}; - -FLAC_API const char * const FLAC__StreamEncoderSeekStatusString[] = { - "FLAC__STREAM_ENCODER_SEEK_STATUS_OK", - "FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR", - "FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED" -}; - -FLAC_API const char * const FLAC__StreamEncoderTellStatusString[] = { - "FLAC__STREAM_ENCODER_TELL_STATUS_OK", - "FLAC__STREAM_ENCODER_TELL_STATUS_ERROR", - "FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED" -}; - -/* Number of samples that will be overread to watch for end of stream. By - * 'overread', we mean that the FLAC__stream_encoder_process*() calls will - * always try to read blocksize+1 samples before encoding a block, so that - * even if the stream has a total sample count that is an integral multiple - * of the blocksize, we will still notice when we are encoding the last - * block. This is needed, for example, to correctly set the end-of-stream - * marker in Ogg FLAC. - * - * WATCHOUT: some parts of the code assert that OVERREAD_ == 1 and there's - * not really any reason to change it. - */ -static const uint32_t OVERREAD_ = 1; - -/*********************************************************************** - * - * Class constructor/destructor - * - */ -FLAC_API FLAC__StreamEncoder *FLAC__stream_encoder_new(void) -{ - FLAC__StreamEncoder *encoder; - uint32_t i; - - FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */ - - encoder = calloc(1, sizeof(FLAC__StreamEncoder)); - if(encoder == 0) { - return 0; - } - - encoder->protected_ = calloc(1, sizeof(FLAC__StreamEncoderProtected)); - if(encoder->protected_ == 0) { - free(encoder); - return 0; - } - - encoder->private_ = calloc(1, sizeof(FLAC__StreamEncoderPrivate)); - if(encoder->private_ == 0) { - free(encoder->protected_); - free(encoder); - return 0; - } - - encoder->private_->frame = FLAC__bitwriter_new(); - if(encoder->private_->frame == 0) { - free(encoder->private_); - free(encoder->protected_); - free(encoder); - return 0; - } - - encoder->private_->file = 0; - - set_defaults_(encoder); - - encoder->private_->is_being_deleted = false; - - for(i = 0; i < FLAC__MAX_CHANNELS; i++) { - encoder->private_->subframe_workspace_ptr[i][0] = &encoder->private_->subframe_workspace[i][0]; - encoder->private_->subframe_workspace_ptr[i][1] = &encoder->private_->subframe_workspace[i][1]; - } - for(i = 0; i < 2; i++) { - encoder->private_->subframe_workspace_ptr_mid_side[i][0] = &encoder->private_->subframe_workspace_mid_side[i][0]; - encoder->private_->subframe_workspace_ptr_mid_side[i][1] = &encoder->private_->subframe_workspace_mid_side[i][1]; - } - for(i = 0; i < FLAC__MAX_CHANNELS; i++) { - encoder->private_->partitioned_rice_contents_workspace_ptr[i][0] = &encoder->private_->partitioned_rice_contents_workspace[i][0]; - encoder->private_->partitioned_rice_contents_workspace_ptr[i][1] = &encoder->private_->partitioned_rice_contents_workspace[i][1]; - } - for(i = 0; i < 2; i++) { - encoder->private_->partitioned_rice_contents_workspace_ptr_mid_side[i][0] = &encoder->private_->partitioned_rice_contents_workspace_mid_side[i][0]; - encoder->private_->partitioned_rice_contents_workspace_ptr_mid_side[i][1] = &encoder->private_->partitioned_rice_contents_workspace_mid_side[i][1]; - } - - for(i = 0; i < FLAC__MAX_CHANNELS; i++) { - FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace[i][0]); - FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace[i][1]); - } - for(i = 0; i < 2; i++) { - FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][0]); - FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][1]); - } - for(i = 0; i < 2; i++) - FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_extra[i]); - - encoder->protected_->state = FLAC__STREAM_ENCODER_UNINITIALIZED; - - return encoder; -} - -FLAC_API void FLAC__stream_encoder_delete(FLAC__StreamEncoder *encoder) -{ - uint32_t i; - - if (encoder == NULL) - return ; - - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->private_->frame); - - encoder->private_->is_being_deleted = true; - - (void)FLAC__stream_encoder_finish(encoder); - - if(0 != encoder->private_->verify.decoder) - FLAC__stream_decoder_delete(encoder->private_->verify.decoder); - - for(i = 0; i < FLAC__MAX_CHANNELS; i++) { - FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace[i][0]); - FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace[i][1]); - } - for(i = 0; i < 2; i++) { - FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][0]); - FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][1]); - } - for(i = 0; i < 2; i++) - FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_extra[i]); - - FLAC__bitwriter_delete(encoder->private_->frame); - free(encoder->private_); - free(encoder->protected_); - free(encoder); -} - -/*********************************************************************** - * - * Public class methods - * - ***********************************************************************/ - -static FLAC__StreamEncoderInitStatus init_stream_internal_( - FLAC__StreamEncoder *encoder, - FLAC__StreamEncoderReadCallback read_callback, - FLAC__StreamEncoderWriteCallback write_callback, - FLAC__StreamEncoderSeekCallback seek_callback, - FLAC__StreamEncoderTellCallback tell_callback, - FLAC__StreamEncoderMetadataCallback metadata_callback, - void *client_data, - FLAC__bool is_ogg -) -{ - uint32_t i; - FLAC__bool metadata_has_seektable, metadata_has_vorbis_comment, metadata_picture_has_type1, metadata_picture_has_type2; - - FLAC__ASSERT(0 != encoder); - - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED; - - if(FLAC__HAS_OGG == 0 && is_ogg) - return FLAC__STREAM_ENCODER_INIT_STATUS_UNSUPPORTED_CONTAINER; - - if(0 == write_callback || (seek_callback && 0 == tell_callback)) - return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_CALLBACKS; - - if(encoder->protected_->channels == 0 || encoder->protected_->channels > FLAC__MAX_CHANNELS) - return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_NUMBER_OF_CHANNELS; - - if(encoder->protected_->channels != 2) { - encoder->protected_->do_mid_side_stereo = false; - encoder->protected_->loose_mid_side_stereo = false; - } - else if(!encoder->protected_->do_mid_side_stereo) - encoder->protected_->loose_mid_side_stereo = false; - - if(encoder->protected_->bits_per_sample >= 32) - encoder->protected_->do_mid_side_stereo = false; /* since we currently do 32-bit math, the side channel would have 33 bps and overflow */ - - if(encoder->protected_->bits_per_sample < FLAC__MIN_BITS_PER_SAMPLE || encoder->protected_->bits_per_sample > FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE) - return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BITS_PER_SAMPLE; - - if(!FLAC__format_sample_rate_is_valid(encoder->protected_->sample_rate)) - return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_SAMPLE_RATE; - - if(encoder->protected_->blocksize == 0) { - if(encoder->protected_->max_lpc_order == 0) - encoder->protected_->blocksize = 1152; - else - encoder->protected_->blocksize = 4096; - } - - if(encoder->protected_->blocksize < FLAC__MIN_BLOCK_SIZE || encoder->protected_->blocksize > FLAC__MAX_BLOCK_SIZE) - return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BLOCK_SIZE; - - if(encoder->protected_->max_lpc_order > FLAC__MAX_LPC_ORDER) - return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_MAX_LPC_ORDER; - - if(encoder->protected_->blocksize < encoder->protected_->max_lpc_order) - return FLAC__STREAM_ENCODER_INIT_STATUS_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER; - - if(encoder->protected_->qlp_coeff_precision == 0) { - if(encoder->protected_->bits_per_sample < 16) { - /* @@@ need some data about how to set this here w.r.t. blocksize and sample rate */ - /* @@@ until then we'll make a guess */ - encoder->protected_->qlp_coeff_precision = flac_max(FLAC__MIN_QLP_COEFF_PRECISION, 2 + encoder->protected_->bits_per_sample / 2); - } - else if(encoder->protected_->bits_per_sample == 16) { - if(encoder->protected_->blocksize <= 192) - encoder->protected_->qlp_coeff_precision = 7; - else if(encoder->protected_->blocksize <= 384) - encoder->protected_->qlp_coeff_precision = 8; - else if(encoder->protected_->blocksize <= 576) - encoder->protected_->qlp_coeff_precision = 9; - else if(encoder->protected_->blocksize <= 1152) - encoder->protected_->qlp_coeff_precision = 10; - else if(encoder->protected_->blocksize <= 2304) - encoder->protected_->qlp_coeff_precision = 11; - else if(encoder->protected_->blocksize <= 4608) - encoder->protected_->qlp_coeff_precision = 12; - else - encoder->protected_->qlp_coeff_precision = 13; - } - else { - if(encoder->protected_->blocksize <= 384) - encoder->protected_->qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION-2; - else if(encoder->protected_->blocksize <= 1152) - encoder->protected_->qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION-1; - else - encoder->protected_->qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION; - } - FLAC__ASSERT(encoder->protected_->qlp_coeff_precision <= FLAC__MAX_QLP_COEFF_PRECISION); - } - else if(encoder->protected_->qlp_coeff_precision < FLAC__MIN_QLP_COEFF_PRECISION || encoder->protected_->qlp_coeff_precision > FLAC__MAX_QLP_COEFF_PRECISION) - return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_QLP_COEFF_PRECISION; - - if(encoder->protected_->streamable_subset) { - if(!FLAC__format_blocksize_is_subset(encoder->protected_->blocksize, encoder->protected_->sample_rate)) - return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE; - if(!FLAC__format_sample_rate_is_subset(encoder->protected_->sample_rate)) - return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE; - if( - encoder->protected_->bits_per_sample != 8 && - encoder->protected_->bits_per_sample != 12 && - encoder->protected_->bits_per_sample != 16 && - encoder->protected_->bits_per_sample != 20 && - encoder->protected_->bits_per_sample != 24 - ) - return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE; - if(encoder->protected_->max_residual_partition_order > FLAC__SUBSET_MAX_RICE_PARTITION_ORDER) - return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE; - if( - encoder->protected_->sample_rate <= 48000 && - ( - encoder->protected_->blocksize > FLAC__SUBSET_MAX_BLOCK_SIZE_48000HZ || - encoder->protected_->max_lpc_order > FLAC__SUBSET_MAX_LPC_ORDER_48000HZ - ) - ) { - return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE; - } - } - - if(encoder->protected_->max_residual_partition_order >= (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN)) - encoder->protected_->max_residual_partition_order = (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN) - 1; - if(encoder->protected_->min_residual_partition_order >= encoder->protected_->max_residual_partition_order) - encoder->protected_->min_residual_partition_order = encoder->protected_->max_residual_partition_order; - -#if FLAC__HAS_OGG - /* reorder metadata if necessary to ensure that any VORBIS_COMMENT is the first, according to the mapping spec */ - if(is_ogg && 0 != encoder->protected_->metadata && encoder->protected_->num_metadata_blocks > 1) { - uint32_t i1; - for(i1 = 1; i1 < encoder->protected_->num_metadata_blocks; i1++) { - if(0 != encoder->protected_->metadata[i1] && encoder->protected_->metadata[i1]->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) { - FLAC__StreamMetadata *vc = encoder->protected_->metadata[i1]; - for( ; i1 > 0; i1--) - encoder->protected_->metadata[i1] = encoder->protected_->metadata[i1-1]; - encoder->protected_->metadata[0] = vc; - break; - } - } - } -#endif - /* keep track of any SEEKTABLE block */ - if(0 != encoder->protected_->metadata && encoder->protected_->num_metadata_blocks > 0) { - uint32_t i2; - for(i2 = 0; i2 < encoder->protected_->num_metadata_blocks; i2++) { - if(0 != encoder->protected_->metadata[i2] && encoder->protected_->metadata[i2]->type == FLAC__METADATA_TYPE_SEEKTABLE) { - encoder->private_->seek_table = &encoder->protected_->metadata[i2]->data.seek_table; - break; /* take only the first one */ - } - } - } - - /* validate metadata */ - if(0 == encoder->protected_->metadata && encoder->protected_->num_metadata_blocks > 0) - return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; - metadata_has_seektable = false; - metadata_has_vorbis_comment = false; - metadata_picture_has_type1 = false; - metadata_picture_has_type2 = false; - for(i = 0; i < encoder->protected_->num_metadata_blocks; i++) { - const FLAC__StreamMetadata *m = encoder->protected_->metadata[i]; - if(m->type == FLAC__METADATA_TYPE_STREAMINFO) - return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; - else if(m->type == FLAC__METADATA_TYPE_SEEKTABLE) { - if(metadata_has_seektable) /* only one is allowed */ - return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; - metadata_has_seektable = true; - if(!FLAC__format_seektable_is_legal(&m->data.seek_table)) - return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; - } - else if(m->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) { - if(metadata_has_vorbis_comment) /* only one is allowed */ - return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; - metadata_has_vorbis_comment = true; - } - else if(m->type == FLAC__METADATA_TYPE_CUESHEET) { - if(!FLAC__format_cuesheet_is_legal(&m->data.cue_sheet, m->data.cue_sheet.is_cd, /*violation=*/0)) - return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; - } - else if(m->type == FLAC__METADATA_TYPE_PICTURE) { - if(!FLAC__format_picture_is_legal(&m->data.picture, /*violation=*/0)) - return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; - if(m->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD) { - if(metadata_picture_has_type1) /* there should only be 1 per stream */ - return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; - metadata_picture_has_type1 = true; - /* standard icon must be 32x32 pixel PNG */ - if( - m->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD && - ( - (strcmp(m->data.picture.mime_type, "image/png") && strcmp(m->data.picture.mime_type, "-->")) || - m->data.picture.width != 32 || - m->data.picture.height != 32 - ) - ) - return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; - } - else if(m->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON) { - if(metadata_picture_has_type2) /* there should only be 1 per stream */ - return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; - metadata_picture_has_type2 = true; - } - } - } - - encoder->private_->input_capacity = 0; - for(i = 0; i < encoder->protected_->channels; i++) { - encoder->private_->integer_signal_unaligned[i] = encoder->private_->integer_signal[i] = 0; -#ifndef FLAC__INTEGER_ONLY_LIBRARY - encoder->private_->real_signal_unaligned[i] = encoder->private_->real_signal[i] = 0; -#endif - } - for(i = 0; i < 2; i++) { - encoder->private_->integer_signal_mid_side_unaligned[i] = encoder->private_->integer_signal_mid_side[i] = 0; -#ifndef FLAC__INTEGER_ONLY_LIBRARY - encoder->private_->real_signal_mid_side_unaligned[i] = encoder->private_->real_signal_mid_side[i] = 0; -#endif - } -#ifndef FLAC__INTEGER_ONLY_LIBRARY - for(i = 0; i < encoder->protected_->num_apodizations; i++) - encoder->private_->window_unaligned[i] = encoder->private_->window[i] = 0; - encoder->private_->windowed_signal_unaligned = encoder->private_->windowed_signal = 0; -#endif - for(i = 0; i < encoder->protected_->channels; i++) { - encoder->private_->residual_workspace_unaligned[i][0] = encoder->private_->residual_workspace[i][0] = 0; - encoder->private_->residual_workspace_unaligned[i][1] = encoder->private_->residual_workspace[i][1] = 0; - encoder->private_->best_subframe[i] = 0; - } - for(i = 0; i < 2; i++) { - encoder->private_->residual_workspace_mid_side_unaligned[i][0] = encoder->private_->residual_workspace_mid_side[i][0] = 0; - encoder->private_->residual_workspace_mid_side_unaligned[i][1] = encoder->private_->residual_workspace_mid_side[i][1] = 0; - encoder->private_->best_subframe_mid_side[i] = 0; - } - encoder->private_->abs_residual_partition_sums_unaligned = encoder->private_->abs_residual_partition_sums = 0; - encoder->private_->raw_bits_per_partition_unaligned = encoder->private_->raw_bits_per_partition = 0; -#ifndef FLAC__INTEGER_ONLY_LIBRARY - encoder->private_->loose_mid_side_stereo_frames = (uint32_t)((double)encoder->protected_->sample_rate * 0.4 / (double)encoder->protected_->blocksize + 0.5); -#else - /* 26214 is the approximate fixed-point equivalent to 0.4 (0.4 * 2^16) */ - /* sample rate can be up to 655350 Hz, and thus use 20 bits, so we do the multiply÷ by hand */ - FLAC__ASSERT(FLAC__MAX_SAMPLE_RATE <= 655350); - FLAC__ASSERT(FLAC__MAX_BLOCK_SIZE <= 65535); - FLAC__ASSERT(encoder->protected_->sample_rate <= 655350); - FLAC__ASSERT(encoder->protected_->blocksize <= 65535); - encoder->private_->loose_mid_side_stereo_frames = (uint32_t)FLAC__fixedpoint_trunc((((FLAC__uint64)(encoder->protected_->sample_rate) * (FLAC__uint64)(26214)) << 16) / (encoder->protected_->blocksize<<16) + FLAC__FP_ONE_HALF); -#endif - if(encoder->private_->loose_mid_side_stereo_frames == 0) - encoder->private_->loose_mid_side_stereo_frames = 1; - encoder->private_->loose_mid_side_stereo_frame_count = 0; - encoder->private_->current_sample_number = 0; - encoder->private_->current_frame_number = 0; - - /* - * get the CPU info and set the function pointers - */ - FLAC__cpu_info(&encoder->private_->cpuinfo); - /* first default to the non-asm routines */ -#ifndef FLAC__INTEGER_ONLY_LIBRARY - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation; -#endif - encoder->private_->local_precompute_partition_info_sums = precompute_partition_info_sums_; - encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor; - encoder->private_->local_fixed_compute_best_predictor_wide = FLAC__fixed_compute_best_predictor_wide; -#ifndef FLAC__INTEGER_ONLY_LIBRARY - encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients; - encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide; - encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients; -#endif - /* now override with asm where appropriate */ -#ifndef FLAC__INTEGER_ONLY_LIBRARY -# ifndef FLAC__NO_ASM -#if defined(FLAC__CPU_PPC64) && defined(FLAC__USE_VSX) -#ifdef FLAC__HAS_TARGET_POWER8 -#ifdef FLAC__HAS_TARGET_POWER9 - if (encoder->private_->cpuinfo.ppc.arch_3_00) { - if(encoder->protected_->max_lpc_order < 4) - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_power9_vsx_lag_4; - else if(encoder->protected_->max_lpc_order < 8) - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_power9_vsx_lag_8; - else if(encoder->protected_->max_lpc_order < 12) - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_power9_vsx_lag_12; - else if(encoder->protected_->max_lpc_order < 16) - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_power9_vsx_lag_16; - else - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation; - } else -#endif - if (encoder->private_->cpuinfo.ppc.arch_2_07) { - if(encoder->protected_->max_lpc_order < 4) - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_power8_vsx_lag_4; - else if(encoder->protected_->max_lpc_order < 8) - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_power8_vsx_lag_8; - else if(encoder->protected_->max_lpc_order < 12) - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_power8_vsx_lag_12; - else if(encoder->protected_->max_lpc_order < 16) - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_power8_vsx_lag_16; - else - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation; - } -#endif -#endif - if(encoder->private_->cpuinfo.use_asm) { -# ifdef FLAC__CPU_IA32 - FLAC__ASSERT(encoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_IA32); -# ifdef FLAC__HAS_NASM - if (encoder->private_->cpuinfo.x86.sse) { - if(encoder->protected_->max_lpc_order < 4) - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_4_old; - else if(encoder->protected_->max_lpc_order < 8) - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_8_old; - else if(encoder->protected_->max_lpc_order < 12) - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_12_old; - else if(encoder->protected_->max_lpc_order < 16) - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_16_old; - else - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32; - } - else - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32; - - encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide_asm_ia32; /* OPT_IA32: was really necessary for GCC < 4.9 */ - if (encoder->private_->cpuinfo.x86.mmx) { - encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32; - encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx; - } - else { - encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32; - encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32; - } - - if (encoder->private_->cpuinfo.x86.mmx && encoder->private_->cpuinfo.x86.cmov) - encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_asm_ia32_mmx_cmov; -# endif /* FLAC__HAS_NASM */ -# if FLAC__HAS_X86INTRIN -# if defined FLAC__SSE_SUPPORTED - if (encoder->private_->cpuinfo.x86.sse) { - if (encoder->private_->cpuinfo.x86.sse42 || !encoder->private_->cpuinfo.x86.intel) { /* use new autocorrelation functions */ - if(encoder->protected_->max_lpc_order < 4) - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4_new; - else if(encoder->protected_->max_lpc_order < 8) - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8_new; - else if(encoder->protected_->max_lpc_order < 12) - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12_new; - else if(encoder->protected_->max_lpc_order < 16) - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16_new; - else - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation; - } - else { /* use old autocorrelation functions */ - if(encoder->protected_->max_lpc_order < 4) - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4_old; - else if(encoder->protected_->max_lpc_order < 8) - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8_old; - else if(encoder->protected_->max_lpc_order < 12) - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12_old; - else if(encoder->protected_->max_lpc_order < 16) - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16_old; - else - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation; - } - } -# endif - -# ifdef FLAC__SSE2_SUPPORTED - if (encoder->private_->cpuinfo.x86.sse2) { - encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse2; - encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_sse2; - } -# endif -# ifdef FLAC__SSE4_1_SUPPORTED - if (encoder->private_->cpuinfo.x86.sse41) { - encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse41; - encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_sse41; - } -# endif -# ifdef FLAC__AVX2_SUPPORTED - if (encoder->private_->cpuinfo.x86.avx2) { - encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_avx2; - encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_avx2; - encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_avx2; - } -# endif - -# ifdef FLAC__SSE2_SUPPORTED - if (encoder->private_->cpuinfo.x86.sse2) { - encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_intrin_sse2; - encoder->private_->local_fixed_compute_best_predictor_wide = FLAC__fixed_compute_best_predictor_wide_intrin_sse2; - } -# endif -# ifdef FLAC__SSSE3_SUPPORTED - if (encoder->private_->cpuinfo.x86.ssse3) { - encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_intrin_ssse3; - encoder->private_->local_fixed_compute_best_predictor_wide = FLAC__fixed_compute_best_predictor_wide_intrin_ssse3; - } -# endif -# endif /* FLAC__HAS_X86INTRIN */ -# elif defined FLAC__CPU_X86_64 - FLAC__ASSERT(encoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_X86_64); -# if FLAC__HAS_X86INTRIN -# ifdef FLAC__SSE_SUPPORTED - if(encoder->private_->cpuinfo.x86.sse42 || !encoder->private_->cpuinfo.x86.intel) { /* use new autocorrelation functions */ - if(encoder->protected_->max_lpc_order < 4) - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4_new; - else if(encoder->protected_->max_lpc_order < 8) - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8_new; - else if(encoder->protected_->max_lpc_order < 12) - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12_new; - else if(encoder->protected_->max_lpc_order < 16) - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16_new; - } - else { - if(encoder->protected_->max_lpc_order < 4) - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4_old; - else if(encoder->protected_->max_lpc_order < 8) - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8_old; - else if(encoder->protected_->max_lpc_order < 12) - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12_old; - else if(encoder->protected_->max_lpc_order < 16) - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16_old; - } -# endif - -# ifdef FLAC__SSE2_SUPPORTED - encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_sse2; -# endif -# ifdef FLAC__SSE4_1_SUPPORTED - if(encoder->private_->cpuinfo.x86.sse41) { - encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse41; - } -# endif -# ifdef FLAC__AVX2_SUPPORTED - if(encoder->private_->cpuinfo.x86.avx2) { - encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_avx2; - encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_avx2; - encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_avx2; - } -# endif - -# ifdef FLAC__SSE2_SUPPORTED - encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_intrin_sse2; - encoder->private_->local_fixed_compute_best_predictor_wide = FLAC__fixed_compute_best_predictor_wide_intrin_sse2; -# endif -# ifdef FLAC__SSSE3_SUPPORTED - if (encoder->private_->cpuinfo.x86.ssse3) { - encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_intrin_ssse3; - encoder->private_->local_fixed_compute_best_predictor_wide = FLAC__fixed_compute_best_predictor_wide_intrin_ssse3; - } -# endif -# endif /* FLAC__HAS_X86INTRIN */ -# endif /* FLAC__CPU_... */ - } -# endif /* !FLAC__NO_ASM */ -#endif /* !FLAC__INTEGER_ONLY_LIBRARY */ -#if !defined FLAC__NO_ASM && FLAC__HAS_X86INTRIN - if(encoder->private_->cpuinfo.use_asm) { -# if defined FLAC__CPU_IA32 -# ifdef FLAC__SSE2_SUPPORTED - if (encoder->private_->cpuinfo.x86.sse2) - encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_sse2; -# endif -# ifdef FLAC__SSSE3_SUPPORTED - if (encoder->private_->cpuinfo.x86.ssse3) - encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_ssse3; -# endif -# ifdef FLAC__AVX2_SUPPORTED - if (encoder->private_->cpuinfo.x86.avx2) - encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_avx2; -# endif -# elif defined FLAC__CPU_X86_64 -# ifdef FLAC__SSE2_SUPPORTED - encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_sse2; -# endif -# ifdef FLAC__SSSE3_SUPPORTED - if(encoder->private_->cpuinfo.x86.ssse3) - encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_ssse3; -# endif -# ifdef FLAC__AVX2_SUPPORTED - if(encoder->private_->cpuinfo.x86.avx2) - encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_avx2; -# endif -# endif /* FLAC__CPU_... */ - } -#endif /* !FLAC__NO_ASM && FLAC__HAS_X86INTRIN */ - - /* set state to OK; from here on, errors are fatal and we'll override the state then */ - encoder->protected_->state = FLAC__STREAM_ENCODER_OK; - -#if FLAC__HAS_OGG - encoder->private_->is_ogg = is_ogg; - if(is_ogg && !FLAC__ogg_encoder_aspect_init(&encoder->protected_->ogg_encoder_aspect)) { - encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR; - return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; - } -#endif - - encoder->private_->read_callback = read_callback; - encoder->private_->write_callback = write_callback; - encoder->private_->seek_callback = seek_callback; - encoder->private_->tell_callback = tell_callback; - encoder->private_->metadata_callback = metadata_callback; - encoder->private_->client_data = client_data; - - if(!resize_buffers_(encoder, encoder->protected_->blocksize)) { - /* the above function sets the state for us in case of an error */ - return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; - } - - if(!FLAC__bitwriter_init(encoder->private_->frame)) { - encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; - return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; - } - - /* - * Set up the verify stuff if necessary - */ - if(encoder->protected_->verify) { - /* - * First, set up the fifo which will hold the - * original signal to compare against - */ - encoder->private_->verify.input_fifo.size = encoder->protected_->blocksize+OVERREAD_; - for(i = 0; i < encoder->protected_->channels; i++) { - if(0 == (encoder->private_->verify.input_fifo.data[i] = safe_malloc_mul_2op_p(sizeof(FLAC__int32), /*times*/encoder->private_->verify.input_fifo.size))) { - encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; - return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; - } - } - encoder->private_->verify.input_fifo.tail = 0; - - /* - * Now set up a stream decoder for verification - */ - if(0 == encoder->private_->verify.decoder) { - encoder->private_->verify.decoder = FLAC__stream_decoder_new(); - if(0 == encoder->private_->verify.decoder) { - encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR; - return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; - } - } - - if(FLAC__stream_decoder_init_stream(encoder->private_->verify.decoder, verify_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, verify_write_callback_, verify_metadata_callback_, verify_error_callback_, /*client_data=*/encoder) != FLAC__STREAM_DECODER_INIT_STATUS_OK) { - encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR; - return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; - } - } - encoder->private_->verify.error_stats.absolute_sample = 0; - encoder->private_->verify.error_stats.frame_number = 0; - encoder->private_->verify.error_stats.channel = 0; - encoder->private_->verify.error_stats.sample = 0; - encoder->private_->verify.error_stats.expected = 0; - encoder->private_->verify.error_stats.got = 0; - - /* - * These must be done before we write any metadata, because that - * calls the write_callback, which uses these values. - */ - encoder->private_->first_seekpoint_to_check = 0; - encoder->private_->samples_written = 0; - encoder->protected_->streaminfo_offset = 0; - encoder->protected_->seektable_offset = 0; - encoder->protected_->audio_offset = 0; - - /* - * write the stream header - */ - if(encoder->protected_->verify) - encoder->private_->verify.state_hint = ENCODER_IN_MAGIC; - if(!FLAC__bitwriter_write_raw_uint32(encoder->private_->frame, FLAC__STREAM_SYNC, FLAC__STREAM_SYNC_LEN)) { - encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; - return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; - } - if(!write_bitbuffer_(encoder, 0, /*is_last_block=*/false)) { - /* the above function sets the state for us in case of an error */ - return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; - } - - /* - * write the STREAMINFO metadata block - */ - if(encoder->protected_->verify) - encoder->private_->verify.state_hint = ENCODER_IN_METADATA; - encoder->private_->streaminfo.type = FLAC__METADATA_TYPE_STREAMINFO; - encoder->private_->streaminfo.is_last = false; /* we will have at a minimum a VORBIS_COMMENT afterwards */ - encoder->private_->streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH; - encoder->private_->streaminfo.data.stream_info.min_blocksize = encoder->protected_->blocksize; /* this encoder uses the same blocksize for the whole stream */ - encoder->private_->streaminfo.data.stream_info.max_blocksize = encoder->protected_->blocksize; - encoder->private_->streaminfo.data.stream_info.min_framesize = 0; /* we don't know this yet; have to fill it in later */ - encoder->private_->streaminfo.data.stream_info.max_framesize = 0; /* we don't know this yet; have to fill it in later */ - encoder->private_->streaminfo.data.stream_info.sample_rate = encoder->protected_->sample_rate; - encoder->private_->streaminfo.data.stream_info.channels = encoder->protected_->channels; - encoder->private_->streaminfo.data.stream_info.bits_per_sample = encoder->protected_->bits_per_sample; - encoder->private_->streaminfo.data.stream_info.total_samples = encoder->protected_->total_samples_estimate; /* we will replace this later with the real total */ - memset(encoder->private_->streaminfo.data.stream_info.md5sum, 0, 16); /* we don't know this yet; have to fill it in later */ - if(encoder->protected_->do_md5) - FLAC__MD5Init(&encoder->private_->md5context); - if(!FLAC__add_metadata_block(&encoder->private_->streaminfo, encoder->private_->frame)) { - encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; - return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; - } - if(!write_bitbuffer_(encoder, 0, /*is_last_block=*/false)) { - /* the above function sets the state for us in case of an error */ - return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; - } - - /* - * Now that the STREAMINFO block is written, we can init this to an - * absurdly-high value... - */ - encoder->private_->streaminfo.data.stream_info.min_framesize = (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN) - 1; - /* ... and clear this to 0 */ - encoder->private_->streaminfo.data.stream_info.total_samples = 0; - - /* - * Check to see if the supplied metadata contains a VORBIS_COMMENT; - * if not, we will write an empty one (FLAC__add_metadata_block() - * automatically supplies the vendor string). - * - * WATCHOUT: the Ogg FLAC mapping requires us to write this block after - * the STREAMINFO. (In the case that metadata_has_vorbis_comment is - * true it will have already insured that the metadata list is properly - * ordered.) - */ - if(!metadata_has_vorbis_comment) { - FLAC__StreamMetadata vorbis_comment; - vorbis_comment.type = FLAC__METADATA_TYPE_VORBIS_COMMENT; - vorbis_comment.is_last = (encoder->protected_->num_metadata_blocks == 0); - vorbis_comment.length = 4 + 4; /* MAGIC NUMBER */ - vorbis_comment.data.vorbis_comment.vendor_string.length = 0; - vorbis_comment.data.vorbis_comment.vendor_string.entry = 0; - vorbis_comment.data.vorbis_comment.num_comments = 0; - vorbis_comment.data.vorbis_comment.comments = 0; - if(!FLAC__add_metadata_block(&vorbis_comment, encoder->private_->frame)) { - encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; - return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; - } - if(!write_bitbuffer_(encoder, 0, /*is_last_block=*/false)) { - /* the above function sets the state for us in case of an error */ - return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; - } - } - - /* - * write the user's metadata blocks - */ - for(i = 0; i < encoder->protected_->num_metadata_blocks; i++) { - encoder->protected_->metadata[i]->is_last = (i == encoder->protected_->num_metadata_blocks - 1); - if(!FLAC__add_metadata_block(encoder->protected_->metadata[i], encoder->private_->frame)) { - encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; - return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; - } - if(!write_bitbuffer_(encoder, 0, /*is_last_block=*/false)) { - /* the above function sets the state for us in case of an error */ - return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; - } - } - - /* now that all the metadata is written, we save the stream offset */ - if(encoder->private_->tell_callback && encoder->private_->tell_callback(encoder, &encoder->protected_->audio_offset, encoder->private_->client_data) == FLAC__STREAM_ENCODER_TELL_STATUS_ERROR) { /* FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED just means we didn't get the offset; no error */ - encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; - return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; - } - - if(encoder->protected_->verify) - encoder->private_->verify.state_hint = ENCODER_IN_AUDIO; - - return FLAC__STREAM_ENCODER_INIT_STATUS_OK; -} - -FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_stream( - FLAC__StreamEncoder *encoder, - FLAC__StreamEncoderWriteCallback write_callback, - FLAC__StreamEncoderSeekCallback seek_callback, - FLAC__StreamEncoderTellCallback tell_callback, - FLAC__StreamEncoderMetadataCallback metadata_callback, - void *client_data -) -{ - return init_stream_internal_( - encoder, - /*read_callback=*/0, - write_callback, - seek_callback, - tell_callback, - metadata_callback, - client_data, - /*is_ogg=*/false - ); -} - -FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_stream( - FLAC__StreamEncoder *encoder, - FLAC__StreamEncoderReadCallback read_callback, - FLAC__StreamEncoderWriteCallback write_callback, - FLAC__StreamEncoderSeekCallback seek_callback, - FLAC__StreamEncoderTellCallback tell_callback, - FLAC__StreamEncoderMetadataCallback metadata_callback, - void *client_data -) -{ - return init_stream_internal_( - encoder, - read_callback, - write_callback, - seek_callback, - tell_callback, - metadata_callback, - client_data, - /*is_ogg=*/true - ); -} - -static FLAC__StreamEncoderInitStatus init_FILE_internal_( - FLAC__StreamEncoder *encoder, - FILE *file, - FLAC__StreamEncoderProgressCallback progress_callback, - void *client_data, - FLAC__bool is_ogg -) -{ - FLAC__StreamEncoderInitStatus init_status; - - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != file); - - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED; - - /* double protection */ - if(file == 0) { - encoder->protected_->state = FLAC__STREAM_ENCODER_IO_ERROR; - return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; - } - - /* - * To make sure that our file does not go unclosed after an error, we - * must assign the FILE pointer before any further error can occur in - * this routine. - */ - if(file == stdout) - file = get_binary_stdout_(); /* just to be safe */ - -#ifdef _WIN32 - /* - * Windows can suffer quite badly from disk fragmentation. This can be - * reduced significantly by setting the output buffer size to be 10MB. - */ - if(GetFileType((HANDLE)_get_osfhandle(_fileno(file))) == FILE_TYPE_DISK) - setvbuf(file, NULL, _IOFBF, 10*1024*1024); -#endif - encoder->private_->file = file; - - encoder->private_->progress_callback = progress_callback; - encoder->private_->bytes_written = 0; - encoder->private_->samples_written = 0; - encoder->private_->frames_written = 0; - - init_status = init_stream_internal_( - encoder, - encoder->private_->file == stdout? 0 : is_ogg? file_read_callback_ : 0, - file_write_callback_, - encoder->private_->file == stdout? 0 : file_seek_callback_, - encoder->private_->file == stdout? 0 : file_tell_callback_, - /*metadata_callback=*/0, - client_data, - is_ogg - ); - if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) { - /* the above function sets the state for us in case of an error */ - return init_status; - } - - { - uint32_t blocksize = FLAC__stream_encoder_get_blocksize(encoder); - - FLAC__ASSERT(blocksize != 0); - encoder->private_->total_frames_estimate = (uint32_t)((FLAC__stream_encoder_get_total_samples_estimate(encoder) + blocksize - 1) / blocksize); - } - - return init_status; -} - -FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_FILE( - FLAC__StreamEncoder *encoder, - FILE *file, - FLAC__StreamEncoderProgressCallback progress_callback, - void *client_data -) -{ - return init_FILE_internal_(encoder, file, progress_callback, client_data, /*is_ogg=*/false); -} - -FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_FILE( - FLAC__StreamEncoder *encoder, - FILE *file, - FLAC__StreamEncoderProgressCallback progress_callback, - void *client_data -) -{ - return init_FILE_internal_(encoder, file, progress_callback, client_data, /*is_ogg=*/true); -} - -static FLAC__StreamEncoderInitStatus init_file_internal_( - FLAC__StreamEncoder *encoder, - const char *filename, - FLAC__StreamEncoderProgressCallback progress_callback, - void *client_data, - FLAC__bool is_ogg -) -{ - FILE *file; - - FLAC__ASSERT(0 != encoder); - - /* - * To make sure that our file does not go unclosed after an error, we - * have to do the same entrance checks here that are later performed - * in FLAC__stream_encoder_init_FILE() before the FILE* is assigned. - */ - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED; - - file = filename? flac_fopen(filename, "w+b") : stdout; - - if(file == 0) { - encoder->protected_->state = FLAC__STREAM_ENCODER_IO_ERROR; - return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; - } - - return init_FILE_internal_(encoder, file, progress_callback, client_data, is_ogg); -} - -FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_file( - FLAC__StreamEncoder *encoder, - const char *filename, - FLAC__StreamEncoderProgressCallback progress_callback, - void *client_data -) -{ - return init_file_internal_(encoder, filename, progress_callback, client_data, /*is_ogg=*/false); -} - -FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_file( - FLAC__StreamEncoder *encoder, - const char *filename, - FLAC__StreamEncoderProgressCallback progress_callback, - void *client_data -) -{ - return init_file_internal_(encoder, filename, progress_callback, client_data, /*is_ogg=*/true); -} - -FLAC_API FLAC__bool FLAC__stream_encoder_finish(FLAC__StreamEncoder *encoder) -{ - FLAC__bool error = false; - - if (encoder == NULL) - return false; - - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - - if(encoder->protected_->state == FLAC__STREAM_ENCODER_UNINITIALIZED) - return true; - - if(encoder->protected_->state == FLAC__STREAM_ENCODER_OK && !encoder->private_->is_being_deleted) { - if(encoder->private_->current_sample_number != 0) { - const FLAC__bool is_fractional_block = encoder->protected_->blocksize != encoder->private_->current_sample_number; - encoder->protected_->blocksize = encoder->private_->current_sample_number; - if(!process_frame_(encoder, is_fractional_block, /*is_last_block=*/true)) - error = true; - } - } - - if(encoder->protected_->do_md5) - FLAC__MD5Final(encoder->private_->streaminfo.data.stream_info.md5sum, &encoder->private_->md5context); - - if(!encoder->private_->is_being_deleted) { - if(encoder->protected_->state == FLAC__STREAM_ENCODER_OK) { - if(encoder->private_->seek_callback) { -#if FLAC__HAS_OGG - if(encoder->private_->is_ogg) - update_ogg_metadata_(encoder); - else -#endif - update_metadata_(encoder); - - /* check if an error occurred while updating metadata */ - if(encoder->protected_->state != FLAC__STREAM_ENCODER_OK) - error = true; - } - if(encoder->private_->metadata_callback) - encoder->private_->metadata_callback(encoder, &encoder->private_->streaminfo, encoder->private_->client_data); - } - - if(encoder->protected_->verify && 0 != encoder->private_->verify.decoder && !FLAC__stream_decoder_finish(encoder->private_->verify.decoder)) { - if(!error) - encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA; - error = true; - } - } - - if(0 != encoder->private_->file) { - if(encoder->private_->file != stdout) - fclose(encoder->private_->file); - encoder->private_->file = 0; - } - -#if FLAC__HAS_OGG - if(encoder->private_->is_ogg) - FLAC__ogg_encoder_aspect_finish(&encoder->protected_->ogg_encoder_aspect); -#endif - - free_(encoder); - set_defaults_(encoder); - - if(!error) - encoder->protected_->state = FLAC__STREAM_ENCODER_UNINITIALIZED; - - return !error; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_set_ogg_serial_number(FLAC__StreamEncoder *encoder, long value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return false; -#if FLAC__HAS_OGG - /* can't check encoder->private_->is_ogg since that's not set until init time */ - FLAC__ogg_encoder_aspect_set_serial_number(&encoder->protected_->ogg_encoder_aspect, value); - return true; -#else - (void)value; - return false; -#endif -} - -FLAC_API FLAC__bool FLAC__stream_encoder_set_verify(FLAC__StreamEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return false; -#ifndef FLAC__MANDATORY_VERIFY_WHILE_ENCODING - encoder->protected_->verify = value; -#endif - return true; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_set_streamable_subset(FLAC__StreamEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return false; - encoder->protected_->streamable_subset = value; - return true; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_set_do_md5(FLAC__StreamEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return false; - encoder->protected_->do_md5 = value; - return true; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_set_channels(FLAC__StreamEncoder *encoder, uint32_t value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return false; - encoder->protected_->channels = value; - return true; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_set_bits_per_sample(FLAC__StreamEncoder *encoder, uint32_t value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return false; - encoder->protected_->bits_per_sample = value; - return true; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *encoder, uint32_t value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return false; - encoder->protected_->sample_rate = value; - return true; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_set_compression_level(FLAC__StreamEncoder *encoder, uint32_t value) -{ - FLAC__bool ok = true; - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return false; - if(value >= sizeof(compression_levels_)/sizeof(compression_levels_[0])) - value = sizeof(compression_levels_)/sizeof(compression_levels_[0]) - 1; - ok &= FLAC__stream_encoder_set_do_mid_side_stereo (encoder, compression_levels_[value].do_mid_side_stereo); - ok &= FLAC__stream_encoder_set_loose_mid_side_stereo (encoder, compression_levels_[value].loose_mid_side_stereo); -#ifndef FLAC__INTEGER_ONLY_LIBRARY -#if 1 - ok &= FLAC__stream_encoder_set_apodization (encoder, compression_levels_[value].apodization); -#else - /* equivalent to -A tukey(0.5) */ - encoder->protected_->num_apodizations = 1; - encoder->protected_->apodizations[0].type = FLAC__APODIZATION_TUKEY; - encoder->protected_->apodizations[0].parameters.tukey.p = 0.5; -#endif -#endif - ok &= FLAC__stream_encoder_set_max_lpc_order (encoder, compression_levels_[value].max_lpc_order); - ok &= FLAC__stream_encoder_set_qlp_coeff_precision (encoder, compression_levels_[value].qlp_coeff_precision); - ok &= FLAC__stream_encoder_set_do_qlp_coeff_prec_search (encoder, compression_levels_[value].do_qlp_coeff_prec_search); - ok &= FLAC__stream_encoder_set_do_escape_coding (encoder, compression_levels_[value].do_escape_coding); - ok &= FLAC__stream_encoder_set_do_exhaustive_model_search (encoder, compression_levels_[value].do_exhaustive_model_search); - ok &= FLAC__stream_encoder_set_min_residual_partition_order(encoder, compression_levels_[value].min_residual_partition_order); - ok &= FLAC__stream_encoder_set_max_residual_partition_order(encoder, compression_levels_[value].max_residual_partition_order); - ok &= FLAC__stream_encoder_set_rice_parameter_search_dist (encoder, compression_levels_[value].rice_parameter_search_dist); - return ok; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_set_blocksize(FLAC__StreamEncoder *encoder, uint32_t value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return false; - encoder->protected_->blocksize = value; - return true; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_set_do_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return false; - encoder->protected_->do_mid_side_stereo = value; - return true; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_set_loose_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return false; - encoder->protected_->loose_mid_side_stereo = value; - return true; -} - -/*@@@@add to tests*/ -FLAC_API FLAC__bool FLAC__stream_encoder_set_apodization(FLAC__StreamEncoder *encoder, const char *specification) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != specification); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return false; -#ifdef FLAC__INTEGER_ONLY_LIBRARY - (void)specification; /* silently ignore since we haven't integerized; will always use a rectangular window */ -#else - encoder->protected_->num_apodizations = 0; - while(1) { - const char *s = strchr(specification, ';'); - const size_t n = s? (size_t)(s - specification) : strlen(specification); - if (n==8 && 0 == strncmp("bartlett" , specification, n)) - encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BARTLETT; - else if(n==13 && 0 == strncmp("bartlett_hann", specification, n)) - encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BARTLETT_HANN; - else if(n==8 && 0 == strncmp("blackman" , specification, n)) - encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BLACKMAN; - else if(n==26 && 0 == strncmp("blackman_harris_4term_92db", specification, n)) - encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BLACKMAN_HARRIS_4TERM_92DB_SIDELOBE; - else if(n==6 && 0 == strncmp("connes" , specification, n)) - encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_CONNES; - else if(n==7 && 0 == strncmp("flattop" , specification, n)) - encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_FLATTOP; - else if(n>7 && 0 == strncmp("gauss(" , specification, 6)) { - FLAC__real stddev = (FLAC__real)strtod(specification+6, 0); - if (stddev > 0.0 && stddev <= 0.5) { - encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.gauss.stddev = stddev; - encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_GAUSS; - } - } - else if(n==7 && 0 == strncmp("hamming" , specification, n)) - encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_HAMMING; - else if(n==4 && 0 == strncmp("hann" , specification, n)) - encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_HANN; - else if(n==13 && 0 == strncmp("kaiser_bessel", specification, n)) - encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_KAISER_BESSEL; - else if(n==7 && 0 == strncmp("nuttall" , specification, n)) - encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_NUTTALL; - else if(n==9 && 0 == strncmp("rectangle" , specification, n)) - encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_RECTANGLE; - else if(n==8 && 0 == strncmp("triangle" , specification, n)) - encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TRIANGLE; - else if(n>7 && 0 == strncmp("tukey(" , specification, 6)) { - FLAC__real p = (FLAC__real)strtod(specification+6, 0); - if (p >= 0.0 && p <= 1.0) { - encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.tukey.p = p; - encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TUKEY; - } - } - else if(n>15 && 0 == strncmp("partial_tukey(" , specification, 14)) { - FLAC__int32 tukey_parts = (FLAC__int32)strtod(specification+14, 0); - const char *si_1 = strchr(specification, '/'); - FLAC__real overlap = si_1?flac_min((FLAC__real)strtod(si_1+1, 0),0.99f):0.1f; - FLAC__real overlap_units = 1.0f/(1.0f - overlap) - 1.0f; - const char *si_2 = strchr((si_1?(si_1+1):specification), '/'); - FLAC__real tukey_p = si_2?(FLAC__real)strtod(si_2+1, 0):0.2f; - - if (tukey_parts <= 1) { - encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.tukey.p = tukey_p; - encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TUKEY; - }else if (encoder->protected_->num_apodizations + tukey_parts < 32){ - FLAC__int32 m; - for(m = 0; m < tukey_parts; m++){ - encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.p = tukey_p; - encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.start = m/(tukey_parts+overlap_units); - encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.end = (m+1+overlap_units)/(tukey_parts+overlap_units); - encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_PARTIAL_TUKEY; - } - } - } - else if(n>16 && 0 == strncmp("punchout_tukey(" , specification, 15)) { - FLAC__int32 tukey_parts = (FLAC__int32)strtod(specification+15, 0); - const char *si_1 = strchr(specification, '/'); - FLAC__real overlap = si_1?flac_min((FLAC__real)strtod(si_1+1, 0),0.99f):0.2f; - FLAC__real overlap_units = 1.0f/(1.0f - overlap) - 1.0f; - const char *si_2 = strchr((si_1?(si_1+1):specification), '/'); - FLAC__real tukey_p = si_2?(FLAC__real)strtod(si_2+1, 0):0.2f; - - if (tukey_parts <= 1) { - encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.tukey.p = tukey_p; - encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TUKEY; - }else if (encoder->protected_->num_apodizations + tukey_parts < 32){ - FLAC__int32 m; - for(m = 0; m < tukey_parts; m++){ - encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.p = tukey_p; - encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.start = m/(tukey_parts+overlap_units); - encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.end = (m+1+overlap_units)/(tukey_parts+overlap_units); - encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_PUNCHOUT_TUKEY; - } - } - } - else if(n==5 && 0 == strncmp("welch" , specification, n)) - encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_WELCH; - if (encoder->protected_->num_apodizations == 32) - break; - if (s) - specification = s+1; - else - break; - } - if(encoder->protected_->num_apodizations == 0) { - encoder->protected_->num_apodizations = 1; - encoder->protected_->apodizations[0].type = FLAC__APODIZATION_TUKEY; - encoder->protected_->apodizations[0].parameters.tukey.p = 0.5; - } -#endif - return true; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_set_max_lpc_order(FLAC__StreamEncoder *encoder, uint32_t value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return false; - encoder->protected_->max_lpc_order = value; - return true; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_set_qlp_coeff_precision(FLAC__StreamEncoder *encoder, uint32_t value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return false; - encoder->protected_->qlp_coeff_precision = value; - return true; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_set_do_qlp_coeff_prec_search(FLAC__StreamEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return false; - encoder->protected_->do_qlp_coeff_prec_search = value; - return true; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_set_do_escape_coding(FLAC__StreamEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return false; -#if 0 - /*@@@ deprecated: */ - encoder->protected_->do_escape_coding = value; -#else - (void)value; -#endif - return true; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_set_do_exhaustive_model_search(FLAC__StreamEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return false; - encoder->protected_->do_exhaustive_model_search = value; - return true; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_set_min_residual_partition_order(FLAC__StreamEncoder *encoder, uint32_t value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return false; - encoder->protected_->min_residual_partition_order = value; - return true; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_set_max_residual_partition_order(FLAC__StreamEncoder *encoder, uint32_t value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return false; - encoder->protected_->max_residual_partition_order = value; - return true; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_set_rice_parameter_search_dist(FLAC__StreamEncoder *encoder, uint32_t value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return false; -#if 0 - /*@@@ deprecated: */ - encoder->protected_->rice_parameter_search_dist = value; -#else - (void)value; -#endif - return true; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_set_total_samples_estimate(FLAC__StreamEncoder *encoder, FLAC__uint64 value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return false; - value = flac_min(value, (FLAC__U64L(1) << FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN) - 1); - encoder->protected_->total_samples_estimate = value; - return true; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_set_metadata(FLAC__StreamEncoder *encoder, FLAC__StreamMetadata **metadata, uint32_t num_blocks) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return false; - if(0 == metadata) - num_blocks = 0; - if(0 == num_blocks) - metadata = 0; - /* realloc() does not do exactly what we want so... */ - if(encoder->protected_->metadata) { - free(encoder->protected_->metadata); - encoder->protected_->metadata = 0; - encoder->protected_->num_metadata_blocks = 0; - } - if(num_blocks) { - FLAC__StreamMetadata **m; - if(0 == (m = safe_malloc_mul_2op_p(sizeof(m[0]), /*times*/num_blocks))) - return false; - memcpy(m, metadata, sizeof(m[0]) * num_blocks); - encoder->protected_->metadata = m; - encoder->protected_->num_metadata_blocks = num_blocks; - } -#if FLAC__HAS_OGG - if(!FLAC__ogg_encoder_aspect_set_num_metadata(&encoder->protected_->ogg_encoder_aspect, num_blocks)) - return false; -#endif - return true; -} - -/* - * These three functions are not static, but not publicly exposed in - * include/FLAC/ either. They are used by the test suite. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_disable_constant_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return false; - encoder->private_->disable_constant_subframes = value; - return true; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_disable_fixed_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return false; - encoder->private_->disable_fixed_subframes = value; - return true; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_disable_verbatim_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return false; - encoder->private_->disable_verbatim_subframes = value; - return true; -} - -FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_get_state(const FLAC__StreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - return encoder->protected_->state; -} - -FLAC_API FLAC__StreamDecoderState FLAC__stream_encoder_get_verify_decoder_state(const FLAC__StreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->verify) - return FLAC__stream_decoder_get_state(encoder->private_->verify.decoder); - else - return FLAC__STREAM_DECODER_UNINITIALIZED; -} - -FLAC_API const char *FLAC__stream_encoder_get_resolved_state_string(const FLAC__StreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR) - return FLAC__StreamEncoderStateString[encoder->protected_->state]; - else - return FLAC__stream_decoder_get_resolved_state_string(encoder->private_->verify.decoder); -} - -FLAC_API void FLAC__stream_encoder_get_verify_decoder_error_stats(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_sample, uint32_t *frame_number, uint32_t *channel, uint32_t *sample, FLAC__int32 *expected, FLAC__int32 *got) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(0 != absolute_sample) - *absolute_sample = encoder->private_->verify.error_stats.absolute_sample; - if(0 != frame_number) - *frame_number = encoder->private_->verify.error_stats.frame_number; - if(0 != channel) - *channel = encoder->private_->verify.error_stats.channel; - if(0 != sample) - *sample = encoder->private_->verify.error_stats.sample; - if(0 != expected) - *expected = encoder->private_->verify.error_stats.expected; - if(0 != got) - *got = encoder->private_->verify.error_stats.got; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_get_verify(const FLAC__StreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - return encoder->protected_->verify; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_get_streamable_subset(const FLAC__StreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - return encoder->protected_->streamable_subset; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_get_do_md5(const FLAC__StreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - return encoder->protected_->do_md5; -} - -FLAC_API uint32_t FLAC__stream_encoder_get_channels(const FLAC__StreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - return encoder->protected_->channels; -} - -FLAC_API uint32_t FLAC__stream_encoder_get_bits_per_sample(const FLAC__StreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - return encoder->protected_->bits_per_sample; -} - -FLAC_API uint32_t FLAC__stream_encoder_get_sample_rate(const FLAC__StreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - return encoder->protected_->sample_rate; -} - -FLAC_API uint32_t FLAC__stream_encoder_get_blocksize(const FLAC__StreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - return encoder->protected_->blocksize; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_get_do_mid_side_stereo(const FLAC__StreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - return encoder->protected_->do_mid_side_stereo; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_get_loose_mid_side_stereo(const FLAC__StreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - return encoder->protected_->loose_mid_side_stereo; -} - -FLAC_API uint32_t FLAC__stream_encoder_get_max_lpc_order(const FLAC__StreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - return encoder->protected_->max_lpc_order; -} - -FLAC_API uint32_t FLAC__stream_encoder_get_qlp_coeff_precision(const FLAC__StreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - return encoder->protected_->qlp_coeff_precision; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_get_do_qlp_coeff_prec_search(const FLAC__StreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - return encoder->protected_->do_qlp_coeff_prec_search; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_get_do_escape_coding(const FLAC__StreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - return encoder->protected_->do_escape_coding; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_get_do_exhaustive_model_search(const FLAC__StreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - return encoder->protected_->do_exhaustive_model_search; -} - -FLAC_API uint32_t FLAC__stream_encoder_get_min_residual_partition_order(const FLAC__StreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - return encoder->protected_->min_residual_partition_order; -} - -FLAC_API uint32_t FLAC__stream_encoder_get_max_residual_partition_order(const FLAC__StreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - return encoder->protected_->max_residual_partition_order; -} - -FLAC_API uint32_t FLAC__stream_encoder_get_rice_parameter_search_dist(const FLAC__StreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - return encoder->protected_->rice_parameter_search_dist; -} - -FLAC_API FLAC__uint64 FLAC__stream_encoder_get_total_samples_estimate(const FLAC__StreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - return encoder->protected_->total_samples_estimate; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC__int32 * const buffer[], uint32_t samples) -{ - uint32_t i, j = 0, channel; - const uint32_t channels = encoder->protected_->channels, blocksize = encoder->protected_->blocksize; - - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(encoder->protected_->state == FLAC__STREAM_ENCODER_OK); - - do { - const uint32_t n = flac_min(blocksize+OVERREAD_-encoder->private_->current_sample_number, samples-j); - - if(encoder->protected_->verify) - append_to_verify_fifo_(&encoder->private_->verify.input_fifo, buffer, j, channels, n); - - for(channel = 0; channel < channels; channel++) { - if (buffer[channel] == NULL) { - return false; - } - memcpy(&encoder->private_->integer_signal[channel][encoder->private_->current_sample_number], &buffer[channel][j], sizeof(buffer[channel][0]) * n); - } - - if(encoder->protected_->do_mid_side_stereo) { - FLAC__ASSERT(channels == 2); - /* "i <= blocksize" to overread 1 sample; see comment in OVERREAD_ decl */ - for(i = encoder->private_->current_sample_number; i <= blocksize && j < samples; i++, j++) { - encoder->private_->integer_signal_mid_side[1][i] = buffer[0][j] - buffer[1][j]; - encoder->private_->integer_signal_mid_side[0][i] = (buffer[0][j] + buffer[1][j]) >> 1; /* NOTE: not the same as 'mid = (buffer[0][j] + buffer[1][j]) / 2' ! */ - } - } - else - j += n; - - encoder->private_->current_sample_number += n; - - /* we only process if we have a full block + 1 extra sample; final block is always handled by FLAC__stream_encoder_finish() */ - if(encoder->private_->current_sample_number > blocksize) { - FLAC__ASSERT(encoder->private_->current_sample_number == blocksize+OVERREAD_); - FLAC__ASSERT(OVERREAD_ == 1); /* assert we only overread 1 sample which simplifies the rest of the code below */ - if(!process_frame_(encoder, /*is_fractional_block=*/false, /*is_last_block=*/false)) - return false; - /* move unprocessed overread samples to beginnings of arrays */ - for(channel = 0; channel < channels; channel++) - encoder->private_->integer_signal[channel][0] = encoder->private_->integer_signal[channel][blocksize]; - if(encoder->protected_->do_mid_side_stereo) { - encoder->private_->integer_signal_mid_side[0][0] = encoder->private_->integer_signal_mid_side[0][blocksize]; - encoder->private_->integer_signal_mid_side[1][0] = encoder->private_->integer_signal_mid_side[1][blocksize]; - } - encoder->private_->current_sample_number = 1; - } - } while(j < samples); - - return true; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder *encoder, const FLAC__int32 buffer[], uint32_t samples) -{ - uint32_t i, j, k, channel; - FLAC__int32 x, mid, side; - const uint32_t channels = encoder->protected_->channels, blocksize = encoder->protected_->blocksize; - - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(encoder->protected_->state == FLAC__STREAM_ENCODER_OK); - - j = k = 0; - /* - * we have several flavors of the same basic loop, optimized for - * different conditions: - */ - if(encoder->protected_->do_mid_side_stereo && channels == 2) { - /* - * stereo coding: unroll channel loop - */ - do { - if(encoder->protected_->verify) - append_to_verify_fifo_interleaved_(&encoder->private_->verify.input_fifo, buffer, j, channels, flac_min(blocksize+OVERREAD_-encoder->private_->current_sample_number, samples-j)); - - /* "i <= blocksize" to overread 1 sample; see comment in OVERREAD_ decl */ - for(i = encoder->private_->current_sample_number; i <= blocksize && j < samples; i++, j++) { - encoder->private_->integer_signal[0][i] = mid = side = buffer[k++]; - x = buffer[k++]; - encoder->private_->integer_signal[1][i] = x; - mid += x; - side -= x; - mid >>= 1; /* NOTE: not the same as 'mid = (left + right) / 2' ! */ - encoder->private_->integer_signal_mid_side[1][i] = side; - encoder->private_->integer_signal_mid_side[0][i] = mid; - } - encoder->private_->current_sample_number = i; - /* we only process if we have a full block + 1 extra sample; final block is always handled by FLAC__stream_encoder_finish() */ - if(i > blocksize) { - if(!process_frame_(encoder, /*is_fractional_block=*/false, /*is_last_block=*/false)) - return false; - /* move unprocessed overread samples to beginnings of arrays */ - FLAC__ASSERT(i == blocksize+OVERREAD_); - FLAC__ASSERT(OVERREAD_ == 1); /* assert we only overread 1 sample which simplifies the rest of the code below */ - encoder->private_->integer_signal[0][0] = encoder->private_->integer_signal[0][blocksize]; - encoder->private_->integer_signal[1][0] = encoder->private_->integer_signal[1][blocksize]; - encoder->private_->integer_signal_mid_side[0][0] = encoder->private_->integer_signal_mid_side[0][blocksize]; - encoder->private_->integer_signal_mid_side[1][0] = encoder->private_->integer_signal_mid_side[1][blocksize]; - encoder->private_->current_sample_number = 1; - } - } while(j < samples); - } - else { - /* - * independent channel coding: buffer each channel in inner loop - */ - do { - if(encoder->protected_->verify) - append_to_verify_fifo_interleaved_(&encoder->private_->verify.input_fifo, buffer, j, channels, flac_min(blocksize+OVERREAD_-encoder->private_->current_sample_number, samples-j)); - - /* "i <= blocksize" to overread 1 sample; see comment in OVERREAD_ decl */ - for(i = encoder->private_->current_sample_number; i <= blocksize && j < samples; i++, j++) { - for(channel = 0; channel < channels; channel++) - encoder->private_->integer_signal[channel][i] = buffer[k++]; - } - encoder->private_->current_sample_number = i; - /* we only process if we have a full block + 1 extra sample; final block is always handled by FLAC__stream_encoder_finish() */ - if(i > blocksize) { - if(!process_frame_(encoder, /*is_fractional_block=*/false, /*is_last_block=*/false)) - return false; - /* move unprocessed overread samples to beginnings of arrays */ - FLAC__ASSERT(i == blocksize+OVERREAD_); - FLAC__ASSERT(OVERREAD_ == 1); /* assert we only overread 1 sample which simplifies the rest of the code below */ - for(channel = 0; channel < channels; channel++) - encoder->private_->integer_signal[channel][0] = encoder->private_->integer_signal[channel][blocksize]; - encoder->private_->current_sample_number = 1; - } - } while(j < samples); - } - - return true; -} - -/*********************************************************************** - * - * Private class methods - * - ***********************************************************************/ - -void set_defaults_(FLAC__StreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - -#ifdef FLAC__MANDATORY_VERIFY_WHILE_ENCODING - encoder->protected_->verify = true; -#else - encoder->protected_->verify = false; -#endif - encoder->protected_->streamable_subset = true; - encoder->protected_->do_md5 = true; - encoder->protected_->do_mid_side_stereo = false; - encoder->protected_->loose_mid_side_stereo = false; - encoder->protected_->channels = 2; - encoder->protected_->bits_per_sample = 16; - encoder->protected_->sample_rate = 44100; - encoder->protected_->blocksize = 0; -#ifndef FLAC__INTEGER_ONLY_LIBRARY - encoder->protected_->num_apodizations = 1; - encoder->protected_->apodizations[0].type = FLAC__APODIZATION_TUKEY; - encoder->protected_->apodizations[0].parameters.tukey.p = 0.5; -#endif - encoder->protected_->max_lpc_order = 0; - encoder->protected_->qlp_coeff_precision = 0; - encoder->protected_->do_qlp_coeff_prec_search = false; - encoder->protected_->do_exhaustive_model_search = false; - encoder->protected_->do_escape_coding = false; - encoder->protected_->min_residual_partition_order = 0; - encoder->protected_->max_residual_partition_order = 0; - encoder->protected_->rice_parameter_search_dist = 0; - encoder->protected_->total_samples_estimate = 0; - encoder->protected_->metadata = 0; - encoder->protected_->num_metadata_blocks = 0; - - encoder->private_->seek_table = 0; - encoder->private_->disable_constant_subframes = false; - encoder->private_->disable_fixed_subframes = false; - encoder->private_->disable_verbatim_subframes = false; - encoder->private_->is_ogg = false; - encoder->private_->read_callback = 0; - encoder->private_->write_callback = 0; - encoder->private_->seek_callback = 0; - encoder->private_->tell_callback = 0; - encoder->private_->metadata_callback = 0; - encoder->private_->progress_callback = 0; - encoder->private_->client_data = 0; - -#if FLAC__HAS_OGG - FLAC__ogg_encoder_aspect_set_defaults(&encoder->protected_->ogg_encoder_aspect); -#endif - - FLAC__stream_encoder_set_compression_level(encoder, 5); -} - -void free_(FLAC__StreamEncoder *encoder) -{ - uint32_t i, channel; - - FLAC__ASSERT(0 != encoder); - if(encoder->protected_->metadata) { - free(encoder->protected_->metadata); - encoder->protected_->metadata = 0; - encoder->protected_->num_metadata_blocks = 0; - } - for(i = 0; i < encoder->protected_->channels; i++) { - if(0 != encoder->private_->integer_signal_unaligned[i]) { - free(encoder->private_->integer_signal_unaligned[i]); - encoder->private_->integer_signal_unaligned[i] = 0; - } -#ifndef FLAC__INTEGER_ONLY_LIBRARY - if(0 != encoder->private_->real_signal_unaligned[i]) { - free(encoder->private_->real_signal_unaligned[i]); - encoder->private_->real_signal_unaligned[i] = 0; - } -#endif - } - for(i = 0; i < 2; i++) { - if(0 != encoder->private_->integer_signal_mid_side_unaligned[i]) { - free(encoder->private_->integer_signal_mid_side_unaligned[i]); - encoder->private_->integer_signal_mid_side_unaligned[i] = 0; - } -#ifndef FLAC__INTEGER_ONLY_LIBRARY - if(0 != encoder->private_->real_signal_mid_side_unaligned[i]) { - free(encoder->private_->real_signal_mid_side_unaligned[i]); - encoder->private_->real_signal_mid_side_unaligned[i] = 0; - } -#endif - } -#ifndef FLAC__INTEGER_ONLY_LIBRARY - for(i = 0; i < encoder->protected_->num_apodizations; i++) { - if(0 != encoder->private_->window_unaligned[i]) { - free(encoder->private_->window_unaligned[i]); - encoder->private_->window_unaligned[i] = 0; - } - } - if(0 != encoder->private_->windowed_signal_unaligned) { - free(encoder->private_->windowed_signal_unaligned); - encoder->private_->windowed_signal_unaligned = 0; - } -#endif - for(channel = 0; channel < encoder->protected_->channels; channel++) { - for(i = 0; i < 2; i++) { - if(0 != encoder->private_->residual_workspace_unaligned[channel][i]) { - free(encoder->private_->residual_workspace_unaligned[channel][i]); - encoder->private_->residual_workspace_unaligned[channel][i] = 0; - } - } - } - for(channel = 0; channel < 2; channel++) { - for(i = 0; i < 2; i++) { - if(0 != encoder->private_->residual_workspace_mid_side_unaligned[channel][i]) { - free(encoder->private_->residual_workspace_mid_side_unaligned[channel][i]); - encoder->private_->residual_workspace_mid_side_unaligned[channel][i] = 0; - } - } - } - if(0 != encoder->private_->abs_residual_partition_sums_unaligned) { - free(encoder->private_->abs_residual_partition_sums_unaligned); - encoder->private_->abs_residual_partition_sums_unaligned = 0; - } - if(0 != encoder->private_->raw_bits_per_partition_unaligned) { - free(encoder->private_->raw_bits_per_partition_unaligned); - encoder->private_->raw_bits_per_partition_unaligned = 0; - } - if(encoder->protected_->verify) { - for(i = 0; i < encoder->protected_->channels; i++) { - if(0 != encoder->private_->verify.input_fifo.data[i]) { - free(encoder->private_->verify.input_fifo.data[i]); - encoder->private_->verify.input_fifo.data[i] = 0; - } - } - } - FLAC__bitwriter_free(encoder->private_->frame); -} - -FLAC__bool resize_buffers_(FLAC__StreamEncoder *encoder, uint32_t new_blocksize) -{ - FLAC__bool ok; - uint32_t i, channel; - - FLAC__ASSERT(new_blocksize > 0); - FLAC__ASSERT(encoder->protected_->state == FLAC__STREAM_ENCODER_OK); - FLAC__ASSERT(encoder->private_->current_sample_number == 0); - - /* To avoid excessive malloc'ing, we only grow the buffer; no shrinking. */ - if(new_blocksize <= encoder->private_->input_capacity) - return true; - - ok = true; - - /* WATCHOUT: FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx() and ..._intrin_sse2() - * require that the input arrays (in our case the integer signals) - * have a buffer of up to 3 zeroes in front (at negative indices) for - * alignment purposes; we use 4 in front to keep the data well-aligned. - */ - - for(i = 0; ok && i < encoder->protected_->channels; i++) { - ok = ok && FLAC__memory_alloc_aligned_int32_array(new_blocksize+4+OVERREAD_, &encoder->private_->integer_signal_unaligned[i], &encoder->private_->integer_signal[i]); - memset(encoder->private_->integer_signal[i], 0, sizeof(FLAC__int32)*4); - encoder->private_->integer_signal[i] += 4; -#ifndef FLAC__INTEGER_ONLY_LIBRARY -#if 0 /* @@@ currently unused */ - if(encoder->protected_->max_lpc_order > 0) - ok = ok && FLAC__memory_alloc_aligned_real_array(new_blocksize+OVERREAD_, &encoder->private_->real_signal_unaligned[i], &encoder->private_->real_signal[i]); -#endif -#endif - } - for(i = 0; ok && i < 2; i++) { - ok = ok && FLAC__memory_alloc_aligned_int32_array(new_blocksize+4+OVERREAD_, &encoder->private_->integer_signal_mid_side_unaligned[i], &encoder->private_->integer_signal_mid_side[i]); - memset(encoder->private_->integer_signal_mid_side[i], 0, sizeof(FLAC__int32)*4); - encoder->private_->integer_signal_mid_side[i] += 4; -#ifndef FLAC__INTEGER_ONLY_LIBRARY -#if 0 /* @@@ currently unused */ - if(encoder->protected_->max_lpc_order > 0) - ok = ok && FLAC__memory_alloc_aligned_real_array(new_blocksize+OVERREAD_, &encoder->private_->real_signal_mid_side_unaligned[i], &encoder->private_->real_signal_mid_side[i]); -#endif -#endif - } -#ifndef FLAC__INTEGER_ONLY_LIBRARY - if(ok && encoder->protected_->max_lpc_order > 0) { - for(i = 0; ok && i < encoder->protected_->num_apodizations; i++) - ok = ok && FLAC__memory_alloc_aligned_real_array(new_blocksize, &encoder->private_->window_unaligned[i], &encoder->private_->window[i]); - ok = ok && FLAC__memory_alloc_aligned_real_array(new_blocksize, &encoder->private_->windowed_signal_unaligned, &encoder->private_->windowed_signal); - } -#endif - for(channel = 0; ok && channel < encoder->protected_->channels; channel++) { - for(i = 0; ok && i < 2; i++) { - ok = ok && FLAC__memory_alloc_aligned_int32_array(new_blocksize, &encoder->private_->residual_workspace_unaligned[channel][i], &encoder->private_->residual_workspace[channel][i]); - } - } - for(channel = 0; ok && channel < 2; channel++) { - for(i = 0; ok && i < 2; i++) { - ok = ok && FLAC__memory_alloc_aligned_int32_array(new_blocksize, &encoder->private_->residual_workspace_mid_side_unaligned[channel][i], &encoder->private_->residual_workspace_mid_side[channel][i]); - } - } - /* the *2 is an approximation to the series 1 + 1/2 + 1/4 + ... that sums tree occupies in a flat array */ - /*@@@ new_blocksize*2 is too pessimistic, but to fix, we need smarter logic because a smaller new_blocksize can actually increase the # of partitions; would require moving this out into a separate function, then checking its capacity against the need of the current blocksize&min/max_partition_order (and maybe predictor order) */ - ok = ok && FLAC__memory_alloc_aligned_uint64_array(new_blocksize * 2, &encoder->private_->abs_residual_partition_sums_unaligned, &encoder->private_->abs_residual_partition_sums); - if(encoder->protected_->do_escape_coding) - ok = ok && FLAC__memory_alloc_aligned_unsigned_array(new_blocksize * 2, &encoder->private_->raw_bits_per_partition_unaligned, &encoder->private_->raw_bits_per_partition); - - /* now adjust the windows if the blocksize has changed */ -#ifndef FLAC__INTEGER_ONLY_LIBRARY - if(ok && new_blocksize != encoder->private_->input_capacity && encoder->protected_->max_lpc_order > 0) { - for(i = 0; ok && i < encoder->protected_->num_apodizations; i++) { - switch(encoder->protected_->apodizations[i].type) { - case FLAC__APODIZATION_BARTLETT: - FLAC__window_bartlett(encoder->private_->window[i], new_blocksize); - break; - case FLAC__APODIZATION_BARTLETT_HANN: - FLAC__window_bartlett_hann(encoder->private_->window[i], new_blocksize); - break; - case FLAC__APODIZATION_BLACKMAN: - FLAC__window_blackman(encoder->private_->window[i], new_blocksize); - break; - case FLAC__APODIZATION_BLACKMAN_HARRIS_4TERM_92DB_SIDELOBE: - FLAC__window_blackman_harris_4term_92db_sidelobe(encoder->private_->window[i], new_blocksize); - break; - case FLAC__APODIZATION_CONNES: - FLAC__window_connes(encoder->private_->window[i], new_blocksize); - break; - case FLAC__APODIZATION_FLATTOP: - FLAC__window_flattop(encoder->private_->window[i], new_blocksize); - break; - case FLAC__APODIZATION_GAUSS: - FLAC__window_gauss(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.gauss.stddev); - break; - case FLAC__APODIZATION_HAMMING: - FLAC__window_hamming(encoder->private_->window[i], new_blocksize); - break; - case FLAC__APODIZATION_HANN: - FLAC__window_hann(encoder->private_->window[i], new_blocksize); - break; - case FLAC__APODIZATION_KAISER_BESSEL: - FLAC__window_kaiser_bessel(encoder->private_->window[i], new_blocksize); - break; - case FLAC__APODIZATION_NUTTALL: - FLAC__window_nuttall(encoder->private_->window[i], new_blocksize); - break; - case FLAC__APODIZATION_RECTANGLE: - FLAC__window_rectangle(encoder->private_->window[i], new_blocksize); - break; - case FLAC__APODIZATION_TRIANGLE: - FLAC__window_triangle(encoder->private_->window[i], new_blocksize); - break; - case FLAC__APODIZATION_TUKEY: - FLAC__window_tukey(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.tukey.p); - break; - case FLAC__APODIZATION_PARTIAL_TUKEY: - FLAC__window_partial_tukey(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.multiple_tukey.p, encoder->protected_->apodizations[i].parameters.multiple_tukey.start, encoder->protected_->apodizations[i].parameters.multiple_tukey.end); - break; - case FLAC__APODIZATION_PUNCHOUT_TUKEY: - FLAC__window_punchout_tukey(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.multiple_tukey.p, encoder->protected_->apodizations[i].parameters.multiple_tukey.start, encoder->protected_->apodizations[i].parameters.multiple_tukey.end); - break; - case FLAC__APODIZATION_WELCH: - FLAC__window_welch(encoder->private_->window[i], new_blocksize); - break; - default: - FLAC__ASSERT(0); - /* double protection */ - FLAC__window_hann(encoder->private_->window[i], new_blocksize); - break; - } - } - } -#endif - - if(ok) - encoder->private_->input_capacity = new_blocksize; - else - encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; - - return ok; -} - -FLAC__bool write_bitbuffer_(FLAC__StreamEncoder *encoder, uint32_t samples, FLAC__bool is_last_block) -{ - const FLAC__byte *buffer; - size_t bytes; - - FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(encoder->private_->frame)); - - if(!FLAC__bitwriter_get_buffer(encoder->private_->frame, &buffer, &bytes)) { - encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; - return false; - } - - if(encoder->protected_->verify) { - encoder->private_->verify.output.data = buffer; - encoder->private_->verify.output.bytes = bytes; - if(encoder->private_->verify.state_hint == ENCODER_IN_MAGIC) { - encoder->private_->verify.needs_magic_hack = true; - } - else { - if(!FLAC__stream_decoder_process_single(encoder->private_->verify.decoder)) { - FLAC__bitwriter_release_buffer(encoder->private_->frame); - FLAC__bitwriter_clear(encoder->private_->frame); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA) - encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR; - return false; - } - } - } - - if(write_frame_(encoder, buffer, bytes, samples, is_last_block) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { - FLAC__bitwriter_release_buffer(encoder->private_->frame); - FLAC__bitwriter_clear(encoder->private_->frame); - encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; - return false; - } - - FLAC__bitwriter_release_buffer(encoder->private_->frame); - FLAC__bitwriter_clear(encoder->private_->frame); - - if(samples > 0) { - encoder->private_->streaminfo.data.stream_info.min_framesize = flac_min(bytes, encoder->private_->streaminfo.data.stream_info.min_framesize); - encoder->private_->streaminfo.data.stream_info.max_framesize = flac_max(bytes, encoder->private_->streaminfo.data.stream_info.max_framesize); - } - - return true; -} - -FLAC__StreamEncoderWriteStatus write_frame_(FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, FLAC__bool is_last_block) -{ - FLAC__StreamEncoderWriteStatus status; - FLAC__uint64 output_position = 0; - -#if FLAC__HAS_OGG == 0 - (void)is_last_block; -#endif - - /* FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED just means we didn't get the offset; no error */ - if(encoder->private_->tell_callback && encoder->private_->tell_callback(encoder, &output_position, encoder->private_->client_data) == FLAC__STREAM_ENCODER_TELL_STATUS_ERROR) { - encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; - return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; - } - - /* - * Watch for the STREAMINFO block and first SEEKTABLE block to go by and store their offsets. - */ - if(samples == 0) { - FLAC__MetadataType type = (buffer[0] & 0x7f); - if(type == FLAC__METADATA_TYPE_STREAMINFO) - encoder->protected_->streaminfo_offset = output_position; - else if(type == FLAC__METADATA_TYPE_SEEKTABLE && encoder->protected_->seektable_offset == 0) - encoder->protected_->seektable_offset = output_position; - } - - /* - * Mark the current seek point if hit (if audio_offset == 0 that - * means we're still writing metadata and haven't hit the first - * frame yet) - */ - if(0 != encoder->private_->seek_table && encoder->protected_->audio_offset > 0 && encoder->private_->seek_table->num_points > 0) { - const uint32_t blocksize = FLAC__stream_encoder_get_blocksize(encoder); - const FLAC__uint64 frame_first_sample = encoder->private_->samples_written; - const FLAC__uint64 frame_last_sample = frame_first_sample + (FLAC__uint64)blocksize - 1; - FLAC__uint64 test_sample; - uint32_t i; - for(i = encoder->private_->first_seekpoint_to_check; i < encoder->private_->seek_table->num_points; i++) { - test_sample = encoder->private_->seek_table->points[i].sample_number; - if(test_sample > frame_last_sample) { - break; - } - else if(test_sample >= frame_first_sample) { - encoder->private_->seek_table->points[i].sample_number = frame_first_sample; - encoder->private_->seek_table->points[i].stream_offset = output_position - encoder->protected_->audio_offset; - encoder->private_->seek_table->points[i].frame_samples = blocksize; - encoder->private_->first_seekpoint_to_check++; - /* DO NOT: "break;" and here's why: - * The seektable template may contain more than one target - * sample for any given frame; we will keep looping, generating - * duplicate seekpoints for them, and we'll clean it up later, - * just before writing the seektable back to the metadata. - */ - } - else { - encoder->private_->first_seekpoint_to_check++; - } - } - } - -#if FLAC__HAS_OGG - if(encoder->private_->is_ogg) { - status = FLAC__ogg_encoder_aspect_write_callback_wrapper( - &encoder->protected_->ogg_encoder_aspect, - buffer, - bytes, - samples, - encoder->private_->current_frame_number, - is_last_block, - (FLAC__OggEncoderAspectWriteCallbackProxy)encoder->private_->write_callback, - encoder, - encoder->private_->client_data - ); - } - else -#endif - status = encoder->private_->write_callback(encoder, buffer, bytes, samples, encoder->private_->current_frame_number, encoder->private_->client_data); - - if(status == FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { - encoder->private_->bytes_written += bytes; - encoder->private_->samples_written += samples; - /* we keep a high watermark on the number of frames written because - * when the encoder goes back to write metadata, 'current_frame' - * will drop back to 0. - */ - encoder->private_->frames_written = flac_max(encoder->private_->frames_written, encoder->private_->current_frame_number+1); - } - else - encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; - - return status; -} - -/* Gets called when the encoding process has finished so that we can update the STREAMINFO and SEEKTABLE blocks. */ -void update_metadata_(const FLAC__StreamEncoder *encoder) -{ - FLAC__byte b[flac_max(6u, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)]; - const FLAC__StreamMetadata *metadata = &encoder->private_->streaminfo; - const FLAC__uint64 samples = metadata->data.stream_info.total_samples; - const uint32_t min_framesize = metadata->data.stream_info.min_framesize; - const uint32_t max_framesize = metadata->data.stream_info.max_framesize; - const uint32_t bps = metadata->data.stream_info.bits_per_sample; - FLAC__StreamEncoderSeekStatus seek_status; - - FLAC__ASSERT(metadata->type == FLAC__METADATA_TYPE_STREAMINFO); - - /* All this is based on intimate knowledge of the stream header - * layout, but a change to the header format that would break this - * would also break all streams encoded in the previous format. - */ - - /* - * Write MD5 signature - */ - { - const uint32_t md5_offset = - FLAC__STREAM_METADATA_HEADER_LENGTH + - ( - FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN + - FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN - ) / 8; - - if((seek_status = encoder->private_->seek_callback(encoder, encoder->protected_->streaminfo_offset + md5_offset, encoder->private_->client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) { - if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR) - encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; - return; - } - if(encoder->private_->write_callback(encoder, metadata->data.stream_info.md5sum, 16, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { - encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; - return; - } - } - - /* - * Write total samples - */ - { - const uint32_t total_samples_byte_offset = - FLAC__STREAM_METADATA_HEADER_LENGTH + - ( - FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN + - FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN - - 4 - ) / 8; - - b[0] = ((FLAC__byte)(bps-1) << 4) | (FLAC__byte)((samples >> 32) & 0x0F); - b[1] = (FLAC__byte)((samples >> 24) & 0xFF); - b[2] = (FLAC__byte)((samples >> 16) & 0xFF); - b[3] = (FLAC__byte)((samples >> 8) & 0xFF); - b[4] = (FLAC__byte)(samples & 0xFF); - if((seek_status = encoder->private_->seek_callback(encoder, encoder->protected_->streaminfo_offset + total_samples_byte_offset, encoder->private_->client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) { - if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR) - encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; - return; - } - if(encoder->private_->write_callback(encoder, b, 5, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { - encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; - return; - } - } - - /* - * Write min/max framesize - */ - { - const uint32_t min_framesize_offset = - FLAC__STREAM_METADATA_HEADER_LENGTH + - ( - FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN - ) / 8; - - b[0] = (FLAC__byte)((min_framesize >> 16) & 0xFF); - b[1] = (FLAC__byte)((min_framesize >> 8) & 0xFF); - b[2] = (FLAC__byte)(min_framesize & 0xFF); - b[3] = (FLAC__byte)((max_framesize >> 16) & 0xFF); - b[4] = (FLAC__byte)((max_framesize >> 8) & 0xFF); - b[5] = (FLAC__byte)(max_framesize & 0xFF); - if((seek_status = encoder->private_->seek_callback(encoder, encoder->protected_->streaminfo_offset + min_framesize_offset, encoder->private_->client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) { - if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR) - encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; - return; - } - if(encoder->private_->write_callback(encoder, b, 6, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { - encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; - return; - } - } - - /* - * Write seektable - */ - if(0 != encoder->private_->seek_table && encoder->private_->seek_table->num_points > 0 && encoder->protected_->seektable_offset > 0) { - uint32_t i; - - FLAC__format_seektable_sort(encoder->private_->seek_table); - - FLAC__ASSERT(FLAC__format_seektable_is_legal(encoder->private_->seek_table)); - - if((seek_status = encoder->private_->seek_callback(encoder, encoder->protected_->seektable_offset + FLAC__STREAM_METADATA_HEADER_LENGTH, encoder->private_->client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) { - if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR) - encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; - return; - } - - for(i = 0; i < encoder->private_->seek_table->num_points; i++) { - FLAC__uint64 xx; - uint32_t x; - xx = encoder->private_->seek_table->points[i].sample_number; - b[7] = (FLAC__byte)xx; xx >>= 8; - b[6] = (FLAC__byte)xx; xx >>= 8; - b[5] = (FLAC__byte)xx; xx >>= 8; - b[4] = (FLAC__byte)xx; xx >>= 8; - b[3] = (FLAC__byte)xx; xx >>= 8; - b[2] = (FLAC__byte)xx; xx >>= 8; - b[1] = (FLAC__byte)xx; xx >>= 8; - b[0] = (FLAC__byte)xx; xx >>= 8; - xx = encoder->private_->seek_table->points[i].stream_offset; - b[15] = (FLAC__byte)xx; xx >>= 8; - b[14] = (FLAC__byte)xx; xx >>= 8; - b[13] = (FLAC__byte)xx; xx >>= 8; - b[12] = (FLAC__byte)xx; xx >>= 8; - b[11] = (FLAC__byte)xx; xx >>= 8; - b[10] = (FLAC__byte)xx; xx >>= 8; - b[9] = (FLAC__byte)xx; xx >>= 8; - b[8] = (FLAC__byte)xx; xx >>= 8; - x = encoder->private_->seek_table->points[i].frame_samples; - b[17] = (FLAC__byte)x; x >>= 8; - b[16] = (FLAC__byte)x; x >>= 8; - if(encoder->private_->write_callback(encoder, b, 18, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { - encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; - return; - } - } - } -} - -#if FLAC__HAS_OGG -/* Gets called when the encoding process has finished so that we can update the STREAMINFO and SEEKTABLE blocks. */ -void update_ogg_metadata_(FLAC__StreamEncoder *encoder) -{ - /* the # of bytes in the 1st packet that precede the STREAMINFO */ - static const uint32_t FIRST_OGG_PACKET_STREAMINFO_PREFIX_LENGTH = - FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH + - FLAC__OGG_MAPPING_MAGIC_LENGTH + - FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH + - FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH + - FLAC__OGG_MAPPING_NUM_HEADERS_LENGTH + - FLAC__STREAM_SYNC_LENGTH - ; - FLAC__byte b[flac_max(6u, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)]; - const FLAC__StreamMetadata *metadata = &encoder->private_->streaminfo; - const FLAC__uint64 samples = metadata->data.stream_info.total_samples; - const uint32_t min_framesize = metadata->data.stream_info.min_framesize; - const uint32_t max_framesize = metadata->data.stream_info.max_framesize; - ogg_page page; - - FLAC__ASSERT(metadata->type == FLAC__METADATA_TYPE_STREAMINFO); - FLAC__ASSERT(0 != encoder->private_->seek_callback); - - /* Pre-check that client supports seeking, since we don't want the - * ogg_helper code to ever have to deal with this condition. - */ - if(encoder->private_->seek_callback(encoder, 0, encoder->private_->client_data) == FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED) - return; - - /* All this is based on intimate knowledge of the stream header - * layout, but a change to the header format that would break this - * would also break all streams encoded in the previous format. - */ - - /** - ** Write STREAMINFO stats - **/ - simple_ogg_page__init(&page); - if(!simple_ogg_page__get_at(encoder, encoder->protected_->streaminfo_offset, &page, encoder->private_->seek_callback, encoder->private_->read_callback, encoder->private_->client_data)) { - simple_ogg_page__clear(&page); - return; /* state already set */ - } - - /* - * Write MD5 signature - */ - { - const uint32_t md5_offset = - FIRST_OGG_PACKET_STREAMINFO_PREFIX_LENGTH + - FLAC__STREAM_METADATA_HEADER_LENGTH + - ( - FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN + - FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN - ) / 8; - - if(md5_offset + 16 > (uint32_t)page.body_len) { - encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR; - simple_ogg_page__clear(&page); - return; - } - memcpy(page.body + md5_offset, metadata->data.stream_info.md5sum, 16); - } - - /* - * Write total samples - */ - { - const uint32_t total_samples_byte_offset = - FIRST_OGG_PACKET_STREAMINFO_PREFIX_LENGTH + - FLAC__STREAM_METADATA_HEADER_LENGTH + - ( - FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN + - FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN - - 4 - ) / 8; - - if(total_samples_byte_offset + 5 > (uint32_t)page.body_len) { - encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR; - simple_ogg_page__clear(&page); - return; - } - b[0] = (FLAC__byte)page.body[total_samples_byte_offset] & 0xF0; - b[0] |= (FLAC__byte)((samples >> 32) & 0x0F); - b[1] = (FLAC__byte)((samples >> 24) & 0xFF); - b[2] = (FLAC__byte)((samples >> 16) & 0xFF); - b[3] = (FLAC__byte)((samples >> 8) & 0xFF); - b[4] = (FLAC__byte)(samples & 0xFF); - memcpy(page.body + total_samples_byte_offset, b, 5); - } - - /* - * Write min/max framesize - */ - { - const uint32_t min_framesize_offset = - FIRST_OGG_PACKET_STREAMINFO_PREFIX_LENGTH + - FLAC__STREAM_METADATA_HEADER_LENGTH + - ( - FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN - ) / 8; - - if(min_framesize_offset + 6 > (uint32_t)page.body_len) { - encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR; - simple_ogg_page__clear(&page); - return; - } - b[0] = (FLAC__byte)((min_framesize >> 16) & 0xFF); - b[1] = (FLAC__byte)((min_framesize >> 8) & 0xFF); - b[2] = (FLAC__byte)(min_framesize & 0xFF); - b[3] = (FLAC__byte)((max_framesize >> 16) & 0xFF); - b[4] = (FLAC__byte)((max_framesize >> 8) & 0xFF); - b[5] = (FLAC__byte)(max_framesize & 0xFF); - memcpy(page.body + min_framesize_offset, b, 6); - } - if(!simple_ogg_page__set_at(encoder, encoder->protected_->streaminfo_offset, &page, encoder->private_->seek_callback, encoder->private_->write_callback, encoder->private_->client_data)) { - simple_ogg_page__clear(&page); - return; /* state already set */ - } - simple_ogg_page__clear(&page); - - /* - * Write seektable - */ - if(0 != encoder->private_->seek_table && encoder->private_->seek_table->num_points > 0 && encoder->protected_->seektable_offset > 0) { - uint32_t i; - FLAC__byte *p; - - FLAC__format_seektable_sort(encoder->private_->seek_table); - - FLAC__ASSERT(FLAC__format_seektable_is_legal(encoder->private_->seek_table)); - - simple_ogg_page__init(&page); - if(!simple_ogg_page__get_at(encoder, encoder->protected_->seektable_offset, &page, encoder->private_->seek_callback, encoder->private_->read_callback, encoder->private_->client_data)) { - simple_ogg_page__clear(&page); - return; /* state already set */ - } - - if((FLAC__STREAM_METADATA_HEADER_LENGTH + 18*encoder->private_->seek_table->num_points) != (uint32_t)page.body_len) { - encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR; - simple_ogg_page__clear(&page); - return; - } - - for(i = 0, p = page.body + FLAC__STREAM_METADATA_HEADER_LENGTH; i < encoder->private_->seek_table->num_points; i++, p += 18) { - FLAC__uint64 xx; - uint32_t x; - xx = encoder->private_->seek_table->points[i].sample_number; - b[7] = (FLAC__byte)xx; xx >>= 8; - b[6] = (FLAC__byte)xx; xx >>= 8; - b[5] = (FLAC__byte)xx; xx >>= 8; - b[4] = (FLAC__byte)xx; xx >>= 8; - b[3] = (FLAC__byte)xx; xx >>= 8; - b[2] = (FLAC__byte)xx; xx >>= 8; - b[1] = (FLAC__byte)xx; xx >>= 8; - b[0] = (FLAC__byte)xx; xx >>= 8; - xx = encoder->private_->seek_table->points[i].stream_offset; - b[15] = (FLAC__byte)xx; xx >>= 8; - b[14] = (FLAC__byte)xx; xx >>= 8; - b[13] = (FLAC__byte)xx; xx >>= 8; - b[12] = (FLAC__byte)xx; xx >>= 8; - b[11] = (FLAC__byte)xx; xx >>= 8; - b[10] = (FLAC__byte)xx; xx >>= 8; - b[9] = (FLAC__byte)xx; xx >>= 8; - b[8] = (FLAC__byte)xx; xx >>= 8; - x = encoder->private_->seek_table->points[i].frame_samples; - b[17] = (FLAC__byte)x; x >>= 8; - b[16] = (FLAC__byte)x; x >>= 8; - memcpy(p, b, 18); - } - - if(!simple_ogg_page__set_at(encoder, encoder->protected_->seektable_offset, &page, encoder->private_->seek_callback, encoder->private_->write_callback, encoder->private_->client_data)) { - simple_ogg_page__clear(&page); - return; /* state already set */ - } - simple_ogg_page__clear(&page); - } -} -#endif - -FLAC__bool process_frame_(FLAC__StreamEncoder *encoder, FLAC__bool is_fractional_block, FLAC__bool is_last_block) -{ - FLAC__uint16 crc; - FLAC__ASSERT(encoder->protected_->state == FLAC__STREAM_ENCODER_OK); - - /* - * Accumulate raw signal to the MD5 signature - */ - if(encoder->protected_->do_md5 && !FLAC__MD5Accumulate(&encoder->private_->md5context, (const FLAC__int32 * const *)encoder->private_->integer_signal, encoder->protected_->channels, encoder->protected_->blocksize, (encoder->protected_->bits_per_sample+7) / 8)) { - encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; - return false; - } - - /* - * Process the frame header and subframes into the frame bitbuffer - */ - if(!process_subframes_(encoder, is_fractional_block)) { - /* the above function sets the state for us in case of an error */ - return false; - } - - /* - * Zero-pad the frame to a byte_boundary - */ - if(!FLAC__bitwriter_zero_pad_to_byte_boundary(encoder->private_->frame)) { - encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; - return false; - } - - /* - * CRC-16 the whole thing - */ - FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(encoder->private_->frame)); - if( - !FLAC__bitwriter_get_write_crc16(encoder->private_->frame, &crc) || - !FLAC__bitwriter_write_raw_uint32(encoder->private_->frame, crc, FLAC__FRAME_FOOTER_CRC_LEN) - ) { - encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; - return false; - } - - /* - * Write it - */ - if(!write_bitbuffer_(encoder, encoder->protected_->blocksize, is_last_block)) { - /* the above function sets the state for us in case of an error */ - return false; - } - - /* - * Get ready for the next frame - */ - encoder->private_->current_sample_number = 0; - encoder->private_->current_frame_number++; - encoder->private_->streaminfo.data.stream_info.total_samples += (FLAC__uint64)encoder->protected_->blocksize; - - return true; -} - -FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_fractional_block) -{ - FLAC__FrameHeader frame_header; - uint32_t channel, min_partition_order = encoder->protected_->min_residual_partition_order, max_partition_order; - FLAC__bool do_independent, do_mid_side; - - /* - * Calculate the min,max Rice partition orders - */ - if(is_fractional_block) { - max_partition_order = 0; - } - else { - max_partition_order = FLAC__format_get_max_rice_partition_order_from_blocksize(encoder->protected_->blocksize); - max_partition_order = flac_min(max_partition_order, encoder->protected_->max_residual_partition_order); - } - min_partition_order = flac_min(min_partition_order, max_partition_order); - - /* - * Setup the frame - */ - frame_header.blocksize = encoder->protected_->blocksize; - frame_header.sample_rate = encoder->protected_->sample_rate; - frame_header.channels = encoder->protected_->channels; - frame_header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT; /* the default unless the encoder determines otherwise */ - frame_header.bits_per_sample = encoder->protected_->bits_per_sample; - frame_header.number_type = FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER; - frame_header.number.frame_number = encoder->private_->current_frame_number; - - /* - * Figure out what channel assignments to try - */ - if(encoder->protected_->do_mid_side_stereo) { - if(encoder->protected_->loose_mid_side_stereo) { - if(encoder->private_->loose_mid_side_stereo_frame_count == 0) { - do_independent = true; - do_mid_side = true; - } - else { - do_independent = (encoder->private_->last_channel_assignment == FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT); - do_mid_side = !do_independent; - } - } - else { - do_independent = true; - do_mid_side = true; - } - } - else { - do_independent = true; - do_mid_side = false; - } - - FLAC__ASSERT(do_independent || do_mid_side); - - /* - * Check for wasted bits; set effective bps for each subframe - */ - if(do_independent) { - for(channel = 0; channel < encoder->protected_->channels; channel++) { - uint32_t w = get_wasted_bits_(encoder->private_->integer_signal[channel], encoder->protected_->blocksize); - if (w > encoder->protected_->bits_per_sample) { - w = encoder->protected_->bits_per_sample; - } - encoder->private_->subframe_workspace[channel][0].wasted_bits = encoder->private_->subframe_workspace[channel][1].wasted_bits = w; - encoder->private_->subframe_bps[channel] = encoder->protected_->bits_per_sample - w; - } - } - if(do_mid_side) { - FLAC__ASSERT(encoder->protected_->channels == 2); - for(channel = 0; channel < 2; channel++) { - uint32_t w = get_wasted_bits_(encoder->private_->integer_signal_mid_side[channel], encoder->protected_->blocksize); - if (w > encoder->protected_->bits_per_sample) { - w = encoder->protected_->bits_per_sample; - } - encoder->private_->subframe_workspace_mid_side[channel][0].wasted_bits = encoder->private_->subframe_workspace_mid_side[channel][1].wasted_bits = w; - encoder->private_->subframe_bps_mid_side[channel] = encoder->protected_->bits_per_sample - w + (channel==0? 0:1); - } - } - - /* - * First do a normal encoding pass of each independent channel - */ - if(do_independent) { - for(channel = 0; channel < encoder->protected_->channels; channel++) { - if(! - process_subframe_( - encoder, - min_partition_order, - max_partition_order, - &frame_header, - encoder->private_->subframe_bps[channel], - encoder->private_->integer_signal[channel], - encoder->private_->subframe_workspace_ptr[channel], - encoder->private_->partitioned_rice_contents_workspace_ptr[channel], - encoder->private_->residual_workspace[channel], - encoder->private_->best_subframe+channel, - encoder->private_->best_subframe_bits+channel - ) - ) - return false; - } - } - - /* - * Now do mid and side channels if requested - */ - if(do_mid_side) { - FLAC__ASSERT(encoder->protected_->channels == 2); - - for(channel = 0; channel < 2; channel++) { - if(! - process_subframe_( - encoder, - min_partition_order, - max_partition_order, - &frame_header, - encoder->private_->subframe_bps_mid_side[channel], - encoder->private_->integer_signal_mid_side[channel], - encoder->private_->subframe_workspace_ptr_mid_side[channel], - encoder->private_->partitioned_rice_contents_workspace_ptr_mid_side[channel], - encoder->private_->residual_workspace_mid_side[channel], - encoder->private_->best_subframe_mid_side+channel, - encoder->private_->best_subframe_bits_mid_side+channel - ) - ) - return false; - } - } - - /* - * Compose the frame bitbuffer - */ - if(do_mid_side) { - uint32_t left_bps = 0, right_bps = 0; /* initialized only to prevent superfluous compiler warning */ - FLAC__Subframe *left_subframe = 0, *right_subframe = 0; /* initialized only to prevent superfluous compiler warning */ - FLAC__ChannelAssignment channel_assignment; - - FLAC__ASSERT(encoder->protected_->channels == 2); - - if(encoder->protected_->loose_mid_side_stereo && encoder->private_->loose_mid_side_stereo_frame_count > 0) { - channel_assignment = (encoder->private_->last_channel_assignment == FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT? FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT : FLAC__CHANNEL_ASSIGNMENT_MID_SIDE); - } - else { - uint32_t bits[4]; /* WATCHOUT - indexed by FLAC__ChannelAssignment */ - uint32_t min_bits; - int ca; - - FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT == 0); - FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE == 1); - FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE == 2); - FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_MID_SIDE == 3); - FLAC__ASSERT(do_independent && do_mid_side); - - /* We have to figure out which channel assignent results in the smallest frame */ - bits[FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT] = encoder->private_->best_subframe_bits [0] + encoder->private_->best_subframe_bits [1]; - bits[FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE ] = encoder->private_->best_subframe_bits [0] + encoder->private_->best_subframe_bits_mid_side[1]; - bits[FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE ] = encoder->private_->best_subframe_bits [1] + encoder->private_->best_subframe_bits_mid_side[1]; - bits[FLAC__CHANNEL_ASSIGNMENT_MID_SIDE ] = encoder->private_->best_subframe_bits_mid_side[0] + encoder->private_->best_subframe_bits_mid_side[1]; - - channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT; - min_bits = bits[channel_assignment]; - for(ca = 1; ca <= 3; ca++) { - if(bits[ca] < min_bits) { - min_bits = bits[ca]; - channel_assignment = (FLAC__ChannelAssignment)ca; - } - } - } - - frame_header.channel_assignment = channel_assignment; - - if(!FLAC__frame_add_header(&frame_header, encoder->private_->frame)) { - encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; - return false; - } - - switch(channel_assignment) { - case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT: - left_subframe = &encoder->private_->subframe_workspace [0][encoder->private_->best_subframe [0]]; - right_subframe = &encoder->private_->subframe_workspace [1][encoder->private_->best_subframe [1]]; - break; - case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE: - left_subframe = &encoder->private_->subframe_workspace [0][encoder->private_->best_subframe [0]]; - right_subframe = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]]; - break; - case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE: - left_subframe = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]]; - right_subframe = &encoder->private_->subframe_workspace [1][encoder->private_->best_subframe [1]]; - break; - case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE: - left_subframe = &encoder->private_->subframe_workspace_mid_side[0][encoder->private_->best_subframe_mid_side[0]]; - right_subframe = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]]; - break; - default: - FLAC__ASSERT(0); - } - - switch(channel_assignment) { - case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT: - left_bps = encoder->private_->subframe_bps [0]; - right_bps = encoder->private_->subframe_bps [1]; - break; - case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE: - left_bps = encoder->private_->subframe_bps [0]; - right_bps = encoder->private_->subframe_bps_mid_side[1]; - break; - case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE: - left_bps = encoder->private_->subframe_bps_mid_side[1]; - right_bps = encoder->private_->subframe_bps [1]; - break; - case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE: - left_bps = encoder->private_->subframe_bps_mid_side[0]; - right_bps = encoder->private_->subframe_bps_mid_side[1]; - break; - default: - FLAC__ASSERT(0); - } - - /* note that encoder_add_subframe_ sets the state for us in case of an error */ - if(!add_subframe_(encoder, frame_header.blocksize, left_bps , left_subframe , encoder->private_->frame)) - return false; - if(!add_subframe_(encoder, frame_header.blocksize, right_bps, right_subframe, encoder->private_->frame)) - return false; - } - else { - if(!FLAC__frame_add_header(&frame_header, encoder->private_->frame)) { - encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; - return false; - } - - for(channel = 0; channel < encoder->protected_->channels; channel++) { - if(!add_subframe_(encoder, frame_header.blocksize, encoder->private_->subframe_bps[channel], &encoder->private_->subframe_workspace[channel][encoder->private_->best_subframe[channel]], encoder->private_->frame)) { - /* the above function sets the state for us in case of an error */ - return false; - } - } - } - - if(encoder->protected_->loose_mid_side_stereo) { - encoder->private_->loose_mid_side_stereo_frame_count++; - if(encoder->private_->loose_mid_side_stereo_frame_count >= encoder->private_->loose_mid_side_stereo_frames) - encoder->private_->loose_mid_side_stereo_frame_count = 0; - } - - encoder->private_->last_channel_assignment = frame_header.channel_assignment; - - return true; -} - -FLAC__bool process_subframe_( - FLAC__StreamEncoder *encoder, - uint32_t min_partition_order, - uint32_t max_partition_order, - const FLAC__FrameHeader *frame_header, - uint32_t subframe_bps, - const FLAC__int32 integer_signal[], - FLAC__Subframe *subframe[2], - FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents[2], - FLAC__int32 *residual[2], - uint32_t *best_subframe, - uint32_t *best_bits -) -{ -#ifndef FLAC__INTEGER_ONLY_LIBRARY - float fixed_residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]; -#else - FLAC__fixedpoint fixed_residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]; -#endif -#ifndef FLAC__INTEGER_ONLY_LIBRARY - double lpc_residual_bits_per_sample; - FLAC__real autoc[FLAC__MAX_LPC_ORDER+1]; /* WATCHOUT: the size is important even though encoder->protected_->max_lpc_order might be less; some asm and x86 intrinsic routines need all the space */ - double lpc_error[FLAC__MAX_LPC_ORDER]; - uint32_t min_lpc_order, max_lpc_order, lpc_order; - uint32_t min_qlp_coeff_precision, max_qlp_coeff_precision, qlp_coeff_precision; -#endif - uint32_t min_fixed_order, max_fixed_order, guess_fixed_order, fixed_order; - uint32_t rice_parameter; - uint32_t _candidate_bits, _best_bits; - uint32_t _best_subframe; - /* only use RICE2 partitions if stream bps > 16 */ - const uint32_t rice_parameter_limit = FLAC__stream_encoder_get_bits_per_sample(encoder) > 16? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER; - - FLAC__ASSERT(frame_header->blocksize > 0); - - /* verbatim subframe is the baseline against which we measure other compressed subframes */ - _best_subframe = 0; - if(encoder->private_->disable_verbatim_subframes && frame_header->blocksize >= FLAC__MAX_FIXED_ORDER) - _best_bits = UINT_MAX; - else - _best_bits = evaluate_verbatim_subframe_(encoder, integer_signal, frame_header->blocksize, subframe_bps, subframe[_best_subframe]); - - if(frame_header->blocksize >= FLAC__MAX_FIXED_ORDER) { - uint32_t signal_is_constant = false; - if(subframe_bps + 4 + FLAC__bitmath_ilog2((frame_header->blocksize-FLAC__MAX_FIXED_ORDER)|1) <= 32) - guess_fixed_order = encoder->private_->local_fixed_compute_best_predictor(integer_signal+FLAC__MAX_FIXED_ORDER, frame_header->blocksize-FLAC__MAX_FIXED_ORDER, fixed_residual_bits_per_sample); - else - guess_fixed_order = encoder->private_->local_fixed_compute_best_predictor_wide(integer_signal+FLAC__MAX_FIXED_ORDER, frame_header->blocksize-FLAC__MAX_FIXED_ORDER, fixed_residual_bits_per_sample); - /* check for constant subframe */ - if( - !encoder->private_->disable_constant_subframes && -#ifndef FLAC__INTEGER_ONLY_LIBRARY - fixed_residual_bits_per_sample[1] == 0.0 -#else - fixed_residual_bits_per_sample[1] == FLAC__FP_ZERO -#endif - ) { - /* the above means it's possible all samples are the same value; now double-check it: */ - uint32_t i; - signal_is_constant = true; - for(i = 1; i < frame_header->blocksize; i++) { - if(integer_signal[0] != integer_signal[i]) { - signal_is_constant = false; - break; - } - } - } - if(signal_is_constant) { - _candidate_bits = evaluate_constant_subframe_(encoder, integer_signal[0], frame_header->blocksize, subframe_bps, subframe[!_best_subframe]); - if(_candidate_bits < _best_bits) { - _best_subframe = !_best_subframe; - _best_bits = _candidate_bits; - } - } - else { - if(!encoder->private_->disable_fixed_subframes || (encoder->protected_->max_lpc_order == 0 && _best_bits == UINT_MAX)) { - /* encode fixed */ - if(encoder->protected_->do_exhaustive_model_search) { - min_fixed_order = 0; - max_fixed_order = FLAC__MAX_FIXED_ORDER; - } - else { - min_fixed_order = max_fixed_order = guess_fixed_order; - } - if(max_fixed_order >= frame_header->blocksize) - max_fixed_order = frame_header->blocksize - 1; - for(fixed_order = min_fixed_order; fixed_order <= max_fixed_order; fixed_order++) { -#ifndef FLAC__INTEGER_ONLY_LIBRARY - if(fixed_residual_bits_per_sample[fixed_order] >= (float)subframe_bps) - continue; /* don't even try */ - rice_parameter = (fixed_residual_bits_per_sample[fixed_order] > 0.0)? (uint32_t)(fixed_residual_bits_per_sample[fixed_order]+0.5) : 0; /* 0.5 is for rounding */ -#else - if(FLAC__fixedpoint_trunc(fixed_residual_bits_per_sample[fixed_order]) >= (int)subframe_bps) - continue; /* don't even try */ - rice_parameter = (fixed_residual_bits_per_sample[fixed_order] > FLAC__FP_ZERO)? (uint32_t)FLAC__fixedpoint_trunc(fixed_residual_bits_per_sample[fixed_order]+FLAC__FP_ONE_HALF) : 0; /* 0.5 is for rounding */ -#endif - rice_parameter++; /* to account for the signed->uint32_t conversion during rice coding */ - if(rice_parameter >= rice_parameter_limit) { -#ifndef NDEBUG - fprintf(stderr, "clipping rice_parameter (%u -> %u) @0\n", rice_parameter, rice_parameter_limit - 1); -#endif - rice_parameter = rice_parameter_limit - 1; - } - _candidate_bits = - evaluate_fixed_subframe_( - encoder, - integer_signal, - residual[!_best_subframe], - encoder->private_->abs_residual_partition_sums, - encoder->private_->raw_bits_per_partition, - frame_header->blocksize, - subframe_bps, - fixed_order, - rice_parameter, - rice_parameter_limit, - min_partition_order, - max_partition_order, - encoder->protected_->do_escape_coding, - encoder->protected_->rice_parameter_search_dist, - subframe[!_best_subframe], - partitioned_rice_contents[!_best_subframe] - ); - if(_candidate_bits < _best_bits) { - _best_subframe = !_best_subframe; - _best_bits = _candidate_bits; - } - } - } - -#ifndef FLAC__INTEGER_ONLY_LIBRARY - /* encode lpc */ - if(encoder->protected_->max_lpc_order > 0) { - if(encoder->protected_->max_lpc_order >= frame_header->blocksize) - max_lpc_order = frame_header->blocksize-1; - else - max_lpc_order = encoder->protected_->max_lpc_order; - if(max_lpc_order > 0) { - uint32_t a; - for (a = 0; a < encoder->protected_->num_apodizations; a++) { - FLAC__lpc_window_data(integer_signal, encoder->private_->window[a], encoder->private_->windowed_signal, frame_header->blocksize); - encoder->private_->local_lpc_compute_autocorrelation(encoder->private_->windowed_signal, frame_header->blocksize, max_lpc_order+1, autoc); - /* if autoc[0] == 0.0, the signal is constant and we usually won't get here, but it can happen */ - if(autoc[0] != 0.0) { - FLAC__lpc_compute_lp_coefficients(autoc, &max_lpc_order, encoder->private_->lp_coeff, lpc_error); - if(encoder->protected_->do_exhaustive_model_search) { - min_lpc_order = 1; - } - else { - const uint32_t guess_lpc_order = - FLAC__lpc_compute_best_order( - lpc_error, - max_lpc_order, - frame_header->blocksize, - subframe_bps + ( - encoder->protected_->do_qlp_coeff_prec_search? - FLAC__MIN_QLP_COEFF_PRECISION : /* have to guess; use the min possible size to avoid accidentally favoring lower orders */ - encoder->protected_->qlp_coeff_precision - ) - ); - min_lpc_order = max_lpc_order = guess_lpc_order; - } - if(max_lpc_order >= frame_header->blocksize) - max_lpc_order = frame_header->blocksize - 1; - for(lpc_order = min_lpc_order; lpc_order <= max_lpc_order; lpc_order++) { - lpc_residual_bits_per_sample = FLAC__lpc_compute_expected_bits_per_residual_sample(lpc_error[lpc_order-1], frame_header->blocksize-lpc_order); - if(lpc_residual_bits_per_sample >= (double)subframe_bps) - continue; /* don't even try */ - rice_parameter = (lpc_residual_bits_per_sample > 0.0)? (uint32_t)(lpc_residual_bits_per_sample+0.5) : 0; /* 0.5 is for rounding */ - rice_parameter++; /* to account for the signed->uint32_t conversion during rice coding */ - if(rice_parameter >= rice_parameter_limit) { -#ifndef NDEBUG - fprintf(stderr, "clipping rice_parameter (%u -> %u) @1\n", rice_parameter, rice_parameter_limit - 1); -#endif - rice_parameter = rice_parameter_limit - 1; - } - if(encoder->protected_->do_qlp_coeff_prec_search) { - min_qlp_coeff_precision = FLAC__MIN_QLP_COEFF_PRECISION; - /* try to keep qlp coeff precision such that only 32-bit math is required for decode of <=16bps(+1bps for side channel) streams */ - if(subframe_bps <= 17) { - max_qlp_coeff_precision = flac_min(32 - subframe_bps - FLAC__bitmath_ilog2(lpc_order), FLAC__MAX_QLP_COEFF_PRECISION); - max_qlp_coeff_precision = flac_max(max_qlp_coeff_precision, min_qlp_coeff_precision); - } - else - max_qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION; - } - else { - min_qlp_coeff_precision = max_qlp_coeff_precision = encoder->protected_->qlp_coeff_precision; - } - for(qlp_coeff_precision = min_qlp_coeff_precision; qlp_coeff_precision <= max_qlp_coeff_precision; qlp_coeff_precision++) { - _candidate_bits = - evaluate_lpc_subframe_( - encoder, - integer_signal, - residual[!_best_subframe], - encoder->private_->abs_residual_partition_sums, - encoder->private_->raw_bits_per_partition, - encoder->private_->lp_coeff[lpc_order-1], - frame_header->blocksize, - subframe_bps, - lpc_order, - qlp_coeff_precision, - rice_parameter, - rice_parameter_limit, - min_partition_order, - max_partition_order, - encoder->protected_->do_escape_coding, - encoder->protected_->rice_parameter_search_dist, - subframe[!_best_subframe], - partitioned_rice_contents[!_best_subframe] - ); - if(_candidate_bits > 0) { /* if == 0, there was a problem quantizing the lpcoeffs */ - if(_candidate_bits < _best_bits) { - _best_subframe = !_best_subframe; - _best_bits = _candidate_bits; - } - } - } - } - } - } - } - } -#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ - } - } - - /* under rare circumstances this can happen when all but lpc subframe types are disabled: */ - if(_best_bits == UINT_MAX) { - FLAC__ASSERT(_best_subframe == 0); - _best_bits = evaluate_verbatim_subframe_(encoder, integer_signal, frame_header->blocksize, subframe_bps, subframe[_best_subframe]); - } - - *best_subframe = _best_subframe; - *best_bits = _best_bits; - - return true; -} - -FLAC__bool add_subframe_( - FLAC__StreamEncoder *encoder, - uint32_t blocksize, - uint32_t subframe_bps, - const FLAC__Subframe *subframe, - FLAC__BitWriter *frame -) -{ - switch(subframe->type) { - case FLAC__SUBFRAME_TYPE_CONSTANT: - if(!FLAC__subframe_add_constant(&(subframe->data.constant), subframe_bps, subframe->wasted_bits, frame)) { - encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; - return false; - } - break; - case FLAC__SUBFRAME_TYPE_FIXED: - if(!FLAC__subframe_add_fixed(&(subframe->data.fixed), blocksize - subframe->data.fixed.order, subframe_bps, subframe->wasted_bits, frame)) { - encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; - return false; - } - break; - case FLAC__SUBFRAME_TYPE_LPC: - if(!FLAC__subframe_add_lpc(&(subframe->data.lpc), blocksize - subframe->data.lpc.order, subframe_bps, subframe->wasted_bits, frame)) { - encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; - return false; - } - break; - case FLAC__SUBFRAME_TYPE_VERBATIM: - if(!FLAC__subframe_add_verbatim(&(subframe->data.verbatim), blocksize, subframe_bps, subframe->wasted_bits, frame)) { - encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; - return false; - } - break; - default: - FLAC__ASSERT(0); - } - - return true; -} - -#define SPOTCHECK_ESTIMATE 0 -#if SPOTCHECK_ESTIMATE -static void spotcheck_subframe_estimate_( - FLAC__StreamEncoder *encoder, - uint32_t blocksize, - uint32_t subframe_bps, - const FLAC__Subframe *subframe, - uint32_t estimate -) -{ - FLAC__bool ret; - FLAC__BitWriter *frame = FLAC__bitwriter_new(); - if(frame == 0) { - fprintf(stderr, "EST: can't allocate frame\n"); - return; - } - if(!FLAC__bitwriter_init(frame)) { - fprintf(stderr, "EST: can't init frame\n"); - return; - } - ret = add_subframe_(encoder, blocksize, subframe_bps, subframe, frame); - FLAC__ASSERT(ret); - { - const uint32_t actual = FLAC__bitwriter_get_input_bits_unconsumed(frame); - if(estimate != actual) - fprintf(stderr, "EST: bad, frame#%u sub#%%d type=%8s est=%u, actual=%u, delta=%d\n", encoder->private_->current_frame_number, FLAC__SubframeTypeString[subframe->type], estimate, actual, (int)actual-(int)estimate); - } - FLAC__bitwriter_delete(frame); -} -#endif - -uint32_t evaluate_constant_subframe_( - FLAC__StreamEncoder *encoder, - const FLAC__int32 signal, - uint32_t blocksize, - uint32_t subframe_bps, - FLAC__Subframe *subframe -) -{ - uint32_t estimate; - subframe->type = FLAC__SUBFRAME_TYPE_CONSTANT; - subframe->data.constant.value = signal; - - estimate = FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + subframe->wasted_bits + subframe_bps; - -#if SPOTCHECK_ESTIMATE - spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate); -#else - (void)encoder, (void)blocksize; -#endif - - return estimate; -} - -uint32_t evaluate_fixed_subframe_( - FLAC__StreamEncoder *encoder, - const FLAC__int32 signal[], - FLAC__int32 residual[], - FLAC__uint64 abs_residual_partition_sums[], - uint32_t raw_bits_per_partition[], - uint32_t blocksize, - uint32_t subframe_bps, - uint32_t order, - uint32_t rice_parameter, - uint32_t rice_parameter_limit, - uint32_t min_partition_order, - uint32_t max_partition_order, - FLAC__bool do_escape_coding, - uint32_t rice_parameter_search_dist, - FLAC__Subframe *subframe, - FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents -) -{ - uint32_t i, residual_bits, estimate; - const uint32_t residual_samples = blocksize - order; - - FLAC__fixed_compute_residual(signal+order, residual_samples, order, residual); - - subframe->type = FLAC__SUBFRAME_TYPE_FIXED; - - subframe->data.fixed.entropy_coding_method.type = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE; - subframe->data.fixed.entropy_coding_method.data.partitioned_rice.contents = partitioned_rice_contents; - subframe->data.fixed.residual = residual; - - residual_bits = - find_best_partition_order_( - encoder->private_, - residual, - abs_residual_partition_sums, - raw_bits_per_partition, - residual_samples, - order, - rice_parameter, - rice_parameter_limit, - min_partition_order, - max_partition_order, - subframe_bps, - do_escape_coding, - rice_parameter_search_dist, - &subframe->data.fixed.entropy_coding_method - ); - - subframe->data.fixed.order = order; - for(i = 0; i < order; i++) - subframe->data.fixed.warmup[i] = signal[i]; - - estimate = FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + subframe->wasted_bits + (order * subframe_bps) + residual_bits; - -#if SPOTCHECK_ESTIMATE - spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate); -#endif - - return estimate; -} - -#ifndef FLAC__INTEGER_ONLY_LIBRARY -uint32_t evaluate_lpc_subframe_( - FLAC__StreamEncoder *encoder, - const FLAC__int32 signal[], - FLAC__int32 residual[], - FLAC__uint64 abs_residual_partition_sums[], - uint32_t raw_bits_per_partition[], - const FLAC__real lp_coeff[], - uint32_t blocksize, - uint32_t subframe_bps, - uint32_t order, - uint32_t qlp_coeff_precision, - uint32_t rice_parameter, - uint32_t rice_parameter_limit, - uint32_t min_partition_order, - uint32_t max_partition_order, - FLAC__bool do_escape_coding, - uint32_t rice_parameter_search_dist, - FLAC__Subframe *subframe, - FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents -) -{ - FLAC__int32 qlp_coeff[FLAC__MAX_LPC_ORDER]; /* WATCHOUT: the size is important; some x86 intrinsic routines need more than lpc order elements */ - uint32_t i, residual_bits, estimate; - int quantization, ret; - const uint32_t residual_samples = blocksize - order; - - /* try to keep qlp coeff precision such that only 32-bit math is required for decode of <=16bps(+1bps for side channel) streams */ - if(subframe_bps <= 17) { - FLAC__ASSERT(order > 0); - FLAC__ASSERT(order <= FLAC__MAX_LPC_ORDER); - qlp_coeff_precision = flac_min(qlp_coeff_precision, 32 - subframe_bps - FLAC__bitmath_ilog2(order)); - } - - ret = FLAC__lpc_quantize_coefficients(lp_coeff, order, qlp_coeff_precision, qlp_coeff, &quantization); - if(ret != 0) - return 0; /* this is a hack to indicate to the caller that we can't do lp at this order on this subframe */ - - if(subframe_bps + qlp_coeff_precision + FLAC__bitmath_ilog2(order) <= 32) - if(subframe_bps <= 16 && qlp_coeff_precision <= 16) - encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit(signal+order, residual_samples, qlp_coeff, order, quantization, residual); - else - encoder->private_->local_lpc_compute_residual_from_qlp_coefficients(signal+order, residual_samples, qlp_coeff, order, quantization, residual); - else - encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit(signal+order, residual_samples, qlp_coeff, order, quantization, residual); - - subframe->type = FLAC__SUBFRAME_TYPE_LPC; - - subframe->data.lpc.entropy_coding_method.type = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE; - subframe->data.lpc.entropy_coding_method.data.partitioned_rice.contents = partitioned_rice_contents; - subframe->data.lpc.residual = residual; - - residual_bits = - find_best_partition_order_( - encoder->private_, - residual, - abs_residual_partition_sums, - raw_bits_per_partition, - residual_samples, - order, - rice_parameter, - rice_parameter_limit, - min_partition_order, - max_partition_order, - subframe_bps, - do_escape_coding, - rice_parameter_search_dist, - &subframe->data.lpc.entropy_coding_method - ); - - subframe->data.lpc.order = order; - subframe->data.lpc.qlp_coeff_precision = qlp_coeff_precision; - subframe->data.lpc.quantization_level = quantization; - memcpy(subframe->data.lpc.qlp_coeff, qlp_coeff, sizeof(FLAC__int32)*FLAC__MAX_LPC_ORDER); - for(i = 0; i < order; i++) - subframe->data.lpc.warmup[i] = signal[i]; - - estimate = FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + subframe->wasted_bits + FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN + FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN + (order * (qlp_coeff_precision + subframe_bps)) + residual_bits; - -#if SPOTCHECK_ESTIMATE - spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate); -#endif - - return estimate; -} -#endif - -uint32_t evaluate_verbatim_subframe_( - FLAC__StreamEncoder *encoder, - const FLAC__int32 signal[], - uint32_t blocksize, - uint32_t subframe_bps, - FLAC__Subframe *subframe -) -{ - uint32_t estimate; - - subframe->type = FLAC__SUBFRAME_TYPE_VERBATIM; - - subframe->data.verbatim.data = signal; - - estimate = FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + subframe->wasted_bits + (blocksize * subframe_bps); - -#if SPOTCHECK_ESTIMATE - spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate); -#else - (void)encoder; -#endif - - return estimate; -} - -uint32_t find_best_partition_order_( - FLAC__StreamEncoderPrivate *private_, - const FLAC__int32 residual[], - FLAC__uint64 abs_residual_partition_sums[], - uint32_t raw_bits_per_partition[], - uint32_t residual_samples, - uint32_t predictor_order, - uint32_t rice_parameter, - uint32_t rice_parameter_limit, - uint32_t min_partition_order, - uint32_t max_partition_order, - uint32_t bps, - FLAC__bool do_escape_coding, - uint32_t rice_parameter_search_dist, - FLAC__EntropyCodingMethod *best_ecm -) -{ - uint32_t residual_bits, best_residual_bits = 0; - uint32_t best_parameters_index = 0; - uint32_t best_partition_order = 0; - const uint32_t blocksize = residual_samples + predictor_order; - - max_partition_order = FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(max_partition_order, blocksize, predictor_order); - min_partition_order = flac_min(min_partition_order, max_partition_order); - - private_->local_precompute_partition_info_sums(residual, abs_residual_partition_sums, residual_samples, predictor_order, min_partition_order, max_partition_order, bps); - - if(do_escape_coding) - precompute_partition_info_escapes_(residual, raw_bits_per_partition, residual_samples, predictor_order, min_partition_order, max_partition_order); - - { - int partition_order; - uint32_t sum; - - for(partition_order = (int)max_partition_order, sum = 0; partition_order >= (int)min_partition_order; partition_order--) { - if(! - set_partitioned_rice_( -#ifdef EXACT_RICE_BITS_CALCULATION - residual, -#endif - abs_residual_partition_sums+sum, - raw_bits_per_partition+sum, - residual_samples, - predictor_order, - rice_parameter, - rice_parameter_limit, - rice_parameter_search_dist, - (uint32_t)partition_order, - do_escape_coding, - &private_->partitioned_rice_contents_extra[!best_parameters_index], - &residual_bits - ) - ) - { - FLAC__ASSERT(best_residual_bits != 0); - break; - } - sum += 1u << partition_order; - if(best_residual_bits == 0 || residual_bits < best_residual_bits) { - best_residual_bits = residual_bits; - best_parameters_index = !best_parameters_index; - best_partition_order = partition_order; - } - } - } - - best_ecm->data.partitioned_rice.order = best_partition_order; - - { - /* - * We are allowed to de-const the pointer based on our special - * knowledge; it is const to the outside world. - */ - FLAC__EntropyCodingMethod_PartitionedRiceContents* prc = (FLAC__EntropyCodingMethod_PartitionedRiceContents*)best_ecm->data.partitioned_rice.contents; - uint32_t partition; - - /* save best parameters and raw_bits */ - FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(prc, flac_max(6u, best_partition_order)); - memcpy(prc->parameters, private_->partitioned_rice_contents_extra[best_parameters_index].parameters, sizeof(uint32_t)*(1<<(best_partition_order))); - if(do_escape_coding) - memcpy(prc->raw_bits, private_->partitioned_rice_contents_extra[best_parameters_index].raw_bits, sizeof(uint32_t)*(1<<(best_partition_order))); - /* - * Now need to check if the type should be changed to - * FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2 based on the - * size of the rice parameters. - */ - for(partition = 0; partition < (1u<parameters[partition] >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) { - best_ecm->type = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2; - break; - } - } - } - - return best_residual_bits; -} - -void precompute_partition_info_sums_( - const FLAC__int32 residual[], - FLAC__uint64 abs_residual_partition_sums[], - uint32_t residual_samples, - uint32_t predictor_order, - uint32_t min_partition_order, - uint32_t max_partition_order, - uint32_t bps -) -{ - const uint32_t default_partition_samples = (residual_samples + predictor_order) >> max_partition_order; - uint32_t partitions = 1u << max_partition_order; - - FLAC__ASSERT(default_partition_samples > predictor_order); - - /* first do max_partition_order */ - { - const uint32_t threshold = 32 - FLAC__bitmath_ilog2(default_partition_samples); - uint32_t partition, residual_sample, end = (uint32_t)(-(int)predictor_order); - /* WATCHOUT: "bps + FLAC__MAX_EXTRA_RESIDUAL_BPS" is the maximum assumed size of the average residual magnitude */ - if(bps + FLAC__MAX_EXTRA_RESIDUAL_BPS < threshold) { - for(partition = residual_sample = 0; partition < partitions; partition++) { - FLAC__uint32 abs_residual_partition_sum = 0; - end += default_partition_samples; - for( ; residual_sample < end; residual_sample++) - abs_residual_partition_sum += abs(residual[residual_sample]); /* abs(INT_MIN) is undefined, but if the residual is INT_MIN we have bigger problems */ - abs_residual_partition_sums[partition] = abs_residual_partition_sum; - } - } - else { /* have to pessimistically use 64 bits for accumulator */ - for(partition = residual_sample = 0; partition < partitions; partition++) { - FLAC__uint64 abs_residual_partition_sum64 = 0; - end += default_partition_samples; - for( ; residual_sample < end; residual_sample++) - abs_residual_partition_sum64 += abs(residual[residual_sample]); /* abs(INT_MIN) is undefined, but if the residual is INT_MIN we have bigger problems */ - abs_residual_partition_sums[partition] = abs_residual_partition_sum64; - } - } - } - - /* now merge partitions for lower orders */ - { - uint32_t from_partition = 0, to_partition = partitions; - int partition_order; - for(partition_order = (int)max_partition_order - 1; partition_order >= (int)min_partition_order; partition_order--) { - uint32_t i; - partitions >>= 1; - for(i = 0; i < partitions; i++) { - abs_residual_partition_sums[to_partition++] = - abs_residual_partition_sums[from_partition ] + - abs_residual_partition_sums[from_partition+1]; - from_partition += 2; - } - } - } -} - -void precompute_partition_info_escapes_( - const FLAC__int32 residual[], - uint32_t raw_bits_per_partition[], - uint32_t residual_samples, - uint32_t predictor_order, - uint32_t min_partition_order, - uint32_t max_partition_order -) -{ - int partition_order; - uint32_t from_partition, to_partition = 0; - const uint32_t blocksize = residual_samples + predictor_order; - - /* first do max_partition_order */ - for(partition_order = (int)max_partition_order; partition_order >= 0; partition_order--) { - FLAC__int32 r; - FLAC__uint32 rmax; - uint32_t partition, partition_sample, partition_samples, residual_sample; - const uint32_t partitions = 1u << partition_order; - const uint32_t default_partition_samples = blocksize >> partition_order; - - FLAC__ASSERT(default_partition_samples > predictor_order); - - for(partition = residual_sample = 0; partition < partitions; partition++) { - partition_samples = default_partition_samples; - if(partition == 0) - partition_samples -= predictor_order; - rmax = 0; - for(partition_sample = 0; partition_sample < partition_samples; partition_sample++) { - r = residual[residual_sample++]; - /* OPT: maybe faster: rmax |= r ^ (r>>31) */ - if(r < 0) - rmax |= ~r; - else - rmax |= r; - } - /* now we know all residual values are in the range [-rmax-1,rmax] */ - raw_bits_per_partition[partition] = rmax? FLAC__bitmath_ilog2(rmax) + 2 : 1; - } - to_partition = partitions; - break; /*@@@ yuck, should remove the 'for' loop instead */ - } - - /* now merge partitions for lower orders */ - for(from_partition = 0, --partition_order; partition_order >= (int)min_partition_order; partition_order--) { - uint32_t m; - uint32_t i; - const uint32_t partitions = 1u << partition_order; - for(i = 0; i < partitions; i++) { - m = raw_bits_per_partition[from_partition]; - from_partition++; - raw_bits_per_partition[to_partition] = flac_max(m, raw_bits_per_partition[from_partition]); - from_partition++; - to_partition++; - } - } -} - -#ifdef EXACT_RICE_BITS_CALCULATION -static inline uint32_t count_rice_bits_in_partition_( - const uint32_t rice_parameter, - const uint32_t partition_samples, - const FLAC__int32 *residual -) -{ - uint32_t i, partition_bits = - FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN + /* actually could end up being FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN but err on side of 16bps */ - (1+rice_parameter) * partition_samples /* 1 for unary stop bit + rice_parameter for the binary portion */ - ; - for(i = 0; i < partition_samples; i++) - partition_bits += ( (FLAC__uint32)((residual[i]<<1)^(residual[i]>>31)) >> rice_parameter ); - return partition_bits; -} -#else -static inline uint32_t count_rice_bits_in_partition_( - const uint32_t rice_parameter, - const uint32_t partition_samples, - const FLAC__uint64 abs_residual_partition_sum -) -{ - return - FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN + /* actually could end up being FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN but err on side of 16bps */ - (1+rice_parameter) * partition_samples + /* 1 for unary stop bit + rice_parameter for the binary portion */ - ( - rice_parameter? - (uint32_t)(abs_residual_partition_sum >> (rice_parameter-1)) /* rice_parameter-1 because the real coder sign-folds instead of using a sign bit */ - : (uint32_t)(abs_residual_partition_sum << 1) /* can't shift by negative number, so reverse */ - ) - - (partition_samples >> 1) - /* -(partition_samples>>1) to subtract out extra contributions to the abs_residual_partition_sum. - * The actual number of bits used is closer to the sum(for all i in the partition) of abs(residual[i])>>(rice_parameter-1) - * By using the abs_residual_partition sum, we also add in bits in the LSBs that would normally be shifted out. - * So the subtraction term tries to guess how many extra bits were contributed. - * If the LSBs are randomly distributed, this should average to 0.5 extra bits per sample. - */ - ; -} -#endif - -FLAC__bool set_partitioned_rice_( -#ifdef EXACT_RICE_BITS_CALCULATION - const FLAC__int32 residual[], -#endif - const FLAC__uint64 abs_residual_partition_sums[], - const uint32_t raw_bits_per_partition[], - const uint32_t residual_samples, - const uint32_t predictor_order, - const uint32_t suggested_rice_parameter, - const uint32_t rice_parameter_limit, - const uint32_t rice_parameter_search_dist, - const uint32_t partition_order, - const FLAC__bool search_for_escapes, - FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, - uint32_t *bits -) -{ - uint32_t rice_parameter, partition_bits; - uint32_t best_partition_bits, best_rice_parameter = 0; - uint32_t bits_ = FLAC__ENTROPY_CODING_METHOD_TYPE_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN; - uint32_t *parameters, *raw_bits; -#ifdef ENABLE_RICE_PARAMETER_SEARCH - uint32_t min_rice_parameter, max_rice_parameter; -#else - (void)rice_parameter_search_dist; -#endif - - FLAC__ASSERT(suggested_rice_parameter < FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER); - FLAC__ASSERT(rice_parameter_limit <= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER); - - FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(partitioned_rice_contents, flac_max(6u, partition_order)); - parameters = partitioned_rice_contents->parameters; - raw_bits = partitioned_rice_contents->raw_bits; - - if(partition_order == 0) { - best_partition_bits = (uint32_t)(-1); -#ifdef ENABLE_RICE_PARAMETER_SEARCH - if(rice_parameter_search_dist) { - if(suggested_rice_parameter < rice_parameter_search_dist) - min_rice_parameter = 0; - else - min_rice_parameter = suggested_rice_parameter - rice_parameter_search_dist; - max_rice_parameter = suggested_rice_parameter + rice_parameter_search_dist; - if(max_rice_parameter >= rice_parameter_limit) { -#ifndef NDEBUG - fprintf(stderr, "clipping rice_parameter (%u -> %u) @5\n", max_rice_parameter, rice_parameter_limit - 1); -#endif - max_rice_parameter = rice_parameter_limit - 1; - } - } - else - min_rice_parameter = max_rice_parameter = suggested_rice_parameter; - - for(rice_parameter = min_rice_parameter; rice_parameter <= max_rice_parameter; rice_parameter++) { -#else - rice_parameter = suggested_rice_parameter; -#endif -#ifdef EXACT_RICE_BITS_CALCULATION - partition_bits = count_rice_bits_in_partition_(rice_parameter, residual_samples, residual); -#else - partition_bits = count_rice_bits_in_partition_(rice_parameter, residual_samples, abs_residual_partition_sums[0]); -#endif - if(partition_bits < best_partition_bits) { - best_rice_parameter = rice_parameter; - best_partition_bits = partition_bits; - } -#ifdef ENABLE_RICE_PARAMETER_SEARCH - } -#endif - if(search_for_escapes) { - partition_bits = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN + raw_bits_per_partition[0] * residual_samples; - if(partition_bits <= best_partition_bits) { - raw_bits[0] = raw_bits_per_partition[0]; - best_rice_parameter = 0; /* will be converted to appropriate escape parameter later */ - best_partition_bits = partition_bits; - } - else - raw_bits[0] = 0; - } - parameters[0] = best_rice_parameter; - bits_ += best_partition_bits; - } - else { - uint32_t partition, residual_sample; - uint32_t partition_samples; - FLAC__uint64 mean, k; - const uint32_t partitions = 1u << partition_order; - for(partition = residual_sample = 0; partition < partitions; partition++) { - partition_samples = (residual_samples+predictor_order) >> partition_order; - if(partition == 0) { - if(partition_samples <= predictor_order) - return false; - else - partition_samples -= predictor_order; - } - mean = abs_residual_partition_sums[partition]; - /* we are basically calculating the size in bits of the - * average residual magnitude in the partition: - * rice_parameter = floor(log2(mean/partition_samples)) - * 'mean' is not a good name for the variable, it is - * actually the sum of magnitudes of all residual values - * in the partition, so the actual mean is - * mean/partition_samples - */ -#if 0 /* old simple code */ - for(rice_parameter = 0, k = partition_samples; k < mean; rice_parameter++, k <<= 1) - ; -#else -#if defined FLAC__CPU_X86_64 /* and other 64-bit arch, too */ - if(mean <= 0x80000000/512) { /* 512: more or less optimal for both 16- and 24-bit input */ -#else - if(mean <= 0x80000000/8) { /* 32-bit arch: use 32-bit math if possible */ -#endif - FLAC__uint32 k2, mean2 = (FLAC__uint32) mean; - rice_parameter = 0; k2 = partition_samples; - while(k2*8 < mean2) { /* requires: mean <= (2^31)/8 */ - rice_parameter += 4; k2 <<= 4; /* tuned for 16-bit input */ - } - while(k2 < mean2) { /* requires: mean <= 2^31 */ - rice_parameter++; k2 <<= 1; - } - } - else { - rice_parameter = 0; k = partition_samples; - if(mean <= FLAC__U64L(0x8000000000000000)/128) /* usually mean is _much_ smaller than this value */ - while(k*128 < mean) { /* requires: mean <= (2^63)/128 */ - rice_parameter += 8; k <<= 8; /* tuned for 24-bit input */ - } - while(k < mean) { /* requires: mean <= 2^63 */ - rice_parameter++; k <<= 1; - } - } -#endif - if(rice_parameter >= rice_parameter_limit) { -#ifndef NDEBUG - fprintf(stderr, "clipping rice_parameter (%u -> %u) @6\n", rice_parameter, rice_parameter_limit - 1); -#endif - rice_parameter = rice_parameter_limit - 1; - } - - best_partition_bits = (uint32_t)(-1); -#ifdef ENABLE_RICE_PARAMETER_SEARCH - if(rice_parameter_search_dist) { - if(rice_parameter < rice_parameter_search_dist) - min_rice_parameter = 0; - else - min_rice_parameter = rice_parameter - rice_parameter_search_dist; - max_rice_parameter = rice_parameter + rice_parameter_search_dist; - if(max_rice_parameter >= rice_parameter_limit) { -#ifndef NDEBUG - fprintf(stderr, "clipping rice_parameter (%u -> %u) @7\n", max_rice_parameter, rice_parameter_limit - 1); -#endif - max_rice_parameter = rice_parameter_limit - 1; - } - } - else - min_rice_parameter = max_rice_parameter = rice_parameter; - - for(rice_parameter = min_rice_parameter; rice_parameter <= max_rice_parameter; rice_parameter++) { -#endif -#ifdef EXACT_RICE_BITS_CALCULATION - partition_bits = count_rice_bits_in_partition_(rice_parameter, partition_samples, residual+residual_sample); -#else - partition_bits = count_rice_bits_in_partition_(rice_parameter, partition_samples, abs_residual_partition_sums[partition]); -#endif - if(partition_bits < best_partition_bits) { - best_rice_parameter = rice_parameter; - best_partition_bits = partition_bits; - } -#ifdef ENABLE_RICE_PARAMETER_SEARCH - } -#endif - if(search_for_escapes) { - partition_bits = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN + raw_bits_per_partition[partition] * partition_samples; - if(partition_bits <= best_partition_bits) { - raw_bits[partition] = raw_bits_per_partition[partition]; - best_rice_parameter = 0; /* will be converted to appropriate escape parameter later */ - best_partition_bits = partition_bits; - } - else - raw_bits[partition] = 0; - } - parameters[partition] = best_rice_parameter; - bits_ += best_partition_bits; - residual_sample += partition_samples; - } - } - - *bits = bits_; - return true; -} - -uint32_t get_wasted_bits_(FLAC__int32 signal[], uint32_t samples) -{ - uint32_t i, shift; - FLAC__int32 x = 0; - - for(i = 0; i < samples && !(x&1); i++) - x |= signal[i]; - - if(x == 0) { - shift = 0; - } - else { - for(shift = 0; !(x&1); shift++) - x >>= 1; - } - - if(shift > 0) { - for(i = 0; i < samples; i++) - signal[i] >>= shift; - } - - return shift; -} - -void append_to_verify_fifo_(verify_input_fifo *fifo, const FLAC__int32 * const input[], uint32_t input_offset, uint32_t channels, uint32_t wide_samples) -{ - uint32_t channel; - - for(channel = 0; channel < channels; channel++) - memcpy(&fifo->data[channel][fifo->tail], &input[channel][input_offset], sizeof(FLAC__int32) * wide_samples); - - fifo->tail += wide_samples; - - FLAC__ASSERT(fifo->tail <= fifo->size); -} - -void append_to_verify_fifo_interleaved_(verify_input_fifo *fifo, const FLAC__int32 input[], uint32_t input_offset, uint32_t channels, uint32_t wide_samples) -{ - uint32_t channel; - uint32_t sample, wide_sample; - uint32_t tail = fifo->tail; - - sample = input_offset * channels; - for(wide_sample = 0; wide_sample < wide_samples; wide_sample++) { - for(channel = 0; channel < channels; channel++) - fifo->data[channel][tail] = input[sample++]; - tail++; - } - fifo->tail = tail; - - FLAC__ASSERT(fifo->tail <= fifo->size); -} - -FLAC__StreamDecoderReadStatus verify_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) -{ - FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder*)client_data; - const size_t encoded_bytes = encoder->private_->verify.output.bytes; - (void)decoder; - - if(encoder->private_->verify.needs_magic_hack) { - FLAC__ASSERT(*bytes >= FLAC__STREAM_SYNC_LENGTH); - *bytes = FLAC__STREAM_SYNC_LENGTH; - memcpy(buffer, FLAC__STREAM_SYNC_STRING, *bytes); - encoder->private_->verify.needs_magic_hack = false; - } - else { - if(encoded_bytes == 0) { - /* - * If we get here, a FIFO underflow has occurred, - * which means there is a bug somewhere. - */ - FLAC__ASSERT(0); - return FLAC__STREAM_DECODER_READ_STATUS_ABORT; - } - else if(encoded_bytes < *bytes) - *bytes = encoded_bytes; - memcpy(buffer, encoder->private_->verify.output.data, *bytes); - encoder->private_->verify.output.data += *bytes; - encoder->private_->verify.output.bytes -= *bytes; - } - - return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; -} - -FLAC__StreamDecoderWriteStatus verify_write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) -{ - FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder *)client_data; - uint32_t channel; - const uint32_t channels = frame->header.channels; - const uint32_t blocksize = frame->header.blocksize; - const uint32_t bytes_per_block = sizeof(FLAC__int32) * blocksize; - - (void)decoder; - - for(channel = 0; channel < channels; channel++) { - if(0 != memcmp(buffer[channel], encoder->private_->verify.input_fifo.data[channel], bytes_per_block)) { - uint32_t i, sample = 0; - FLAC__int32 expect = 0, got = 0; - - for(i = 0; i < blocksize; i++) { - if(buffer[channel][i] != encoder->private_->verify.input_fifo.data[channel][i]) { - sample = i; - expect = (FLAC__int32)encoder->private_->verify.input_fifo.data[channel][i]; - got = (FLAC__int32)buffer[channel][i]; - break; - } - } - FLAC__ASSERT(i < blocksize); - FLAC__ASSERT(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); - encoder->private_->verify.error_stats.absolute_sample = frame->header.number.sample_number + sample; - encoder->private_->verify.error_stats.frame_number = (uint32_t)(frame->header.number.sample_number / blocksize); - encoder->private_->verify.error_stats.channel = channel; - encoder->private_->verify.error_stats.sample = sample; - encoder->private_->verify.error_stats.expected = expect; - encoder->private_->verify.error_stats.got = got; - encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA; - return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; - } - } - /* dequeue the frame from the fifo */ - encoder->private_->verify.input_fifo.tail -= blocksize; - FLAC__ASSERT(encoder->private_->verify.input_fifo.tail <= OVERREAD_); - for(channel = 0; channel < channels; channel++) - memmove(&encoder->private_->verify.input_fifo.data[channel][0], &encoder->private_->verify.input_fifo.data[channel][blocksize], encoder->private_->verify.input_fifo.tail * sizeof(encoder->private_->verify.input_fifo.data[0][0])); - return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; -} - -void verify_metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) -{ - (void)decoder, (void)metadata, (void)client_data; -} - -void verify_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) -{ - FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder*)client_data; - (void)decoder, (void)status; - encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR; -} - -FLAC__StreamEncoderReadStatus file_read_callback_(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data) -{ - (void)client_data; - - *bytes = fread(buffer, 1, *bytes, encoder->private_->file); - if (*bytes == 0) { - if (feof(encoder->private_->file)) - return FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM; - else if (ferror(encoder->private_->file)) - return FLAC__STREAM_ENCODER_READ_STATUS_ABORT; - } - return FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE; -} - -FLAC__StreamEncoderSeekStatus file_seek_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data) -{ - (void)client_data; - - if(fseeko(encoder->private_->file, (FLAC__off_t)absolute_byte_offset, SEEK_SET) < 0) - return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR; - else - return FLAC__STREAM_ENCODER_SEEK_STATUS_OK; -} - -FLAC__StreamEncoderTellStatus file_tell_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data) -{ - FLAC__off_t offset; - - (void)client_data; - - offset = ftello(encoder->private_->file); - - if(offset < 0) { - return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR; - } - else { - *absolute_byte_offset = (FLAC__uint64)offset; - return FLAC__STREAM_ENCODER_TELL_STATUS_OK; - } -} - -#ifdef FLAC__VALGRIND_TESTING -static size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) -{ - size_t ret = fwrite(ptr, size, nmemb, stream); - if(!ferror(stream)) - fflush(stream); - return ret; -} -#else -#define local__fwrite fwrite -#endif - -FLAC__StreamEncoderWriteStatus file_write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, void *client_data) -{ - (void)client_data, (void)current_frame; - - if(local__fwrite(buffer, sizeof(FLAC__byte), bytes, encoder->private_->file) == bytes) { - FLAC__bool call_it = 0 != encoder->private_->progress_callback && ( -#if FLAC__HAS_OGG - /* We would like to be able to use 'samples > 0' in the - * clause here but currently because of the nature of our - * Ogg writing implementation, 'samples' is always 0 (see - * ogg_encoder_aspect.c). The downside is extra progress - * callbacks. - */ - encoder->private_->is_ogg? true : -#endif - samples > 0 - ); - if(call_it) { - /* NOTE: We have to add +bytes, +samples, and +1 to the stats - * because at this point in the callback chain, the stats - * have not been updated. Only after we return and control - * gets back to write_frame_() are the stats updated - */ - encoder->private_->progress_callback(encoder, encoder->private_->bytes_written+bytes, encoder->private_->samples_written+samples, encoder->private_->frames_written+(samples?1:0), encoder->private_->total_frames_estimate, encoder->private_->client_data); - } - return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; - } - else - return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; -} - -/* - * This will forcibly set stdout to binary mode (for OSes that require it) - */ -FILE *get_binary_stdout_(void) -{ - /* if something breaks here it is probably due to the presence or - * absence of an underscore before the identifiers 'setmode', - * 'fileno', and/or 'O_BINARY'; check your system header files. - */ -#if defined _MSC_VER || defined __MINGW32__ - _setmode(_fileno(stdout), _O_BINARY); -#elif defined __EMX__ - setmode(fileno(stdout), O_BINARY); -#endif - - return stdout; -} diff --git a/lib/flac/src/stream_encoder_framing.c b/lib/flac/src/stream_encoder_framing.c deleted file mode 100644 index 2c78916..0000000 --- a/lib/flac/src/stream_encoder_framing.c +++ /dev/null @@ -1,554 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2016 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include /* for strlen() */ -#include "private/stream_encoder_framing.h" -#include "private/crc.h" -#include "FLAC/assert.h" -#include "share/compat.h" - -static FLAC__bool add_entropy_coding_method_(FLAC__BitWriter *bw, const FLAC__EntropyCodingMethod *method); -static FLAC__bool add_residual_partitioned_rice_(FLAC__BitWriter *bw, const FLAC__int32 residual[], const uint32_t residual_samples, const uint32_t predictor_order, const uint32_t rice_parameters[], const uint32_t raw_bits[], const uint32_t partition_order, const FLAC__bool is_extended); - -FLAC__bool FLAC__add_metadata_block(const FLAC__StreamMetadata *metadata, FLAC__BitWriter *bw) -{ - uint32_t i, j; - const uint32_t vendor_string_length = (uint32_t)strlen(FLAC__VENDOR_STRING); - - if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->is_last, FLAC__STREAM_METADATA_IS_LAST_LEN)) - return false; - - if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->type, FLAC__STREAM_METADATA_TYPE_LEN)) - return false; - - /* - * First, for VORBIS_COMMENTs, adjust the length to reflect our vendor string - */ - i = metadata->length; - if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) { - FLAC__ASSERT(metadata->data.vorbis_comment.vendor_string.length == 0 || 0 != metadata->data.vorbis_comment.vendor_string.entry); - i -= metadata->data.vorbis_comment.vendor_string.length; - i += vendor_string_length; - } - FLAC__ASSERT(i < (1u << FLAC__STREAM_METADATA_LENGTH_LEN)); - /* double protection */ - if(i >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) - return false; - if(!FLAC__bitwriter_write_raw_uint32(bw, i, FLAC__STREAM_METADATA_LENGTH_LEN)) - return false; - - switch(metadata->type) { - case FLAC__METADATA_TYPE_STREAMINFO: - FLAC__ASSERT(metadata->data.stream_info.min_blocksize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN)); - if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.min_blocksize, FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN)) - return false; - FLAC__ASSERT(metadata->data.stream_info.max_blocksize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN)); - if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.max_blocksize, FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN)) - return false; - FLAC__ASSERT(metadata->data.stream_info.min_framesize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN)); - if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.min_framesize, FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN)) - return false; - FLAC__ASSERT(metadata->data.stream_info.max_framesize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN)); - if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.max_framesize, FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN)) - return false; - FLAC__ASSERT(FLAC__format_sample_rate_is_valid(metadata->data.stream_info.sample_rate)); - if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.sample_rate, FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN)) - return false; - FLAC__ASSERT(metadata->data.stream_info.channels > 0); - FLAC__ASSERT(metadata->data.stream_info.channels <= (1u << FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN)); - if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.channels-1, FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN)) - return false; - FLAC__ASSERT(metadata->data.stream_info.bits_per_sample > 0); - FLAC__ASSERT(metadata->data.stream_info.bits_per_sample <= (1u << FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN)); - if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.bits_per_sample-1, FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN)) - return false; - FLAC__ASSERT(metadata->data.stream_info.total_samples < (FLAC__U64L(1) << FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN)); - if(!FLAC__bitwriter_write_raw_uint64(bw, metadata->data.stream_info.total_samples, FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN)) - return false; - if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.stream_info.md5sum, 16)) - return false; - break; - case FLAC__METADATA_TYPE_PADDING: - if(!FLAC__bitwriter_write_zeroes(bw, metadata->length * 8)) - return false; - break; - case FLAC__METADATA_TYPE_APPLICATION: - if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8)) - return false; - if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.application.data, metadata->length - (FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8))) - return false; - break; - case FLAC__METADATA_TYPE_SEEKTABLE: - for(i = 0; i < metadata->data.seek_table.num_points; i++) { - if(!FLAC__bitwriter_write_raw_uint64(bw, metadata->data.seek_table.points[i].sample_number, FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN)) - return false; - if(!FLAC__bitwriter_write_raw_uint64(bw, metadata->data.seek_table.points[i].stream_offset, FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN)) - return false; - if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.seek_table.points[i].frame_samples, FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN)) - return false; - } - break; - case FLAC__METADATA_TYPE_VORBIS_COMMENT: - if(!FLAC__bitwriter_write_raw_uint32_little_endian(bw, vendor_string_length)) - return false; - if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)FLAC__VENDOR_STRING, vendor_string_length)) - return false; - if(!FLAC__bitwriter_write_raw_uint32_little_endian(bw, metadata->data.vorbis_comment.num_comments)) - return false; - for(i = 0; i < metadata->data.vorbis_comment.num_comments; i++) { - if(!FLAC__bitwriter_write_raw_uint32_little_endian(bw, metadata->data.vorbis_comment.comments[i].length)) - return false; - if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.vorbis_comment.comments[i].entry, metadata->data.vorbis_comment.comments[i].length)) - return false; - } - break; - case FLAC__METADATA_TYPE_CUESHEET: - FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0); - if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)metadata->data.cue_sheet.media_catalog_number, FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN/8)) - return false; - if(!FLAC__bitwriter_write_raw_uint64(bw, metadata->data.cue_sheet.lead_in, FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN)) - return false; - if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.cue_sheet.is_cd? 1 : 0, FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN)) - return false; - if(!FLAC__bitwriter_write_zeroes(bw, FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN)) - return false; - if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.cue_sheet.num_tracks, FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN)) - return false; - for(i = 0; i < metadata->data.cue_sheet.num_tracks; i++) { - const FLAC__StreamMetadata_CueSheet_Track *track = metadata->data.cue_sheet.tracks + i; - - if(!FLAC__bitwriter_write_raw_uint64(bw, track->offset, FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN)) - return false; - if(!FLAC__bitwriter_write_raw_uint32(bw, track->number, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN)) - return false; - FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0); - if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)track->isrc, FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN/8)) - return false; - if(!FLAC__bitwriter_write_raw_uint32(bw, track->type, FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN)) - return false; - if(!FLAC__bitwriter_write_raw_uint32(bw, track->pre_emphasis, FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN)) - return false; - if(!FLAC__bitwriter_write_zeroes(bw, FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN)) - return false; - if(!FLAC__bitwriter_write_raw_uint32(bw, track->num_indices, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN)) - return false; - for(j = 0; j < track->num_indices; j++) { - const FLAC__StreamMetadata_CueSheet_Index *indx = track->indices + j; - - if(!FLAC__bitwriter_write_raw_uint64(bw, indx->offset, FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN)) - return false; - if(!FLAC__bitwriter_write_raw_uint32(bw, indx->number, FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN)) - return false; - if(!FLAC__bitwriter_write_zeroes(bw, FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN)) - return false; - } - } - break; - case FLAC__METADATA_TYPE_PICTURE: - { - size_t len; - if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.type, FLAC__STREAM_METADATA_PICTURE_TYPE_LEN)) - return false; - len = strlen(metadata->data.picture.mime_type); - if(!FLAC__bitwriter_write_raw_uint32(bw, len, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN)) - return false; - if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)metadata->data.picture.mime_type, len)) - return false; - len = strlen((const char *)metadata->data.picture.description); - if(!FLAC__bitwriter_write_raw_uint32(bw, len, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN)) - return false; - if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.picture.description, len)) - return false; - if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.width, FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN)) - return false; - if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.height, FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN)) - return false; - if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.depth, FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN)) - return false; - if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.colors, FLAC__STREAM_METADATA_PICTURE_COLORS_LEN)) - return false; - if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.data_length, FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN)) - return false; - if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.picture.data, metadata->data.picture.data_length)) - return false; - } - break; - default: - if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.unknown.data, metadata->length)) - return false; - break; - } - - FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(bw)); - return true; -} - -FLAC__bool FLAC__frame_add_header(const FLAC__FrameHeader *header, FLAC__BitWriter *bw) -{ - uint32_t u, blocksize_hint, sample_rate_hint; - FLAC__byte crc; - - FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(bw)); - - if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__FRAME_HEADER_SYNC, FLAC__FRAME_HEADER_SYNC_LEN)) - return false; - - if(!FLAC__bitwriter_write_raw_uint32(bw, 0, FLAC__FRAME_HEADER_RESERVED_LEN)) - return false; - - if(!FLAC__bitwriter_write_raw_uint32(bw, (header->number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER)? 0 : 1, FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN)) - return false; - - FLAC__ASSERT(header->blocksize > 0 && header->blocksize <= FLAC__MAX_BLOCK_SIZE); - /* when this assertion holds true, any legal blocksize can be expressed in the frame header */ - FLAC__ASSERT(FLAC__MAX_BLOCK_SIZE <= 65535u); - blocksize_hint = 0; - switch(header->blocksize) { - case 192: u = 1; break; - case 576: u = 2; break; - case 1152: u = 3; break; - case 2304: u = 4; break; - case 4608: u = 5; break; - case 256: u = 8; break; - case 512: u = 9; break; - case 1024: u = 10; break; - case 2048: u = 11; break; - case 4096: u = 12; break; - case 8192: u = 13; break; - case 16384: u = 14; break; - case 32768: u = 15; break; - default: - if(header->blocksize <= 0x100) - blocksize_hint = u = 6; - else - blocksize_hint = u = 7; - break; - } - if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_BLOCK_SIZE_LEN)) - return false; - - FLAC__ASSERT(FLAC__format_sample_rate_is_valid(header->sample_rate)); - sample_rate_hint = 0; - switch(header->sample_rate) { - case 88200: u = 1; break; - case 176400: u = 2; break; - case 192000: u = 3; break; - case 8000: u = 4; break; - case 16000: u = 5; break; - case 22050: u = 6; break; - case 24000: u = 7; break; - case 32000: u = 8; break; - case 44100: u = 9; break; - case 48000: u = 10; break; - case 96000: u = 11; break; - default: - if(header->sample_rate <= 255000 && header->sample_rate % 1000 == 0) - sample_rate_hint = u = 12; - else if(header->sample_rate % 10 == 0) - sample_rate_hint = u = 14; - else if(header->sample_rate <= 0xffff) - sample_rate_hint = u = 13; - else - u = 0; - break; - } - if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_SAMPLE_RATE_LEN)) - return false; - - FLAC__ASSERT(header->channels > 0 && header->channels <= (1u << FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN) && header->channels <= FLAC__MAX_CHANNELS); - switch(header->channel_assignment) { - case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT: - u = header->channels - 1; - break; - case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE: - FLAC__ASSERT(header->channels == 2); - u = 8; - break; - case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE: - FLAC__ASSERT(header->channels == 2); - u = 9; - break; - case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE: - FLAC__ASSERT(header->channels == 2); - u = 10; - break; - default: - FLAC__ASSERT(0); - } - if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN)) - return false; - - FLAC__ASSERT(header->bits_per_sample > 0 && header->bits_per_sample <= (1u << FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN)); - switch(header->bits_per_sample) { - case 8 : u = 1; break; - case 12: u = 2; break; - case 16: u = 4; break; - case 20: u = 5; break; - case 24: u = 6; break; - default: u = 0; break; - } - if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN)) - return false; - - if(!FLAC__bitwriter_write_raw_uint32(bw, 0, FLAC__FRAME_HEADER_ZERO_PAD_LEN)) - return false; - - if(header->number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER) { - if(!FLAC__bitwriter_write_utf8_uint32(bw, header->number.frame_number)) - return false; - } - else { - if(!FLAC__bitwriter_write_utf8_uint64(bw, header->number.sample_number)) - return false; - } - - if(blocksize_hint) - if(!FLAC__bitwriter_write_raw_uint32(bw, header->blocksize-1, (blocksize_hint==6)? 8:16)) - return false; - - switch(sample_rate_hint) { - case 12: - if(!FLAC__bitwriter_write_raw_uint32(bw, header->sample_rate / 1000, 8)) - return false; - break; - case 13: - if(!FLAC__bitwriter_write_raw_uint32(bw, header->sample_rate, 16)) - return false; - break; - case 14: - if(!FLAC__bitwriter_write_raw_uint32(bw, header->sample_rate / 10, 16)) - return false; - break; - } - - /* write the CRC */ - if(!FLAC__bitwriter_get_write_crc8(bw, &crc)) - return false; - if(!FLAC__bitwriter_write_raw_uint32(bw, crc, FLAC__FRAME_HEADER_CRC_LEN)) - return false; - - return true; -} - -FLAC__bool FLAC__subframe_add_constant(const FLAC__Subframe_Constant *subframe, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw) -{ - FLAC__bool ok; - - ok = - FLAC__bitwriter_write_raw_uint32(bw, FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN) && - (wasted_bits? FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1) : true) && - FLAC__bitwriter_write_raw_int32(bw, subframe->value, subframe_bps) - ; - - return ok; -} - -FLAC__bool FLAC__subframe_add_fixed(const FLAC__Subframe_Fixed *subframe, uint32_t residual_samples, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw) -{ - uint32_t i; - - if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK | (subframe->order<<1) | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN)) - return false; - if(wasted_bits) - if(!FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1)) - return false; - - for(i = 0; i < subframe->order; i++) - if(!FLAC__bitwriter_write_raw_int32(bw, subframe->warmup[i], subframe_bps)) - return false; - - if(!add_entropy_coding_method_(bw, &subframe->entropy_coding_method)) - return false; - switch(subframe->entropy_coding_method.type) { - case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: - case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2: - if(!add_residual_partitioned_rice_( - bw, - subframe->residual, - residual_samples, - subframe->order, - subframe->entropy_coding_method.data.partitioned_rice.contents->parameters, - subframe->entropy_coding_method.data.partitioned_rice.contents->raw_bits, - subframe->entropy_coding_method.data.partitioned_rice.order, - /*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2 - )) - return false; - break; - default: - FLAC__ASSERT(0); - } - - return true; -} - -FLAC__bool FLAC__subframe_add_lpc(const FLAC__Subframe_LPC *subframe, uint32_t residual_samples, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw) -{ - uint32_t i; - - if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK | ((subframe->order-1)<<1) | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN)) - return false; - if(wasted_bits) - if(!FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1)) - return false; - - for(i = 0; i < subframe->order; i++) - if(!FLAC__bitwriter_write_raw_int32(bw, subframe->warmup[i], subframe_bps)) - return false; - - if(!FLAC__bitwriter_write_raw_uint32(bw, subframe->qlp_coeff_precision-1, FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN)) - return false; - if(!FLAC__bitwriter_write_raw_int32(bw, subframe->quantization_level, FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN)) - return false; - for(i = 0; i < subframe->order; i++) - if(!FLAC__bitwriter_write_raw_int32(bw, subframe->qlp_coeff[i], subframe->qlp_coeff_precision)) - return false; - - if(!add_entropy_coding_method_(bw, &subframe->entropy_coding_method)) - return false; - switch(subframe->entropy_coding_method.type) { - case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: - case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2: - if(!add_residual_partitioned_rice_( - bw, - subframe->residual, - residual_samples, - subframe->order, - subframe->entropy_coding_method.data.partitioned_rice.contents->parameters, - subframe->entropy_coding_method.data.partitioned_rice.contents->raw_bits, - subframe->entropy_coding_method.data.partitioned_rice.order, - /*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2 - )) - return false; - break; - default: - FLAC__ASSERT(0); - } - - return true; -} - -FLAC__bool FLAC__subframe_add_verbatim(const FLAC__Subframe_Verbatim *subframe, uint32_t samples, uint32_t subframe_bps, uint32_t wasted_bits, FLAC__BitWriter *bw) -{ - uint32_t i; - const FLAC__int32 *signal = subframe->data; - - if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN)) - return false; - if(wasted_bits) - if(!FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1)) - return false; - - for(i = 0; i < samples; i++) - if(!FLAC__bitwriter_write_raw_int32(bw, signal[i], subframe_bps)) - return false; - - return true; -} - -FLAC__bool add_entropy_coding_method_(FLAC__BitWriter *bw, const FLAC__EntropyCodingMethod *method) -{ - if(!FLAC__bitwriter_write_raw_uint32(bw, method->type, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN)) - return false; - switch(method->type) { - case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: - case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2: - if(!FLAC__bitwriter_write_raw_uint32(bw, method->data.partitioned_rice.order, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN)) - return false; - break; - default: - FLAC__ASSERT(0); - } - return true; -} - -FLAC__bool add_residual_partitioned_rice_(FLAC__BitWriter *bw, const FLAC__int32 residual[], const uint32_t residual_samples, const uint32_t predictor_order, const uint32_t rice_parameters[], const uint32_t raw_bits[], const uint32_t partition_order, const FLAC__bool is_extended) -{ - const uint32_t plen = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; - const uint32_t pesc = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER; - - if(partition_order == 0) { - uint32_t i; - - if(raw_bits[0] == 0) { - if(!FLAC__bitwriter_write_raw_uint32(bw, rice_parameters[0], plen)) - return false; - if(!FLAC__bitwriter_write_rice_signed_block(bw, residual, residual_samples, rice_parameters[0])) - return false; - } - else { - FLAC__ASSERT(rice_parameters[0] == 0); - if(!FLAC__bitwriter_write_raw_uint32(bw, pesc, plen)) - return false; - if(!FLAC__bitwriter_write_raw_uint32(bw, raw_bits[0], FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN)) - return false; - for(i = 0; i < residual_samples; i++) { - if(!FLAC__bitwriter_write_raw_int32(bw, residual[i], raw_bits[0])) - return false; - } - } - return true; - } - else { - uint32_t i, j, k = 0, k_last = 0; - uint32_t partition_samples; - const uint32_t default_partition_samples = (residual_samples+predictor_order) >> partition_order; - for(i = 0; i < (1u< -#endif - -#include -#include "share/compat.h" -#include "FLAC/assert.h" -#include "FLAC/format.h" -#include "private/window.h" - -#ifndef FLAC__INTEGER_ONLY_LIBRARY - - -void FLAC__window_bartlett(FLAC__real *window, const FLAC__int32 L) -{ - const FLAC__int32 N = L - 1; - FLAC__int32 n; - - if (L & 1) { - for (n = 0; n <= N/2; n++) - window[n] = 2.0f * n / (float)N; - for (; n <= N; n++) - window[n] = 2.0f - 2.0f * n / (float)N; - } - else { - for (n = 0; n <= L/2-1; n++) - window[n] = 2.0f * n / (float)N; - for (; n <= N; n++) - window[n] = 2.0f - 2.0f * n / (float)N; - } -} - -void FLAC__window_bartlett_hann(FLAC__real *window, const FLAC__int32 L) -{ - const FLAC__int32 N = L - 1; - FLAC__int32 n; - - for (n = 0; n < L; n++) - window[n] = (FLAC__real)(0.62f - 0.48f * fabs((float)n/(float)N-0.5f) - 0.38f * cos(2.0f * M_PI * ((float)n/(float)N))); -} - -void FLAC__window_blackman(FLAC__real *window, const FLAC__int32 L) -{ - const FLAC__int32 N = L - 1; - FLAC__int32 n; - - for (n = 0; n < L; n++) - window[n] = (FLAC__real)(0.42f - 0.5f * cos(2.0f * M_PI * n / N) + 0.08f * cos(4.0f * M_PI * n / N)); -} - -/* 4-term -92dB side-lobe */ -void FLAC__window_blackman_harris_4term_92db_sidelobe(FLAC__real *window, const FLAC__int32 L) -{ - const FLAC__int32 N = L - 1; - FLAC__int32 n; - - for (n = 0; n <= N; n++) - window[n] = (FLAC__real)(0.35875f - 0.48829f * cos(2.0f * M_PI * n / N) + 0.14128f * cos(4.0f * M_PI * n / N) - 0.01168f * cos(6.0f * M_PI * n / N)); -} - -void FLAC__window_connes(FLAC__real *window, const FLAC__int32 L) -{ - const FLAC__int32 N = L - 1; - const double N2 = (double)N / 2.; - FLAC__int32 n; - - for (n = 0; n <= N; n++) { - double k = ((double)n - N2) / N2; - k = 1.0f - k * k; - window[n] = (FLAC__real)(k * k); - } -} - -void FLAC__window_flattop(FLAC__real *window, const FLAC__int32 L) -{ - const FLAC__int32 N = L - 1; - FLAC__int32 n; - - for (n = 0; n < L; n++) - window[n] = (FLAC__real)(0.21557895f - 0.41663158f * cos(2.0f * M_PI * n / N) + 0.277263158f * cos(4.0f * M_PI * n / N) - 0.083578947f * cos(6.0f * M_PI * n / N) + 0.006947368f * cos(8.0f * M_PI * n / N)); -} - -void FLAC__window_gauss(FLAC__real *window, const FLAC__int32 L, const FLAC__real stddev) -{ - const FLAC__int32 N = L - 1; - const double N2 = (double)N / 2.; - FLAC__int32 n; - - for (n = 0; n <= N; n++) { - const double k = ((double)n - N2) / (stddev * N2); - window[n] = (FLAC__real)exp(-0.5f * k * k); - } -} - -void FLAC__window_hamming(FLAC__real *window, const FLAC__int32 L) -{ - const FLAC__int32 N = L - 1; - FLAC__int32 n; - - for (n = 0; n < L; n++) - window[n] = (FLAC__real)(0.54f - 0.46f * cos(2.0f * M_PI * n / N)); -} - -void FLAC__window_hann(FLAC__real *window, const FLAC__int32 L) -{ - const FLAC__int32 N = L - 1; - FLAC__int32 n; - - for (n = 0; n < L; n++) - window[n] = (FLAC__real)(0.5f - 0.5f * cos(2.0f * M_PI * n / N)); -} - -void FLAC__window_kaiser_bessel(FLAC__real *window, const FLAC__int32 L) -{ - const FLAC__int32 N = L - 1; - FLAC__int32 n; - - for (n = 0; n < L; n++) - window[n] = (FLAC__real)(0.402f - 0.498f * cos(2.0f * M_PI * n / N) + 0.098f * cos(4.0f * M_PI * n / N) - 0.001f * cos(6.0f * M_PI * n / N)); -} - -void FLAC__window_nuttall(FLAC__real *window, const FLAC__int32 L) -{ - const FLAC__int32 N = L - 1; - FLAC__int32 n; - - for (n = 0; n < L; n++) - window[n] = (FLAC__real)(0.3635819f - 0.4891775f*cos(2.0f*M_PI*n/N) + 0.1365995f*cos(4.0f*M_PI*n/N) - 0.0106411f*cos(6.0f*M_PI*n/N)); -} - -void FLAC__window_rectangle(FLAC__real *window, const FLAC__int32 L) -{ - FLAC__int32 n; - - for (n = 0; n < L; n++) - window[n] = 1.0f; -} - -void FLAC__window_triangle(FLAC__real *window, const FLAC__int32 L) -{ - FLAC__int32 n; - - if (L & 1) { - for (n = 1; n <= (L+1)/2; n++) - window[n-1] = 2.0f * n / ((float)L + 1.0f); - for (; n <= L; n++) - window[n-1] = (float)(2 * (L - n + 1)) / ((float)L + 1.0f); - } - else { - for (n = 1; n <= L/2; n++) - window[n-1] = 2.0f * n / ((float)L + 1.0f); - for (; n <= L; n++) - window[n-1] = (float)(2 * (L - n + 1)) / ((float)L + 1.0f); - } -} - -void FLAC__window_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p) -{ - if (p <= 0.0) - FLAC__window_rectangle(window, L); - else if (p >= 1.0) - FLAC__window_hann(window, L); - else { - const FLAC__int32 Np = (FLAC__int32)(p / 2.0f * L) - 1; - FLAC__int32 n; - /* start with rectangle... */ - FLAC__window_rectangle(window, L); - /* ...replace ends with hann */ - if (Np > 0) { - for (n = 0; n <= Np; n++) { - window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * n / Np)); - window[L-Np-1+n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * (n+Np) / Np)); - } - } - } -} - -void FLAC__window_partial_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end) -{ - const FLAC__int32 start_n = (FLAC__int32)(start * L); - const FLAC__int32 end_n = (FLAC__int32)(end * L); - const FLAC__int32 N = end_n - start_n; - FLAC__int32 Np, n, i; - - if (p <= 0.0f) - FLAC__window_partial_tukey(window, L, 0.05f, start, end); - else if (p >= 1.0f) - FLAC__window_partial_tukey(window, L, 0.95f, start, end); - else { - - Np = (FLAC__int32)(p / 2.0f * N); - - for (n = 0; n < start_n && n < L; n++) - window[n] = 0.0f; - for (i = 1; n < (start_n+Np) && n < L; n++, i++) - window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Np)); - for (; n < (end_n-Np) && n < L; n++) - window[n] = 1.0f; - for (i = Np; n < end_n && n < L; n++, i--) - window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Np)); - for (; n < L; n++) - window[n] = 0.0f; - } -} - -void FLAC__window_punchout_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end) -{ - const FLAC__int32 start_n = (FLAC__int32)(start * L); - const FLAC__int32 end_n = (FLAC__int32)(end * L); - FLAC__int32 Ns, Ne, n, i; - - if (p <= 0.0f) - FLAC__window_punchout_tukey(window, L, 0.05f, start, end); - else if (p >= 1.0f) - FLAC__window_punchout_tukey(window, L, 0.95f, start, end); - else { - - Ns = (FLAC__int32)(p / 2.0f * start_n); - Ne = (FLAC__int32)(p / 2.0f * (L - end_n)); - - for (n = 0, i = 1; n < Ns && n < L; n++, i++) - window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Ns)); - for (; n < start_n-Ns && n < L; n++) - window[n] = 1.0f; - for (i = Ns; n < start_n && n < L; n++, i--) - window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Ns)); - for (; n < end_n && n < L; n++) - window[n] = 0.0f; - for (i = 1; n < end_n+Ne && n < L; n++, i++) - window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Ne)); - for (; n < L - (Ne) && n < L; n++) - window[n] = 1.0f; - for (i = Ne; n < L; n++, i--) - window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Ne)); - } -} - -void FLAC__window_welch(FLAC__real *window, const FLAC__int32 L) -{ - const FLAC__int32 N = L - 1; - const double N2 = (double)N / 2.; - FLAC__int32 n; - - for (n = 0; n <= N; n++) { - const double k = ((double)n - N2) / N2; - window[n] = (FLAC__real)(1.0f - k * k); - } -} - -#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ diff --git a/lib/libchdr/include/dr_libs/dr_flac.h b/lib/libchdr/include/dr_libs/dr_flac.h new file mode 100644 index 0000000..14324cf --- /dev/null +++ b/lib/libchdr/include/dr_libs/dr_flac.h @@ -0,0 +1,12536 @@ +/* +FLAC audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file. +dr_flac - v0.12.42 - 2023-11-02 + +David Reid - mackron@gmail.com + +GitHub: https://github.com/mackron/dr_libs +*/ + +/* +RELEASE NOTES - v0.12.0 +======================= +Version 0.12.0 has breaking API changes including changes to the existing API and the removal of deprecated APIs. + + +Improved Client-Defined Memory Allocation +----------------------------------------- +The main change with this release is the addition of a more flexible way of implementing custom memory allocation routines. The +existing system of DRFLAC_MALLOC, DRFLAC_REALLOC and DRFLAC_FREE are still in place and will be used by default when no custom +allocation callbacks are specified. + +To use the new system, you pass in a pointer to a drflac_allocation_callbacks object to drflac_open() and family, like this: + + void* my_malloc(size_t sz, void* pUserData) + { + return malloc(sz); + } + void* my_realloc(void* p, size_t sz, void* pUserData) + { + return realloc(p, sz); + } + void my_free(void* p, void* pUserData) + { + free(p); + } + + ... + + drflac_allocation_callbacks allocationCallbacks; + allocationCallbacks.pUserData = &myData; + allocationCallbacks.onMalloc = my_malloc; + allocationCallbacks.onRealloc = my_realloc; + allocationCallbacks.onFree = my_free; + drflac* pFlac = drflac_open_file("my_file.flac", &allocationCallbacks); + +The advantage of this new system is that it allows you to specify user data which will be passed in to the allocation routines. + +Passing in null for the allocation callbacks object will cause dr_flac to use defaults which is the same as DRFLAC_MALLOC, +DRFLAC_REALLOC and DRFLAC_FREE and the equivalent of how it worked in previous versions. + +Every API that opens a drflac object now takes this extra parameter. These include the following: + + drflac_open() + drflac_open_relaxed() + drflac_open_with_metadata() + drflac_open_with_metadata_relaxed() + drflac_open_file() + drflac_open_file_with_metadata() + drflac_open_memory() + drflac_open_memory_with_metadata() + drflac_open_and_read_pcm_frames_s32() + drflac_open_and_read_pcm_frames_s16() + drflac_open_and_read_pcm_frames_f32() + drflac_open_file_and_read_pcm_frames_s32() + drflac_open_file_and_read_pcm_frames_s16() + drflac_open_file_and_read_pcm_frames_f32() + drflac_open_memory_and_read_pcm_frames_s32() + drflac_open_memory_and_read_pcm_frames_s16() + drflac_open_memory_and_read_pcm_frames_f32() + + + +Optimizations +------------- +Seeking performance has been greatly improved. A new binary search based seeking algorithm has been introduced which significantly +improves performance over the brute force method which was used when no seek table was present. Seek table based seeking also takes +advantage of the new binary search seeking system to further improve performance there as well. Note that this depends on CRC which +means it will be disabled when DR_FLAC_NO_CRC is used. + +The SSE4.1 pipeline has been cleaned up and optimized. You should see some improvements with decoding speed of 24-bit files in +particular. 16-bit streams should also see some improvement. + +drflac_read_pcm_frames_s16() has been optimized. Previously this sat on top of drflac_read_pcm_frames_s32() and performed it's s32 +to s16 conversion in a second pass. This is now all done in a single pass. This includes SSE2 and ARM NEON optimized paths. + +A minor optimization has been implemented for drflac_read_pcm_frames_s32(). This will now use an SSE2 optimized pipeline for stereo +channel reconstruction which is the last part of the decoding process. + +The ARM build has seen a few improvements. The CLZ (count leading zeroes) and REV (byte swap) instructions are now used when +compiling with GCC and Clang which is achieved using inline assembly. The CLZ instruction requires ARM architecture version 5 at +compile time and the REV instruction requires ARM architecture version 6. + +An ARM NEON optimized pipeline has been implemented. To enable this you'll need to add -mfpu=neon to the command line when compiling. + + +Removed APIs +------------ +The following APIs were deprecated in version 0.11.0 and have been completely removed in version 0.12.0: + + drflac_read_s32() -> drflac_read_pcm_frames_s32() + drflac_read_s16() -> drflac_read_pcm_frames_s16() + drflac_read_f32() -> drflac_read_pcm_frames_f32() + drflac_seek_to_sample() -> drflac_seek_to_pcm_frame() + drflac_open_and_decode_s32() -> drflac_open_and_read_pcm_frames_s32() + drflac_open_and_decode_s16() -> drflac_open_and_read_pcm_frames_s16() + drflac_open_and_decode_f32() -> drflac_open_and_read_pcm_frames_f32() + drflac_open_and_decode_file_s32() -> drflac_open_file_and_read_pcm_frames_s32() + drflac_open_and_decode_file_s16() -> drflac_open_file_and_read_pcm_frames_s16() + drflac_open_and_decode_file_f32() -> drflac_open_file_and_read_pcm_frames_f32() + drflac_open_and_decode_memory_s32() -> drflac_open_memory_and_read_pcm_frames_s32() + drflac_open_and_decode_memory_s16() -> drflac_open_memory_and_read_pcm_frames_s16() + drflac_open_and_decode_memory_f32() -> drflac_open_memroy_and_read_pcm_frames_f32() + +Prior versions of dr_flac operated on a per-sample basis whereas now it operates on PCM frames. The removed APIs all relate +to the old per-sample APIs. You now need to use the "pcm_frame" versions. +*/ + + +/* +Introduction +============ +dr_flac is a single file library. To use it, do something like the following in one .c file. + + ```c + #define DR_FLAC_IMPLEMENTATION + #include "dr_flac.h" + ``` + +You can then #include this file in other parts of the program as you would with any other header file. To decode audio data, do something like the following: + + ```c + drflac* pFlac = drflac_open_file("MySong.flac", NULL); + if (pFlac == NULL) { + // Failed to open FLAC file + } + + drflac_int32* pSamples = malloc(pFlac->totalPCMFrameCount * pFlac->channels * sizeof(drflac_int32)); + drflac_uint64 numberOfInterleavedSamplesActuallyRead = drflac_read_pcm_frames_s32(pFlac, pFlac->totalPCMFrameCount, pSamples); + ``` + +The drflac object represents the decoder. It is a transparent type so all the information you need, such as the number of channels and the bits per sample, +should be directly accessible - just make sure you don't change their values. Samples are always output as interleaved signed 32-bit PCM. In the example above +a native FLAC stream was opened, however dr_flac has seamless support for Ogg encapsulated FLAC streams as well. + +You do not need to decode the entire stream in one go - you just specify how many samples you'd like at any given time and the decoder will give you as many +samples as it can, up to the amount requested. Later on when you need the next batch of samples, just call it again. Example: + + ```c + while (drflac_read_pcm_frames_s32(pFlac, chunkSizeInPCMFrames, pChunkSamples) > 0) { + do_something(); + } + ``` + +You can seek to a specific PCM frame with `drflac_seek_to_pcm_frame()`. + +If you just want to quickly decode an entire FLAC file in one go you can do something like this: + + ```c + unsigned int channels; + unsigned int sampleRate; + drflac_uint64 totalPCMFrameCount; + drflac_int32* pSampleData = drflac_open_file_and_read_pcm_frames_s32("MySong.flac", &channels, &sampleRate, &totalPCMFrameCount, NULL); + if (pSampleData == NULL) { + // Failed to open and decode FLAC file. + } + + ... + + drflac_free(pSampleData, NULL); + ``` + +You can read samples as signed 16-bit integer and 32-bit floating-point PCM with the *_s16() and *_f32() family of APIs respectively, but note that these +should be considered lossy. + + +If you need access to metadata (album art, etc.), use `drflac_open_with_metadata()`, `drflac_open_file_with_metdata()` or `drflac_open_memory_with_metadata()`. +The rationale for keeping these APIs separate is that they're slightly slower than the normal versions and also just a little bit harder to use. dr_flac +reports metadata to the application through the use of a callback, and every metadata block is reported before `drflac_open_with_metdata()` returns. + +The main opening APIs (`drflac_open()`, etc.) will fail if the header is not present. The presents a problem in certain scenarios such as broadcast style +streams or internet radio where the header may not be present because the user has started playback mid-stream. To handle this, use the relaxed APIs: + + `drflac_open_relaxed()` + `drflac_open_with_metadata_relaxed()` + +It is not recommended to use these APIs for file based streams because a missing header would usually indicate a corrupt or perverse file. In addition, these +APIs can take a long time to initialize because they may need to spend a lot of time finding the first frame. + + + +Build Options +============= +#define these options before including this file. + +#define DR_FLAC_NO_STDIO + Disable `drflac_open_file()` and family. + +#define DR_FLAC_NO_OGG + Disables support for Ogg/FLAC streams. + +#define DR_FLAC_BUFFER_SIZE + Defines the size of the internal buffer to store data from onRead(). This buffer is used to reduce the number of calls back to the client for more data. + Larger values means more memory, but better performance. My tests show diminishing returns after about 4KB (which is the default). Consider reducing this if + you have a very efficient implementation of onRead(), or increase it if it's very inefficient. Must be a multiple of 8. + +#define DR_FLAC_NO_CRC + Disables CRC checks. This will offer a performance boost when CRC is unnecessary. This will disable binary search seeking. When seeking, the seek table will + be used if available. Otherwise the seek will be performed using brute force. + +#define DR_FLAC_NO_SIMD + Disables SIMD optimizations (SSE on x86/x64 architectures, NEON on ARM architectures). Use this if you are having compatibility issues with your compiler. + +#define DR_FLAC_NO_WCHAR + Disables all functions ending with `_w`. Use this if your compiler does not provide wchar.h. Not required if DR_FLAC_NO_STDIO is also defined. + + + +Notes +===== +- dr_flac does not support changing the sample rate nor channel count mid stream. +- dr_flac is not thread-safe, but its APIs can be called from any thread so long as you do your own synchronization. +- When using Ogg encapsulation, a corrupted metadata block will result in `drflac_open_with_metadata()` and `drflac_open()` returning inconsistent samples due + to differences in corrupted stream recorvery logic between the two APIs. +*/ + +#ifndef dr_flac_h +#define dr_flac_h + +#ifdef __cplusplus +extern "C" { +#endif + +#define DRFLAC_STRINGIFY(x) #x +#define DRFLAC_XSTRINGIFY(x) DRFLAC_STRINGIFY(x) + +#define DRFLAC_VERSION_MAJOR 0 +#define DRFLAC_VERSION_MINOR 12 +#define DRFLAC_VERSION_REVISION 42 +#define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION) + +#include /* For size_t. */ + +/* Sized Types */ +typedef signed char drflac_int8; +typedef unsigned char drflac_uint8; +typedef signed short drflac_int16; +typedef unsigned short drflac_uint16; +typedef signed int drflac_int32; +typedef unsigned int drflac_uint32; +#if defined(_MSC_VER) && !defined(__clang__) + typedef signed __int64 drflac_int64; + typedef unsigned __int64 drflac_uint64; +#else + #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wlong-long" + #if defined(__clang__) + #pragma GCC diagnostic ignored "-Wc++11-long-long" + #endif + #endif + typedef signed long long drflac_int64; + typedef unsigned long long drflac_uint64; + #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #pragma GCC diagnostic pop + #endif +#endif +#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined(_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__) + typedef drflac_uint64 drflac_uintptr; +#else + typedef drflac_uint32 drflac_uintptr; +#endif +typedef drflac_uint8 drflac_bool8; +typedef drflac_uint32 drflac_bool32; +#define DRFLAC_TRUE 1 +#define DRFLAC_FALSE 0 +/* End Sized Types */ + +/* Decorations */ +#if !defined(DRFLAC_API) + #if defined(DRFLAC_DLL) + #if defined(_WIN32) + #define DRFLAC_DLL_IMPORT __declspec(dllimport) + #define DRFLAC_DLL_EXPORT __declspec(dllexport) + #define DRFLAC_DLL_PRIVATE static + #else + #if defined(__GNUC__) && __GNUC__ >= 4 + #define DRFLAC_DLL_IMPORT __attribute__((visibility("default"))) + #define DRFLAC_DLL_EXPORT __attribute__((visibility("default"))) + #define DRFLAC_DLL_PRIVATE __attribute__((visibility("hidden"))) + #else + #define DRFLAC_DLL_IMPORT + #define DRFLAC_DLL_EXPORT + #define DRFLAC_DLL_PRIVATE static + #endif + #endif + + #if defined(DR_FLAC_IMPLEMENTATION) || defined(DRFLAC_IMPLEMENTATION) + #define DRFLAC_API DRFLAC_DLL_EXPORT + #else + #define DRFLAC_API DRFLAC_DLL_IMPORT + #endif + #define DRFLAC_PRIVATE DRFLAC_DLL_PRIVATE + #else + #define DRFLAC_API extern + #define DRFLAC_PRIVATE static + #endif +#endif +/* End Decorations */ + +#if defined(_MSC_VER) && _MSC_VER >= 1700 /* Visual Studio 2012 */ + #define DRFLAC_DEPRECATED __declspec(deprecated) +#elif (defined(__GNUC__) && __GNUC__ >= 4) /* GCC 4 */ + #define DRFLAC_DEPRECATED __attribute__((deprecated)) +#elif defined(__has_feature) /* Clang */ + #if __has_feature(attribute_deprecated) + #define DRFLAC_DEPRECATED __attribute__((deprecated)) + #else + #define DRFLAC_DEPRECATED + #endif +#else + #define DRFLAC_DEPRECATED +#endif + +DRFLAC_API void drflac_version(drflac_uint32* pMajor, drflac_uint32* pMinor, drflac_uint32* pRevision); +DRFLAC_API const char* drflac_version_string(void); + +/* Allocation Callbacks */ +typedef struct +{ + void* pUserData; + void* (* onMalloc)(size_t sz, void* pUserData); + void* (* onRealloc)(void* p, size_t sz, void* pUserData); + void (* onFree)(void* p, void* pUserData); +} drflac_allocation_callbacks; +/* End Allocation Callbacks */ + +/* +As data is read from the client it is placed into an internal buffer for fast access. This controls the size of that buffer. Larger values means more speed, +but also more memory. In my testing there is diminishing returns after about 4KB, but you can fiddle with this to suit your own needs. Must be a multiple of 8. +*/ +#ifndef DR_FLAC_BUFFER_SIZE +#define DR_FLAC_BUFFER_SIZE 4096 +#endif + + +/* Architecture Detection */ +#if defined(_WIN64) || defined(_LP64) || defined(__LP64__) +#define DRFLAC_64BIT +#endif + +#if defined(__x86_64__) || defined(_M_X64) + #define DRFLAC_X64 +#elif defined(__i386) || defined(_M_IX86) + #define DRFLAC_X86 +#elif defined(__arm__) || defined(_M_ARM) || defined(__arm64) || defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64) + #define DRFLAC_ARM +#endif +/* End Architecture Detection */ + + +#ifdef DRFLAC_64BIT +typedef drflac_uint64 drflac_cache_t; +#else +typedef drflac_uint32 drflac_cache_t; +#endif + +/* The various metadata block types. */ +#define DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO 0 +#define DRFLAC_METADATA_BLOCK_TYPE_PADDING 1 +#define DRFLAC_METADATA_BLOCK_TYPE_APPLICATION 2 +#define DRFLAC_METADATA_BLOCK_TYPE_SEEKTABLE 3 +#define DRFLAC_METADATA_BLOCK_TYPE_VORBIS_COMMENT 4 +#define DRFLAC_METADATA_BLOCK_TYPE_CUESHEET 5 +#define DRFLAC_METADATA_BLOCK_TYPE_PICTURE 6 +#define DRFLAC_METADATA_BLOCK_TYPE_INVALID 127 + +/* The various picture types specified in the PICTURE block. */ +#define DRFLAC_PICTURE_TYPE_OTHER 0 +#define DRFLAC_PICTURE_TYPE_FILE_ICON 1 +#define DRFLAC_PICTURE_TYPE_OTHER_FILE_ICON 2 +#define DRFLAC_PICTURE_TYPE_COVER_FRONT 3 +#define DRFLAC_PICTURE_TYPE_COVER_BACK 4 +#define DRFLAC_PICTURE_TYPE_LEAFLET_PAGE 5 +#define DRFLAC_PICTURE_TYPE_MEDIA 6 +#define DRFLAC_PICTURE_TYPE_LEAD_ARTIST 7 +#define DRFLAC_PICTURE_TYPE_ARTIST 8 +#define DRFLAC_PICTURE_TYPE_CONDUCTOR 9 +#define DRFLAC_PICTURE_TYPE_BAND 10 +#define DRFLAC_PICTURE_TYPE_COMPOSER 11 +#define DRFLAC_PICTURE_TYPE_LYRICIST 12 +#define DRFLAC_PICTURE_TYPE_RECORDING_LOCATION 13 +#define DRFLAC_PICTURE_TYPE_DURING_RECORDING 14 +#define DRFLAC_PICTURE_TYPE_DURING_PERFORMANCE 15 +#define DRFLAC_PICTURE_TYPE_SCREEN_CAPTURE 16 +#define DRFLAC_PICTURE_TYPE_BRIGHT_COLORED_FISH 17 +#define DRFLAC_PICTURE_TYPE_ILLUSTRATION 18 +#define DRFLAC_PICTURE_TYPE_BAND_LOGOTYPE 19 +#define DRFLAC_PICTURE_TYPE_PUBLISHER_LOGOTYPE 20 + +typedef enum +{ + drflac_container_native, + drflac_container_ogg, + drflac_container_unknown +} drflac_container; + +typedef enum +{ + drflac_seek_origin_start, + drflac_seek_origin_current +} drflac_seek_origin; + +/* The order of members in this structure is important because we map this directly to the raw data within the SEEKTABLE metadata block. */ +typedef struct +{ + drflac_uint64 firstPCMFrame; + drflac_uint64 flacFrameOffset; /* The offset from the first byte of the header of the first frame. */ + drflac_uint16 pcmFrameCount; +} drflac_seekpoint; + +typedef struct +{ + drflac_uint16 minBlockSizeInPCMFrames; + drflac_uint16 maxBlockSizeInPCMFrames; + drflac_uint32 minFrameSizeInPCMFrames; + drflac_uint32 maxFrameSizeInPCMFrames; + drflac_uint32 sampleRate; + drflac_uint8 channels; + drflac_uint8 bitsPerSample; + drflac_uint64 totalPCMFrameCount; + drflac_uint8 md5[16]; +} drflac_streaminfo; + +typedef struct +{ + /* + The metadata type. Use this to know how to interpret the data below. Will be set to one of the + DRFLAC_METADATA_BLOCK_TYPE_* tokens. + */ + drflac_uint32 type; + + /* + A pointer to the raw data. This points to a temporary buffer so don't hold on to it. It's best to + not modify the contents of this buffer. Use the structures below for more meaningful and structured + information about the metadata. It's possible for this to be null. + */ + const void* pRawData; + + /* The size in bytes of the block and the buffer pointed to by pRawData if it's non-NULL. */ + drflac_uint32 rawDataSize; + + union + { + drflac_streaminfo streaminfo; + + struct + { + int unused; + } padding; + + struct + { + drflac_uint32 id; + const void* pData; + drflac_uint32 dataSize; + } application; + + struct + { + drflac_uint32 seekpointCount; + const drflac_seekpoint* pSeekpoints; + } seektable; + + struct + { + drflac_uint32 vendorLength; + const char* vendor; + drflac_uint32 commentCount; + const void* pComments; + } vorbis_comment; + + struct + { + char catalog[128]; + drflac_uint64 leadInSampleCount; + drflac_bool32 isCD; + drflac_uint8 trackCount; + const void* pTrackData; + } cuesheet; + + struct + { + drflac_uint32 type; + drflac_uint32 mimeLength; + const char* mime; + drflac_uint32 descriptionLength; + const char* description; + drflac_uint32 width; + drflac_uint32 height; + drflac_uint32 colorDepth; + drflac_uint32 indexColorCount; + drflac_uint32 pictureDataSize; + const drflac_uint8* pPictureData; + } picture; + } data; +} drflac_metadata; + + +/* +Callback for when data needs to be read from the client. + + +Parameters +---------- +pUserData (in) + The user data that was passed to drflac_open() and family. + +pBufferOut (out) + The output buffer. + +bytesToRead (in) + The number of bytes to read. + + +Return Value +------------ +The number of bytes actually read. + + +Remarks +------- +A return value of less than bytesToRead indicates the end of the stream. Do _not_ return from this callback until either the entire bytesToRead is filled or +you have reached the end of the stream. +*/ +typedef size_t (* drflac_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); + +/* +Callback for when data needs to be seeked. + + +Parameters +---------- +pUserData (in) + The user data that was passed to drflac_open() and family. + +offset (in) + The number of bytes to move, relative to the origin. Will never be negative. + +origin (in) + The origin of the seek - the current position or the start of the stream. + + +Return Value +------------ +Whether or not the seek was successful. + + +Remarks +------- +The offset will never be negative. Whether or not it is relative to the beginning or current position is determined by the "origin" parameter which will be +either drflac_seek_origin_start or drflac_seek_origin_current. + +When seeking to a PCM frame using drflac_seek_to_pcm_frame(), dr_flac may call this with an offset beyond the end of the FLAC stream. This needs to be detected +and handled by returning DRFLAC_FALSE. +*/ +typedef drflac_bool32 (* drflac_seek_proc)(void* pUserData, int offset, drflac_seek_origin origin); + +/* +Callback for when a metadata block is read. + + +Parameters +---------- +pUserData (in) + The user data that was passed to drflac_open() and family. + +pMetadata (in) + A pointer to a structure containing the data of the metadata block. + + +Remarks +------- +Use pMetadata->type to determine which metadata block is being handled and how to read the data. This +will be set to one of the DRFLAC_METADATA_BLOCK_TYPE_* tokens. +*/ +typedef void (* drflac_meta_proc)(void* pUserData, drflac_metadata* pMetadata); + + +/* Structure for internal use. Only used for decoders opened with drflac_open_memory. */ +typedef struct +{ + const drflac_uint8* data; + size_t dataSize; + size_t currentReadPos; +} drflac__memory_stream; + +/* Structure for internal use. Used for bit streaming. */ +typedef struct +{ + /* The function to call when more data needs to be read. */ + drflac_read_proc onRead; + + /* The function to call when the current read position needs to be moved. */ + drflac_seek_proc onSeek; + + /* The user data to pass around to onRead and onSeek. */ + void* pUserData; + + + /* + The number of unaligned bytes in the L2 cache. This will always be 0 until the end of the stream is hit. At the end of the + stream there will be a number of bytes that don't cleanly fit in an L1 cache line, so we use this variable to know whether + or not the bistreamer needs to run on a slower path to read those last bytes. This will never be more than sizeof(drflac_cache_t). + */ + size_t unalignedByteCount; + + /* The content of the unaligned bytes. */ + drflac_cache_t unalignedCache; + + /* The index of the next valid cache line in the "L2" cache. */ + drflac_uint32 nextL2Line; + + /* The number of bits that have been consumed by the cache. This is used to determine how many valid bits are remaining. */ + drflac_uint32 consumedBits; + + /* + The cached data which was most recently read from the client. There are two levels of cache. Data flows as such: + Client -> L2 -> L1. The L2 -> L1 movement is aligned and runs on a fast path in just a few instructions. + */ + drflac_cache_t cacheL2[DR_FLAC_BUFFER_SIZE/sizeof(drflac_cache_t)]; + drflac_cache_t cache; + + /* + CRC-16. This is updated whenever bits are read from the bit stream. Manually set this to 0 to reset the CRC. For FLAC, this + is reset to 0 at the beginning of each frame. + */ + drflac_uint16 crc16; + drflac_cache_t crc16Cache; /* A cache for optimizing CRC calculations. This is filled when when the L1 cache is reloaded. */ + drflac_uint32 crc16CacheIgnoredBytes; /* The number of bytes to ignore when updating the CRC-16 from the CRC-16 cache. */ +} drflac_bs; + +typedef struct +{ + /* The type of the subframe: SUBFRAME_CONSTANT, SUBFRAME_VERBATIM, SUBFRAME_FIXED or SUBFRAME_LPC. */ + drflac_uint8 subframeType; + + /* The number of wasted bits per sample as specified by the sub-frame header. */ + drflac_uint8 wastedBitsPerSample; + + /* The order to use for the prediction stage for SUBFRAME_FIXED and SUBFRAME_LPC. */ + drflac_uint8 lpcOrder; + + /* A pointer to the buffer containing the decoded samples in the subframe. This pointer is an offset from drflac::pExtraData. */ + drflac_int32* pSamplesS32; +} drflac_subframe; + +typedef struct +{ + /* + If the stream uses variable block sizes, this will be set to the index of the first PCM frame. If fixed block sizes are used, this will + always be set to 0. This is 64-bit because the decoded PCM frame number will be 36 bits. + */ + drflac_uint64 pcmFrameNumber; + + /* + If the stream uses fixed block sizes, this will be set to the frame number. If variable block sizes are used, this will always be 0. This + is 32-bit because in fixed block sizes, the maximum frame number will be 31 bits. + */ + drflac_uint32 flacFrameNumber; + + /* The sample rate of this frame. */ + drflac_uint32 sampleRate; + + /* The number of PCM frames in each sub-frame within this frame. */ + drflac_uint16 blockSizeInPCMFrames; + + /* + The channel assignment of this frame. This is not always set to the channel count. If interchannel decorrelation is being used this + will be set to DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE, DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE or DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE. + */ + drflac_uint8 channelAssignment; + + /* The number of bits per sample within this frame. */ + drflac_uint8 bitsPerSample; + + /* The frame's CRC. */ + drflac_uint8 crc8; +} drflac_frame_header; + +typedef struct +{ + /* The header. */ + drflac_frame_header header; + + /* + The number of PCM frames left to be read in this FLAC frame. This is initially set to the block size. As PCM frames are read, + this will be decremented. When it reaches 0, the decoder will see this frame as fully consumed and load the next frame. + */ + drflac_uint32 pcmFramesRemaining; + + /* The list of sub-frames within the frame. There is one sub-frame for each channel, and there's a maximum of 8 channels. */ + drflac_subframe subframes[8]; +} drflac_frame; + +typedef struct +{ + /* The function to call when a metadata block is read. */ + drflac_meta_proc onMeta; + + /* The user data posted to the metadata callback function. */ + void* pUserDataMD; + + /* Memory allocation callbacks. */ + drflac_allocation_callbacks allocationCallbacks; + + + /* The sample rate. Will be set to something like 44100. */ + drflac_uint32 sampleRate; + + /* + The number of channels. This will be set to 1 for monaural streams, 2 for stereo, etc. Maximum 8. This is set based on the + value specified in the STREAMINFO block. + */ + drflac_uint8 channels; + + /* The bits per sample. Will be set to something like 16, 24, etc. */ + drflac_uint8 bitsPerSample; + + /* The maximum block size, in samples. This number represents the number of samples in each channel (not combined). */ + drflac_uint16 maxBlockSizeInPCMFrames; + + /* + The total number of PCM Frames making up the stream. Can be 0 in which case it's still a valid stream, but just means + the total PCM frame count is unknown. Likely the case with streams like internet radio. + */ + drflac_uint64 totalPCMFrameCount; + + + /* The container type. This is set based on whether or not the decoder was opened from a native or Ogg stream. */ + drflac_container container; + + /* The number of seekpoints in the seektable. */ + drflac_uint32 seekpointCount; + + + /* Information about the frame the decoder is currently sitting on. */ + drflac_frame currentFLACFrame; + + + /* The index of the PCM frame the decoder is currently sitting on. This is only used for seeking. */ + drflac_uint64 currentPCMFrame; + + /* The position of the first FLAC frame in the stream. This is only ever used for seeking. */ + drflac_uint64 firstFLACFramePosInBytes; + + + /* A hack to avoid a malloc() when opening a decoder with drflac_open_memory(). */ + drflac__memory_stream memoryStream; + + + /* A pointer to the decoded sample data. This is an offset of pExtraData. */ + drflac_int32* pDecodedSamples; + + /* A pointer to the seek table. This is an offset of pExtraData, or NULL if there is no seek table. */ + drflac_seekpoint* pSeekpoints; + + /* Internal use only. Only used with Ogg containers. Points to a drflac_oggbs object. This is an offset of pExtraData. */ + void* _oggbs; + + /* Internal use only. Used for profiling and testing different seeking modes. */ + drflac_bool32 _noSeekTableSeek : 1; + drflac_bool32 _noBinarySearchSeek : 1; + drflac_bool32 _noBruteForceSeek : 1; + + /* The bit streamer. The raw FLAC data is fed through this object. */ + drflac_bs bs; + + /* Variable length extra data. We attach this to the end of the object so we can avoid unnecessary mallocs. */ + drflac_uint8 pExtraData[1]; +} drflac; + + +/* +Opens a FLAC decoder. + + +Parameters +---------- +onRead (in) + The function to call when data needs to be read from the client. + +onSeek (in) + The function to call when the read position of the client data needs to move. + +pUserData (in, optional) + A pointer to application defined data that will be passed to onRead and onSeek. + +pAllocationCallbacks (in, optional) + A pointer to application defined callbacks for managing memory allocations. + + +Return Value +------------ +Returns a pointer to an object representing the decoder. + + +Remarks +------- +Close the decoder with `drflac_close()`. + +`pAllocationCallbacks` can be NULL in which case it will use `DRFLAC_MALLOC`, `DRFLAC_REALLOC` and `DRFLAC_FREE`. + +This function will automatically detect whether or not you are attempting to open a native or Ogg encapsulated FLAC, both of which should work seamlessly +without any manual intervention. Ogg encapsulation also works with multiplexed streams which basically means it can play FLAC encoded audio tracks in videos. + +This is the lowest level function for opening a FLAC stream. You can also use `drflac_open_file()` and `drflac_open_memory()` to open the stream from a file or +from a block of memory respectively. + +The STREAMINFO block must be present for this to succeed. Use `drflac_open_relaxed()` to open a FLAC stream where the header may not be present. + +Use `drflac_open_with_metadata()` if you need access to metadata. + + +Seek Also +--------- +drflac_open_file() +drflac_open_memory() +drflac_open_with_metadata() +drflac_close() +*/ +DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks); + +/* +Opens a FLAC stream with relaxed validation of the header block. + + +Parameters +---------- +onRead (in) + The function to call when data needs to be read from the client. + +onSeek (in) + The function to call when the read position of the client data needs to move. + +container (in) + Whether or not the FLAC stream is encapsulated using standard FLAC encapsulation or Ogg encapsulation. + +pUserData (in, optional) + A pointer to application defined data that will be passed to onRead and onSeek. + +pAllocationCallbacks (in, optional) + A pointer to application defined callbacks for managing memory allocations. + + +Return Value +------------ +A pointer to an object representing the decoder. + + +Remarks +------- +The same as drflac_open(), except attempts to open the stream even when a header block is not present. + +Because the header is not necessarily available, the caller must explicitly define the container (Native or Ogg). Do not set this to `drflac_container_unknown` +as that is for internal use only. + +Opening in relaxed mode will continue reading data from onRead until it finds a valid frame. If a frame is never found it will continue forever. To abort, +force your `onRead` callback to return 0, which dr_flac will use as an indicator that the end of the stream was found. + +Use `drflac_open_with_metadata_relaxed()` if you need access to metadata. +*/ +DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks); + +/* +Opens a FLAC decoder and notifies the caller of the metadata chunks (album art, etc.). + + +Parameters +---------- +onRead (in) + The function to call when data needs to be read from the client. + +onSeek (in) + The function to call when the read position of the client data needs to move. + +onMeta (in) + The function to call for every metadata block. + +pUserData (in, optional) + A pointer to application defined data that will be passed to onRead, onSeek and onMeta. + +pAllocationCallbacks (in, optional) + A pointer to application defined callbacks for managing memory allocations. + + +Return Value +------------ +A pointer to an object representing the decoder. + + +Remarks +------- +Close the decoder with `drflac_close()`. + +`pAllocationCallbacks` can be NULL in which case it will use `DRFLAC_MALLOC`, `DRFLAC_REALLOC` and `DRFLAC_FREE`. + +This is slower than `drflac_open()`, so avoid this one if you don't need metadata. Internally, this will allocate and free memory on the heap for every +metadata block except for STREAMINFO and PADDING blocks. + +The caller is notified of the metadata via the `onMeta` callback. All metadata blocks will be handled before the function returns. This callback takes a +pointer to a `drflac_metadata` object which is a union containing the data of all relevant metadata blocks. Use the `type` member to discriminate against +the different metadata types. + +The STREAMINFO block must be present for this to succeed. Use `drflac_open_with_metadata_relaxed()` to open a FLAC stream where the header may not be present. + +Note that this will behave inconsistently with `drflac_open()` if the stream is an Ogg encapsulated stream and a metadata block is corrupted. This is due to +the way the Ogg stream recovers from corrupted pages. When `drflac_open_with_metadata()` is being used, the open routine will try to read the contents of the +metadata block, whereas `drflac_open()` will simply seek past it (for the sake of efficiency). This inconsistency can result in different samples being +returned depending on whether or not the stream is being opened with metadata. + + +Seek Also +--------- +drflac_open_file_with_metadata() +drflac_open_memory_with_metadata() +drflac_open() +drflac_close() +*/ +DRFLAC_API drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks); + +/* +The same as drflac_open_with_metadata(), except attempts to open the stream even when a header block is not present. + +See Also +-------- +drflac_open_with_metadata() +drflac_open_relaxed() +*/ +DRFLAC_API drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks); + +/* +Closes the given FLAC decoder. + + +Parameters +---------- +pFlac (in) + The decoder to close. + + +Remarks +------- +This will destroy the decoder object. + + +See Also +-------- +drflac_open() +drflac_open_with_metadata() +drflac_open_file() +drflac_open_file_w() +drflac_open_file_with_metadata() +drflac_open_file_with_metadata_w() +drflac_open_memory() +drflac_open_memory_with_metadata() +*/ +DRFLAC_API void drflac_close(drflac* pFlac); + + +/* +Reads sample data from the given FLAC decoder, output as interleaved signed 32-bit PCM. + + +Parameters +---------- +pFlac (in) + The decoder. + +framesToRead (in) + The number of PCM frames to read. + +pBufferOut (out, optional) + A pointer to the buffer that will receive the decoded samples. + + +Return Value +------------ +Returns the number of PCM frames actually read. If the return value is less than `framesToRead` it has reached the end. + + +Remarks +------- +pBufferOut can be null, in which case the call will act as a seek, and the return value will be the number of frames seeked. +*/ +DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s32(drflac* pFlac, drflac_uint64 framesToRead, drflac_int32* pBufferOut); + + +/* +Reads sample data from the given FLAC decoder, output as interleaved signed 16-bit PCM. + + +Parameters +---------- +pFlac (in) + The decoder. + +framesToRead (in) + The number of PCM frames to read. + +pBufferOut (out, optional) + A pointer to the buffer that will receive the decoded samples. + + +Return Value +------------ +Returns the number of PCM frames actually read. If the return value is less than `framesToRead` it has reached the end. + + +Remarks +------- +pBufferOut can be null, in which case the call will act as a seek, and the return value will be the number of frames seeked. + +Note that this is lossy for streams where the bits per sample is larger than 16. +*/ +DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s16(drflac* pFlac, drflac_uint64 framesToRead, drflac_int16* pBufferOut); + +/* +Reads sample data from the given FLAC decoder, output as interleaved 32-bit floating point PCM. + + +Parameters +---------- +pFlac (in) + The decoder. + +framesToRead (in) + The number of PCM frames to read. + +pBufferOut (out, optional) + A pointer to the buffer that will receive the decoded samples. + + +Return Value +------------ +Returns the number of PCM frames actually read. If the return value is less than `framesToRead` it has reached the end. + + +Remarks +------- +pBufferOut can be null, in which case the call will act as a seek, and the return value will be the number of frames seeked. + +Note that this should be considered lossy due to the nature of floating point numbers not being able to exactly represent every possible number. +*/ +DRFLAC_API drflac_uint64 drflac_read_pcm_frames_f32(drflac* pFlac, drflac_uint64 framesToRead, float* pBufferOut); + +/* +Seeks to the PCM frame at the given index. + + +Parameters +---------- +pFlac (in) + The decoder. + +pcmFrameIndex (in) + The index of the PCM frame to seek to. See notes below. + + +Return Value +------------- +`DRFLAC_TRUE` if successful; `DRFLAC_FALSE` otherwise. +*/ +DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex); + + + +#ifndef DR_FLAC_NO_STDIO +/* +Opens a FLAC decoder from the file at the given path. + + +Parameters +---------- +pFileName (in) + The path of the file to open, either absolute or relative to the current directory. + +pAllocationCallbacks (in, optional) + A pointer to application defined callbacks for managing memory allocations. + + +Return Value +------------ +A pointer to an object representing the decoder. + + +Remarks +------- +Close the decoder with drflac_close(). + + +Remarks +------- +This will hold a handle to the file until the decoder is closed with drflac_close(). Some platforms will restrict the number of files a process can have open +at any given time, so keep this mind if you have many decoders open at the same time. + + +See Also +-------- +drflac_open_file_with_metadata() +drflac_open() +drflac_close() +*/ +DRFLAC_API drflac* drflac_open_file(const char* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks); +DRFLAC_API drflac* drflac_open_file_w(const wchar_t* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks); + +/* +Opens a FLAC decoder from the file at the given path and notifies the caller of the metadata chunks (album art, etc.) + + +Parameters +---------- +pFileName (in) + The path of the file to open, either absolute or relative to the current directory. + +pAllocationCallbacks (in, optional) + A pointer to application defined callbacks for managing memory allocations. + +onMeta (in) + The callback to fire for each metadata block. + +pUserData (in) + A pointer to the user data to pass to the metadata callback. + +pAllocationCallbacks (in) + A pointer to application defined callbacks for managing memory allocations. + + +Remarks +------- +Look at the documentation for drflac_open_with_metadata() for more information on how metadata is handled. + + +See Also +-------- +drflac_open_with_metadata() +drflac_open() +drflac_close() +*/ +DRFLAC_API drflac* drflac_open_file_with_metadata(const char* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks); +DRFLAC_API drflac* drflac_open_file_with_metadata_w(const wchar_t* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks); +#endif + +/* +Opens a FLAC decoder from a pre-allocated block of memory + + +Parameters +---------- +pData (in) + A pointer to the raw encoded FLAC data. + +dataSize (in) + The size in bytes of `data`. + +pAllocationCallbacks (in) + A pointer to application defined callbacks for managing memory allocations. + + +Return Value +------------ +A pointer to an object representing the decoder. + + +Remarks +------- +This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for the lifetime of the decoder. + + +See Also +-------- +drflac_open() +drflac_close() +*/ +DRFLAC_API drflac* drflac_open_memory(const void* pData, size_t dataSize, const drflac_allocation_callbacks* pAllocationCallbacks); + +/* +Opens a FLAC decoder from a pre-allocated block of memory and notifies the caller of the metadata chunks (album art, etc.) + + +Parameters +---------- +pData (in) + A pointer to the raw encoded FLAC data. + +dataSize (in) + The size in bytes of `data`. + +onMeta (in) + The callback to fire for each metadata block. + +pUserData (in) + A pointer to the user data to pass to the metadata callback. + +pAllocationCallbacks (in) + A pointer to application defined callbacks for managing memory allocations. + + +Remarks +------- +Look at the documentation for drflac_open_with_metadata() for more information on how metadata is handled. + + +See Also +------- +drflac_open_with_metadata() +drflac_open() +drflac_close() +*/ +DRFLAC_API drflac* drflac_open_memory_with_metadata(const void* pData, size_t dataSize, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks); + + + +/* High Level APIs */ + +/* +Opens a FLAC stream from the given callbacks and fully decodes it in a single operation. The return value is a +pointer to the sample data as interleaved signed 32-bit PCM. The returned data must be freed with drflac_free(). + +You can pass in custom memory allocation callbacks via the pAllocationCallbacks parameter. This can be NULL in which +case it will use DRFLAC_MALLOC, DRFLAC_REALLOC and DRFLAC_FREE. + +Sometimes a FLAC file won't keep track of the total sample count. In this situation the function will continuously +read samples into a dynamically sized buffer on the heap until no samples are left. + +Do not call this function on a broadcast type of stream (like internet radio streams and whatnot). +*/ +DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks); + +/* Same as drflac_open_and_read_pcm_frames_s32(), except returns signed 16-bit integer samples. */ +DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks); + +/* Same as drflac_open_and_read_pcm_frames_s32(), except returns 32-bit floating-point samples. */ +DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks); + +#ifndef DR_FLAC_NO_STDIO +/* Same as drflac_open_and_read_pcm_frames_s32() except opens the decoder from a file. */ +DRFLAC_API drflac_int32* drflac_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks); + +/* Same as drflac_open_file_and_read_pcm_frames_s32(), except returns signed 16-bit integer samples. */ +DRFLAC_API drflac_int16* drflac_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks); + +/* Same as drflac_open_file_and_read_pcm_frames_s32(), except returns 32-bit floating-point samples. */ +DRFLAC_API float* drflac_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks); +#endif + +/* Same as drflac_open_and_read_pcm_frames_s32() except opens the decoder from a block of memory. */ +DRFLAC_API drflac_int32* drflac_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks); + +/* Same as drflac_open_memory_and_read_pcm_frames_s32(), except returns signed 16-bit integer samples. */ +DRFLAC_API drflac_int16* drflac_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks); + +/* Same as drflac_open_memory_and_read_pcm_frames_s32(), except returns 32-bit floating-point samples. */ +DRFLAC_API float* drflac_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks); + +/* +Frees memory that was allocated internally by dr_flac. + +Set pAllocationCallbacks to the same object that was passed to drflac_open_*_and_read_pcm_frames_*(). If you originally passed in NULL, pass in NULL for this. +*/ +DRFLAC_API void drflac_free(void* p, const drflac_allocation_callbacks* pAllocationCallbacks); + + +/* Structure representing an iterator for vorbis comments in a VORBIS_COMMENT metadata block. */ +typedef struct +{ + drflac_uint32 countRemaining; + const char* pRunningData; +} drflac_vorbis_comment_iterator; + +/* +Initializes a vorbis comment iterator. This can be used for iterating over the vorbis comments in a VORBIS_COMMENT +metadata block. +*/ +DRFLAC_API void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, drflac_uint32 commentCount, const void* pComments); + +/* +Goes to the next vorbis comment in the given iterator. If null is returned it means there are no more comments. The +returned string is NOT null terminated. +*/ +DRFLAC_API const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, drflac_uint32* pCommentLengthOut); + + +/* Structure representing an iterator for cuesheet tracks in a CUESHEET metadata block. */ +typedef struct +{ + drflac_uint32 countRemaining; + const char* pRunningData; +} drflac_cuesheet_track_iterator; + +/* The order of members here is important because we map this directly to the raw data within the CUESHEET metadata block. */ +typedef struct +{ + drflac_uint64 offset; + drflac_uint8 index; + drflac_uint8 reserved[3]; +} drflac_cuesheet_track_index; + +typedef struct +{ + drflac_uint64 offset; + drflac_uint8 trackNumber; + char ISRC[12]; + drflac_bool8 isAudio; + drflac_bool8 preEmphasis; + drflac_uint8 indexCount; + const drflac_cuesheet_track_index* pIndexPoints; +} drflac_cuesheet_track; + +/* +Initializes a cuesheet track iterator. This can be used for iterating over the cuesheet tracks in a CUESHEET metadata +block. +*/ +DRFLAC_API void drflac_init_cuesheet_track_iterator(drflac_cuesheet_track_iterator* pIter, drflac_uint32 trackCount, const void* pTrackData); + +/* Goes to the next cuesheet track in the given iterator. If DRFLAC_FALSE is returned it means there are no more comments. */ +DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterator* pIter, drflac_cuesheet_track* pCuesheetTrack); + + +#ifdef __cplusplus +} +#endif +#endif /* dr_flac_h */ + + +/************************************************************************************************************************************************************ + ************************************************************************************************************************************************************ + + IMPLEMENTATION + + ************************************************************************************************************************************************************ + ************************************************************************************************************************************************************/ +#if defined(DR_FLAC_IMPLEMENTATION) || defined(DRFLAC_IMPLEMENTATION) +#ifndef dr_flac_c +#define dr_flac_c + +/* Disable some annoying warnings. */ +#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #pragma GCC diagnostic push + #if __GNUC__ >= 7 + #pragma GCC diagnostic ignored "-Wimplicit-fallthrough" + #endif +#endif + +#ifdef __linux__ + #ifndef _BSD_SOURCE + #define _BSD_SOURCE + #endif + #ifndef _DEFAULT_SOURCE + #define _DEFAULT_SOURCE + #endif + #ifndef __USE_BSD + #define __USE_BSD + #endif + #include +#endif + +#include +#include + +/* Inline */ +#ifdef _MSC_VER + #define DRFLAC_INLINE __forceinline +#elif defined(__GNUC__) + /* + I've had a bug report where GCC is emitting warnings about functions possibly not being inlineable. This warning happens when + the __attribute__((always_inline)) attribute is defined without an "inline" statement. I think therefore there must be some + case where "__inline__" is not always defined, thus the compiler emitting these warnings. When using -std=c89 or -ansi on the + command line, we cannot use the "inline" keyword and instead need to use "__inline__". In an attempt to work around this issue + I am using "__inline__" only when we're compiling in strict ANSI mode. + */ + #if defined(__STRICT_ANSI__) + #define DRFLAC_GNUC_INLINE_HINT __inline__ + #else + #define DRFLAC_GNUC_INLINE_HINT inline + #endif + + #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)) || defined(__clang__) + #define DRFLAC_INLINE DRFLAC_GNUC_INLINE_HINT __attribute__((always_inline)) + #else + #define DRFLAC_INLINE DRFLAC_GNUC_INLINE_HINT + #endif +#elif defined(__WATCOMC__) + #define DRFLAC_INLINE __inline +#else + #define DRFLAC_INLINE +#endif +/* End Inline */ + +/* +Intrinsics Support + +There's a bug in GCC 4.2.x which results in an incorrect compilation error when using _mm_slli_epi32() where it complains with + + "error: shift must be an immediate" + +Unfortuantely dr_flac depends on this for a few things so we're just going to disable SSE on GCC 4.2 and below. +*/ +#if !defined(DR_FLAC_NO_SIMD) + #if defined(DRFLAC_X64) || defined(DRFLAC_X86) + #if defined(_MSC_VER) && !defined(__clang__) + /* MSVC. */ + #if _MSC_VER >= 1400 && !defined(DRFLAC_NO_SSE2) /* 2005 */ + #define DRFLAC_SUPPORT_SSE2 + #endif + #if _MSC_VER >= 1600 && !defined(DRFLAC_NO_SSE41) /* 2010 */ + #define DRFLAC_SUPPORT_SSE41 + #endif + #elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) + /* Assume GNUC-style. */ + #if defined(__SSE2__) && !defined(DRFLAC_NO_SSE2) + #define DRFLAC_SUPPORT_SSE2 + #endif + #if defined(__SSE4_1__) && !defined(DRFLAC_NO_SSE41) + #define DRFLAC_SUPPORT_SSE41 + #endif + #endif + + /* If at this point we still haven't determined compiler support for the intrinsics just fall back to __has_include. */ + #if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include) + #if !defined(DRFLAC_SUPPORT_SSE2) && !defined(DRFLAC_NO_SSE2) && __has_include() + #define DRFLAC_SUPPORT_SSE2 + #endif + #if !defined(DRFLAC_SUPPORT_SSE41) && !defined(DRFLAC_NO_SSE41) && __has_include() + #define DRFLAC_SUPPORT_SSE41 + #endif + #endif + + #if defined(DRFLAC_SUPPORT_SSE41) + #include + #elif defined(DRFLAC_SUPPORT_SSE2) + #include + #endif + #endif + + #if defined(DRFLAC_ARM) + #if !defined(DRFLAC_NO_NEON) && (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64)) + #define DRFLAC_SUPPORT_NEON + #include + #endif + #endif +#endif + +/* Compile-time CPU feature support. */ +#if !defined(DR_FLAC_NO_SIMD) && (defined(DRFLAC_X86) || defined(DRFLAC_X64)) + #if defined(_MSC_VER) && !defined(__clang__) + #if _MSC_VER >= 1400 + #include + static void drflac__cpuid(int info[4], int fid) + { + __cpuid(info, fid); + } + #else + #define DRFLAC_NO_CPUID + #endif + #else + #if defined(__GNUC__) || defined(__clang__) + static void drflac__cpuid(int info[4], int fid) + { + /* + It looks like the -fPIC option uses the ebx register which GCC complains about. We can work around this by just using a different register, the + specific register of which I'm letting the compiler decide on. The "k" prefix is used to specify a 32-bit register. The {...} syntax is for + supporting different assembly dialects. + + What's basically happening is that we're saving and restoring the ebx register manually. + */ + #if defined(DRFLAC_X86) && defined(__PIC__) + __asm__ __volatile__ ( + "xchg{l} {%%}ebx, %k1;" + "cpuid;" + "xchg{l} {%%}ebx, %k1;" + : "=a"(info[0]), "=&r"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0) + ); + #else + __asm__ __volatile__ ( + "cpuid" : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0) + ); + #endif + } + #else + #define DRFLAC_NO_CPUID + #endif + #endif +#else + #define DRFLAC_NO_CPUID +#endif + +static DRFLAC_INLINE drflac_bool32 drflac_has_sse2(void) +{ +#if defined(DRFLAC_SUPPORT_SSE2) + #if (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(DRFLAC_NO_SSE2) + #if defined(DRFLAC_X64) + return DRFLAC_TRUE; /* 64-bit targets always support SSE2. */ + #elif (defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE2__) + return DRFLAC_TRUE; /* If the compiler is allowed to freely generate SSE2 code we can assume support. */ + #else + #if defined(DRFLAC_NO_CPUID) + return DRFLAC_FALSE; + #else + int info[4]; + drflac__cpuid(info, 1); + return (info[3] & (1 << 26)) != 0; + #endif + #endif + #else + return DRFLAC_FALSE; /* SSE2 is only supported on x86 and x64 architectures. */ + #endif +#else + return DRFLAC_FALSE; /* No compiler support. */ +#endif +} + +static DRFLAC_INLINE drflac_bool32 drflac_has_sse41(void) +{ +#if defined(DRFLAC_SUPPORT_SSE41) + #if (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(DRFLAC_NO_SSE41) + #if defined(__SSE4_1__) || defined(__AVX__) + return DRFLAC_TRUE; /* If the compiler is allowed to freely generate SSE41 code we can assume support. */ + #else + #if defined(DRFLAC_NO_CPUID) + return DRFLAC_FALSE; + #else + int info[4]; + drflac__cpuid(info, 1); + return (info[2] & (1 << 19)) != 0; + #endif + #endif + #else + return DRFLAC_FALSE; /* SSE41 is only supported on x86 and x64 architectures. */ + #endif +#else + return DRFLAC_FALSE; /* No compiler support. */ +#endif +} + + +#if defined(_MSC_VER) && _MSC_VER >= 1500 && (defined(DRFLAC_X86) || defined(DRFLAC_X64)) && !defined(__clang__) + #define DRFLAC_HAS_LZCNT_INTRINSIC +#elif (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) + #define DRFLAC_HAS_LZCNT_INTRINSIC +#elif defined(__clang__) + #if defined(__has_builtin) + #if __has_builtin(__builtin_clzll) || __has_builtin(__builtin_clzl) + #define DRFLAC_HAS_LZCNT_INTRINSIC + #endif + #endif +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(__clang__) + #define DRFLAC_HAS_BYTESWAP16_INTRINSIC + #define DRFLAC_HAS_BYTESWAP32_INTRINSIC + #define DRFLAC_HAS_BYTESWAP64_INTRINSIC +#elif defined(__clang__) + #if defined(__has_builtin) + #if __has_builtin(__builtin_bswap16) + #define DRFLAC_HAS_BYTESWAP16_INTRINSIC + #endif + #if __has_builtin(__builtin_bswap32) + #define DRFLAC_HAS_BYTESWAP32_INTRINSIC + #endif + #if __has_builtin(__builtin_bswap64) + #define DRFLAC_HAS_BYTESWAP64_INTRINSIC + #endif + #endif +#elif defined(__GNUC__) + #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) + #define DRFLAC_HAS_BYTESWAP32_INTRINSIC + #define DRFLAC_HAS_BYTESWAP64_INTRINSIC + #endif + #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) + #define DRFLAC_HAS_BYTESWAP16_INTRINSIC + #endif +#elif defined(__WATCOMC__) && defined(__386__) + #define DRFLAC_HAS_BYTESWAP16_INTRINSIC + #define DRFLAC_HAS_BYTESWAP32_INTRINSIC + #define DRFLAC_HAS_BYTESWAP64_INTRINSIC + extern __inline drflac_uint16 _watcom_bswap16(drflac_uint16); + extern __inline drflac_uint32 _watcom_bswap32(drflac_uint32); + extern __inline drflac_uint64 _watcom_bswap64(drflac_uint64); +#pragma aux _watcom_bswap16 = \ + "xchg al, ah" \ + parm [ax] \ + value [ax] \ + modify nomemory; +#pragma aux _watcom_bswap32 = \ + "bswap eax" \ + parm [eax] \ + value [eax] \ + modify nomemory; +#pragma aux _watcom_bswap64 = \ + "bswap eax" \ + "bswap edx" \ + "xchg eax,edx" \ + parm [eax edx] \ + value [eax edx] \ + modify nomemory; +#endif + + +/* Standard library stuff. */ +#ifndef DRFLAC_ASSERT +#include +#define DRFLAC_ASSERT(expression) assert(expression) +#endif +#ifndef DRFLAC_MALLOC +#define DRFLAC_MALLOC(sz) malloc((sz)) +#endif +#ifndef DRFLAC_REALLOC +#define DRFLAC_REALLOC(p, sz) realloc((p), (sz)) +#endif +#ifndef DRFLAC_FREE +#define DRFLAC_FREE(p) free((p)) +#endif +#ifndef DRFLAC_COPY_MEMORY +#define DRFLAC_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz)) +#endif +#ifndef DRFLAC_ZERO_MEMORY +#define DRFLAC_ZERO_MEMORY(p, sz) memset((p), 0, (sz)) +#endif +#ifndef DRFLAC_ZERO_OBJECT +#define DRFLAC_ZERO_OBJECT(p) DRFLAC_ZERO_MEMORY((p), sizeof(*(p))) +#endif + +#define DRFLAC_MAX_SIMD_VECTOR_SIZE 64 /* 64 for AVX-512 in the future. */ + +/* Result Codes */ +typedef drflac_int32 drflac_result; +#define DRFLAC_SUCCESS 0 +#define DRFLAC_ERROR -1 /* A generic error. */ +#define DRFLAC_INVALID_ARGS -2 +#define DRFLAC_INVALID_OPERATION -3 +#define DRFLAC_OUT_OF_MEMORY -4 +#define DRFLAC_OUT_OF_RANGE -5 +#define DRFLAC_ACCESS_DENIED -6 +#define DRFLAC_DOES_NOT_EXIST -7 +#define DRFLAC_ALREADY_EXISTS -8 +#define DRFLAC_TOO_MANY_OPEN_FILES -9 +#define DRFLAC_INVALID_FILE -10 +#define DRFLAC_TOO_BIG -11 +#define DRFLAC_PATH_TOO_LONG -12 +#define DRFLAC_NAME_TOO_LONG -13 +#define DRFLAC_NOT_DIRECTORY -14 +#define DRFLAC_IS_DIRECTORY -15 +#define DRFLAC_DIRECTORY_NOT_EMPTY -16 +#define DRFLAC_END_OF_FILE -17 +#define DRFLAC_NO_SPACE -18 +#define DRFLAC_BUSY -19 +#define DRFLAC_IO_ERROR -20 +#define DRFLAC_INTERRUPT -21 +#define DRFLAC_UNAVAILABLE -22 +#define DRFLAC_ALREADY_IN_USE -23 +#define DRFLAC_BAD_ADDRESS -24 +#define DRFLAC_BAD_SEEK -25 +#define DRFLAC_BAD_PIPE -26 +#define DRFLAC_DEADLOCK -27 +#define DRFLAC_TOO_MANY_LINKS -28 +#define DRFLAC_NOT_IMPLEMENTED -29 +#define DRFLAC_NO_MESSAGE -30 +#define DRFLAC_BAD_MESSAGE -31 +#define DRFLAC_NO_DATA_AVAILABLE -32 +#define DRFLAC_INVALID_DATA -33 +#define DRFLAC_TIMEOUT -34 +#define DRFLAC_NO_NETWORK -35 +#define DRFLAC_NOT_UNIQUE -36 +#define DRFLAC_NOT_SOCKET -37 +#define DRFLAC_NO_ADDRESS -38 +#define DRFLAC_BAD_PROTOCOL -39 +#define DRFLAC_PROTOCOL_UNAVAILABLE -40 +#define DRFLAC_PROTOCOL_NOT_SUPPORTED -41 +#define DRFLAC_PROTOCOL_FAMILY_NOT_SUPPORTED -42 +#define DRFLAC_ADDRESS_FAMILY_NOT_SUPPORTED -43 +#define DRFLAC_SOCKET_NOT_SUPPORTED -44 +#define DRFLAC_CONNECTION_RESET -45 +#define DRFLAC_ALREADY_CONNECTED -46 +#define DRFLAC_NOT_CONNECTED -47 +#define DRFLAC_CONNECTION_REFUSED -48 +#define DRFLAC_NO_HOST -49 +#define DRFLAC_IN_PROGRESS -50 +#define DRFLAC_CANCELLED -51 +#define DRFLAC_MEMORY_ALREADY_MAPPED -52 +#define DRFLAC_AT_END -53 + +#define DRFLAC_CRC_MISMATCH -100 +/* End Result Codes */ + + +#define DRFLAC_SUBFRAME_CONSTANT 0 +#define DRFLAC_SUBFRAME_VERBATIM 1 +#define DRFLAC_SUBFRAME_FIXED 8 +#define DRFLAC_SUBFRAME_LPC 32 +#define DRFLAC_SUBFRAME_RESERVED 255 + +#define DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE 0 +#define DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2 1 + +#define DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT 0 +#define DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE 8 +#define DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE 9 +#define DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE 10 + +#define DRFLAC_SEEKPOINT_SIZE_IN_BYTES 18 +#define DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES 36 +#define DRFLAC_CUESHEET_TRACK_INDEX_SIZE_IN_BYTES 12 + +#define drflac_align(x, a) ((((x) + (a) - 1) / (a)) * (a)) + + +DRFLAC_API void drflac_version(drflac_uint32* pMajor, drflac_uint32* pMinor, drflac_uint32* pRevision) +{ + if (pMajor) { + *pMajor = DRFLAC_VERSION_MAJOR; + } + + if (pMinor) { + *pMinor = DRFLAC_VERSION_MINOR; + } + + if (pRevision) { + *pRevision = DRFLAC_VERSION_REVISION; + } +} + +DRFLAC_API const char* drflac_version_string(void) +{ + return DRFLAC_VERSION_STRING; +} + + +/* CPU caps. */ +#if defined(__has_feature) + #if __has_feature(thread_sanitizer) + #define DRFLAC_NO_THREAD_SANITIZE __attribute__((no_sanitize("thread"))) + #else + #define DRFLAC_NO_THREAD_SANITIZE + #endif +#else + #define DRFLAC_NO_THREAD_SANITIZE +#endif + +#if defined(DRFLAC_HAS_LZCNT_INTRINSIC) +static drflac_bool32 drflac__gIsLZCNTSupported = DRFLAC_FALSE; +#endif + +#ifndef DRFLAC_NO_CPUID +static drflac_bool32 drflac__gIsSSE2Supported = DRFLAC_FALSE; +static drflac_bool32 drflac__gIsSSE41Supported = DRFLAC_FALSE; + +/* +I've had a bug report that Clang's ThreadSanitizer presents a warning in this function. Having reviewed this, this does +actually make sense. However, since CPU caps should never differ for a running process, I don't think the trade off of +complicating internal API's by passing around CPU caps versus just disabling the warnings is worthwhile. I'm therefore +just going to disable these warnings. This is disabled via the DRFLAC_NO_THREAD_SANITIZE attribute. +*/ +DRFLAC_NO_THREAD_SANITIZE static void drflac__init_cpu_caps(void) +{ + static drflac_bool32 isCPUCapsInitialized = DRFLAC_FALSE; + + if (!isCPUCapsInitialized) { + /* LZCNT */ +#if defined(DRFLAC_HAS_LZCNT_INTRINSIC) + int info[4] = {0}; + drflac__cpuid(info, 0x80000001); + drflac__gIsLZCNTSupported = (info[2] & (1 << 5)) != 0; +#endif + + /* SSE2 */ + drflac__gIsSSE2Supported = drflac_has_sse2(); + + /* SSE4.1 */ + drflac__gIsSSE41Supported = drflac_has_sse41(); + + /* Initialized. */ + isCPUCapsInitialized = DRFLAC_TRUE; + } +} +#else +static drflac_bool32 drflac__gIsNEONSupported = DRFLAC_FALSE; + +static DRFLAC_INLINE drflac_bool32 drflac__has_neon(void) +{ +#if defined(DRFLAC_SUPPORT_NEON) + #if defined(DRFLAC_ARM) && !defined(DRFLAC_NO_NEON) + #if (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64)) + return DRFLAC_TRUE; /* If the compiler is allowed to freely generate NEON code we can assume support. */ + #else + /* TODO: Runtime check. */ + return DRFLAC_FALSE; + #endif + #else + return DRFLAC_FALSE; /* NEON is only supported on ARM architectures. */ + #endif +#else + return DRFLAC_FALSE; /* No compiler support. */ +#endif +} + +DRFLAC_NO_THREAD_SANITIZE static void drflac__init_cpu_caps(void) +{ + drflac__gIsNEONSupported = drflac__has_neon(); + +#if defined(DRFLAC_HAS_LZCNT_INTRINSIC) && defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) + drflac__gIsLZCNTSupported = DRFLAC_TRUE; +#endif +} +#endif + + +/* Endian Management */ +static DRFLAC_INLINE drflac_bool32 drflac__is_little_endian(void) +{ +#if defined(DRFLAC_X86) || defined(DRFLAC_X64) + return DRFLAC_TRUE; +#elif defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN + return DRFLAC_TRUE; +#else + int n = 1; + return (*(char*)&n) == 1; +#endif +} + +static DRFLAC_INLINE drflac_uint16 drflac__swap_endian_uint16(drflac_uint16 n) +{ +#ifdef DRFLAC_HAS_BYTESWAP16_INTRINSIC + #if defined(_MSC_VER) && !defined(__clang__) + return _byteswap_ushort(n); + #elif defined(__GNUC__) || defined(__clang__) + return __builtin_bswap16(n); + #elif defined(__WATCOMC__) && defined(__386__) + return _watcom_bswap16(n); + #else + #error "This compiler does not support the byte swap intrinsic." + #endif +#else + return ((n & 0xFF00) >> 8) | + ((n & 0x00FF) << 8); +#endif +} + +static DRFLAC_INLINE drflac_uint32 drflac__swap_endian_uint32(drflac_uint32 n) +{ +#ifdef DRFLAC_HAS_BYTESWAP32_INTRINSIC + #if defined(_MSC_VER) && !defined(__clang__) + return _byteswap_ulong(n); + #elif defined(__GNUC__) || defined(__clang__) + #if defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 6) && !defined(__ARM_ARCH_6M__) && !defined(DRFLAC_64BIT) /* <-- 64-bit inline assembly has not been tested, so disabling for now. */ + /* Inline assembly optimized implementation for ARM. In my testing, GCC does not generate optimized code with __builtin_bswap32(). */ + drflac_uint32 r; + __asm__ __volatile__ ( + #if defined(DRFLAC_64BIT) + "rev %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(n) /* <-- This is untested. If someone in the community could test this, that would be appreciated! */ + #else + "rev %[out], %[in]" : [out]"=r"(r) : [in]"r"(n) + #endif + ); + return r; + #else + return __builtin_bswap32(n); + #endif + #elif defined(__WATCOMC__) && defined(__386__) + return _watcom_bswap32(n); + #else + #error "This compiler does not support the byte swap intrinsic." + #endif +#else + return ((n & 0xFF000000) >> 24) | + ((n & 0x00FF0000) >> 8) | + ((n & 0x0000FF00) << 8) | + ((n & 0x000000FF) << 24); +#endif +} + +static DRFLAC_INLINE drflac_uint64 drflac__swap_endian_uint64(drflac_uint64 n) +{ +#ifdef DRFLAC_HAS_BYTESWAP64_INTRINSIC + #if defined(_MSC_VER) && !defined(__clang__) + return _byteswap_uint64(n); + #elif defined(__GNUC__) || defined(__clang__) + return __builtin_bswap64(n); + #elif defined(__WATCOMC__) && defined(__386__) + return _watcom_bswap64(n); + #else + #error "This compiler does not support the byte swap intrinsic." + #endif +#else + /* Weird "<< 32" bitshift is required for C89 because it doesn't support 64-bit constants. Should be optimized out by a good compiler. */ + return ((n & ((drflac_uint64)0xFF000000 << 32)) >> 56) | + ((n & ((drflac_uint64)0x00FF0000 << 32)) >> 40) | + ((n & ((drflac_uint64)0x0000FF00 << 32)) >> 24) | + ((n & ((drflac_uint64)0x000000FF << 32)) >> 8) | + ((n & ((drflac_uint64)0xFF000000 )) << 8) | + ((n & ((drflac_uint64)0x00FF0000 )) << 24) | + ((n & ((drflac_uint64)0x0000FF00 )) << 40) | + ((n & ((drflac_uint64)0x000000FF )) << 56); +#endif +} + + +static DRFLAC_INLINE drflac_uint16 drflac__be2host_16(drflac_uint16 n) +{ + if (drflac__is_little_endian()) { + return drflac__swap_endian_uint16(n); + } + + return n; +} + +static DRFLAC_INLINE drflac_uint32 drflac__be2host_32(drflac_uint32 n) +{ + if (drflac__is_little_endian()) { + return drflac__swap_endian_uint32(n); + } + + return n; +} + +static DRFLAC_INLINE drflac_uint32 drflac__be2host_32_ptr_unaligned(const void* pData) +{ + const drflac_uint8* pNum = (drflac_uint8*)pData; + return *(pNum) << 24 | *(pNum+1) << 16 | *(pNum+2) << 8 | *(pNum+3); +} + +static DRFLAC_INLINE drflac_uint64 drflac__be2host_64(drflac_uint64 n) +{ + if (drflac__is_little_endian()) { + return drflac__swap_endian_uint64(n); + } + + return n; +} + + +static DRFLAC_INLINE drflac_uint32 drflac__le2host_32(drflac_uint32 n) +{ + if (!drflac__is_little_endian()) { + return drflac__swap_endian_uint32(n); + } + + return n; +} + +static DRFLAC_INLINE drflac_uint32 drflac__le2host_32_ptr_unaligned(const void* pData) +{ + const drflac_uint8* pNum = (drflac_uint8*)pData; + return *pNum | *(pNum+1) << 8 | *(pNum+2) << 16 | *(pNum+3) << 24; +} + + +static DRFLAC_INLINE drflac_uint32 drflac__unsynchsafe_32(drflac_uint32 n) +{ + drflac_uint32 result = 0; + result |= (n & 0x7F000000) >> 3; + result |= (n & 0x007F0000) >> 2; + result |= (n & 0x00007F00) >> 1; + result |= (n & 0x0000007F) >> 0; + + return result; +} + + + +/* The CRC code below is based on this document: http://zlib.net/crc_v3.txt */ +static drflac_uint8 drflac__crc8_table[] = { + 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, + 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, + 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, + 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, + 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, + 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, + 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, + 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, + 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, + 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, + 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, + 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, + 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, + 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, + 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, + 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 +}; + +static drflac_uint16 drflac__crc16_table[] = { + 0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011, + 0x8033, 0x0036, 0x003C, 0x8039, 0x0028, 0x802D, 0x8027, 0x0022, + 0x8063, 0x0066, 0x006C, 0x8069, 0x0078, 0x807D, 0x8077, 0x0072, + 0x0050, 0x8055, 0x805F, 0x005A, 0x804B, 0x004E, 0x0044, 0x8041, + 0x80C3, 0x00C6, 0x00CC, 0x80C9, 0x00D8, 0x80DD, 0x80D7, 0x00D2, + 0x00F0, 0x80F5, 0x80FF, 0x00FA, 0x80EB, 0x00EE, 0x00E4, 0x80E1, + 0x00A0, 0x80A5, 0x80AF, 0x00AA, 0x80BB, 0x00BE, 0x00B4, 0x80B1, + 0x8093, 0x0096, 0x009C, 0x8099, 0x0088, 0x808D, 0x8087, 0x0082, + 0x8183, 0x0186, 0x018C, 0x8189, 0x0198, 0x819D, 0x8197, 0x0192, + 0x01B0, 0x81B5, 0x81BF, 0x01BA, 0x81AB, 0x01AE, 0x01A4, 0x81A1, + 0x01E0, 0x81E5, 0x81EF, 0x01EA, 0x81FB, 0x01FE, 0x01F4, 0x81F1, + 0x81D3, 0x01D6, 0x01DC, 0x81D9, 0x01C8, 0x81CD, 0x81C7, 0x01C2, + 0x0140, 0x8145, 0x814F, 0x014A, 0x815B, 0x015E, 0x0154, 0x8151, + 0x8173, 0x0176, 0x017C, 0x8179, 0x0168, 0x816D, 0x8167, 0x0162, + 0x8123, 0x0126, 0x012C, 0x8129, 0x0138, 0x813D, 0x8137, 0x0132, + 0x0110, 0x8115, 0x811F, 0x011A, 0x810B, 0x010E, 0x0104, 0x8101, + 0x8303, 0x0306, 0x030C, 0x8309, 0x0318, 0x831D, 0x8317, 0x0312, + 0x0330, 0x8335, 0x833F, 0x033A, 0x832B, 0x032E, 0x0324, 0x8321, + 0x0360, 0x8365, 0x836F, 0x036A, 0x837B, 0x037E, 0x0374, 0x8371, + 0x8353, 0x0356, 0x035C, 0x8359, 0x0348, 0x834D, 0x8347, 0x0342, + 0x03C0, 0x83C5, 0x83CF, 0x03CA, 0x83DB, 0x03DE, 0x03D4, 0x83D1, + 0x83F3, 0x03F6, 0x03FC, 0x83F9, 0x03E8, 0x83ED, 0x83E7, 0x03E2, + 0x83A3, 0x03A6, 0x03AC, 0x83A9, 0x03B8, 0x83BD, 0x83B7, 0x03B2, + 0x0390, 0x8395, 0x839F, 0x039A, 0x838B, 0x038E, 0x0384, 0x8381, + 0x0280, 0x8285, 0x828F, 0x028A, 0x829B, 0x029E, 0x0294, 0x8291, + 0x82B3, 0x02B6, 0x02BC, 0x82B9, 0x02A8, 0x82AD, 0x82A7, 0x02A2, + 0x82E3, 0x02E6, 0x02EC, 0x82E9, 0x02F8, 0x82FD, 0x82F7, 0x02F2, + 0x02D0, 0x82D5, 0x82DF, 0x02DA, 0x82CB, 0x02CE, 0x02C4, 0x82C1, + 0x8243, 0x0246, 0x024C, 0x8249, 0x0258, 0x825D, 0x8257, 0x0252, + 0x0270, 0x8275, 0x827F, 0x027A, 0x826B, 0x026E, 0x0264, 0x8261, + 0x0220, 0x8225, 0x822F, 0x022A, 0x823B, 0x023E, 0x0234, 0x8231, + 0x8213, 0x0216, 0x021C, 0x8219, 0x0208, 0x820D, 0x8207, 0x0202 +}; + +static DRFLAC_INLINE drflac_uint8 drflac_crc8_byte(drflac_uint8 crc, drflac_uint8 data) +{ + return drflac__crc8_table[crc ^ data]; +} + +static DRFLAC_INLINE drflac_uint8 drflac_crc8(drflac_uint8 crc, drflac_uint32 data, drflac_uint32 count) +{ +#ifdef DR_FLAC_NO_CRC + (void)crc; + (void)data; + (void)count; + return 0; +#else +#if 0 + /* REFERENCE (use of this implementation requires an explicit flush by doing "drflac_crc8(crc, 0, 8);") */ + drflac_uint8 p = 0x07; + for (int i = count-1; i >= 0; --i) { + drflac_uint8 bit = (data & (1 << i)) >> i; + if (crc & 0x80) { + crc = ((crc << 1) | bit) ^ p; + } else { + crc = ((crc << 1) | bit); + } + } + return crc; +#else + drflac_uint32 wholeBytes; + drflac_uint32 leftoverBits; + drflac_uint64 leftoverDataMask; + + static drflac_uint64 leftoverDataMaskTable[8] = { + 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F + }; + + DRFLAC_ASSERT(count <= 32); + + wholeBytes = count >> 3; + leftoverBits = count - (wholeBytes*8); + leftoverDataMask = leftoverDataMaskTable[leftoverBits]; + + switch (wholeBytes) { + case 4: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0xFF000000UL << leftoverBits)) >> (24 + leftoverBits))); + case 3: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0x00FF0000UL << leftoverBits)) >> (16 + leftoverBits))); + case 2: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0x0000FF00UL << leftoverBits)) >> ( 8 + leftoverBits))); + case 1: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0x000000FFUL << leftoverBits)) >> ( 0 + leftoverBits))); + case 0: if (leftoverBits > 0) crc = (drflac_uint8)((crc << leftoverBits) ^ drflac__crc8_table[(crc >> (8 - leftoverBits)) ^ (data & leftoverDataMask)]); + } + return crc; +#endif +#endif +} + +static DRFLAC_INLINE drflac_uint16 drflac_crc16_byte(drflac_uint16 crc, drflac_uint8 data) +{ + return (crc << 8) ^ drflac__crc16_table[(drflac_uint8)(crc >> 8) ^ data]; +} + +static DRFLAC_INLINE drflac_uint16 drflac_crc16_cache(drflac_uint16 crc, drflac_cache_t data) +{ +#ifdef DRFLAC_64BIT + crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 56) & 0xFF)); + crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 48) & 0xFF)); + crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 40) & 0xFF)); + crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 32) & 0xFF)); +#endif + crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 24) & 0xFF)); + crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 16) & 0xFF)); + crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 8) & 0xFF)); + crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 0) & 0xFF)); + + return crc; +} + +static DRFLAC_INLINE drflac_uint16 drflac_crc16_bytes(drflac_uint16 crc, drflac_cache_t data, drflac_uint32 byteCount) +{ + switch (byteCount) + { +#ifdef DRFLAC_64BIT + case 8: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 56) & 0xFF)); + case 7: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 48) & 0xFF)); + case 6: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 40) & 0xFF)); + case 5: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 32) & 0xFF)); +#endif + case 4: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 24) & 0xFF)); + case 3: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 16) & 0xFF)); + case 2: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 8) & 0xFF)); + case 1: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 0) & 0xFF)); + } + + return crc; +} + +#if 0 +static DRFLAC_INLINE drflac_uint16 drflac_crc16__32bit(drflac_uint16 crc, drflac_uint32 data, drflac_uint32 count) +{ +#ifdef DR_FLAC_NO_CRC + (void)crc; + (void)data; + (void)count; + return 0; +#else +#if 0 + /* REFERENCE (use of this implementation requires an explicit flush by doing "drflac_crc16(crc, 0, 16);") */ + drflac_uint16 p = 0x8005; + for (int i = count-1; i >= 0; --i) { + drflac_uint16 bit = (data & (1ULL << i)) >> i; + if (r & 0x8000) { + r = ((r << 1) | bit) ^ p; + } else { + r = ((r << 1) | bit); + } + } + + return crc; +#else + drflac_uint32 wholeBytes; + drflac_uint32 leftoverBits; + drflac_uint64 leftoverDataMask; + + static drflac_uint64 leftoverDataMaskTable[8] = { + 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F + }; + + DRFLAC_ASSERT(count <= 64); + + wholeBytes = count >> 3; + leftoverBits = count & 7; + leftoverDataMask = leftoverDataMaskTable[leftoverBits]; + + switch (wholeBytes) { + default: + case 4: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0xFF000000UL << leftoverBits)) >> (24 + leftoverBits))); + case 3: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0x00FF0000UL << leftoverBits)) >> (16 + leftoverBits))); + case 2: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0x0000FF00UL << leftoverBits)) >> ( 8 + leftoverBits))); + case 1: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0x000000FFUL << leftoverBits)) >> ( 0 + leftoverBits))); + case 0: if (leftoverBits > 0) crc = (crc << leftoverBits) ^ drflac__crc16_table[(crc >> (16 - leftoverBits)) ^ (data & leftoverDataMask)]; + } + return crc; +#endif +#endif +} + +static DRFLAC_INLINE drflac_uint16 drflac_crc16__64bit(drflac_uint16 crc, drflac_uint64 data, drflac_uint32 count) +{ +#ifdef DR_FLAC_NO_CRC + (void)crc; + (void)data; + (void)count; + return 0; +#else + drflac_uint32 wholeBytes; + drflac_uint32 leftoverBits; + drflac_uint64 leftoverDataMask; + + static drflac_uint64 leftoverDataMaskTable[8] = { + 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F + }; + + DRFLAC_ASSERT(count <= 64); + + wholeBytes = count >> 3; + leftoverBits = count & 7; + leftoverDataMask = leftoverDataMaskTable[leftoverBits]; + + switch (wholeBytes) { + default: + case 8: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0xFF000000 << 32) << leftoverBits)) >> (56 + leftoverBits))); /* Weird "<< 32" bitshift is required for C89 because it doesn't support 64-bit constants. Should be optimized out by a good compiler. */ + case 7: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x00FF0000 << 32) << leftoverBits)) >> (48 + leftoverBits))); + case 6: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x0000FF00 << 32) << leftoverBits)) >> (40 + leftoverBits))); + case 5: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x000000FF << 32) << leftoverBits)) >> (32 + leftoverBits))); + case 4: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0xFF000000 ) << leftoverBits)) >> (24 + leftoverBits))); + case 3: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x00FF0000 ) << leftoverBits)) >> (16 + leftoverBits))); + case 2: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x0000FF00 ) << leftoverBits)) >> ( 8 + leftoverBits))); + case 1: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x000000FF ) << leftoverBits)) >> ( 0 + leftoverBits))); + case 0: if (leftoverBits > 0) crc = (crc << leftoverBits) ^ drflac__crc16_table[(crc >> (16 - leftoverBits)) ^ (data & leftoverDataMask)]; + } + return crc; +#endif +} + + +static DRFLAC_INLINE drflac_uint16 drflac_crc16(drflac_uint16 crc, drflac_cache_t data, drflac_uint32 count) +{ +#ifdef DRFLAC_64BIT + return drflac_crc16__64bit(crc, data, count); +#else + return drflac_crc16__32bit(crc, data, count); +#endif +} +#endif + + +#ifdef DRFLAC_64BIT +#define drflac__be2host__cache_line drflac__be2host_64 +#else +#define drflac__be2host__cache_line drflac__be2host_32 +#endif + +/* +BIT READING ATTEMPT #2 + +This uses a 32- or 64-bit bit-shifted cache - as bits are read, the cache is shifted such that the first valid bit is sitting +on the most significant bit. It uses the notion of an L1 and L2 cache (borrowed from CPU architecture), where the L1 cache +is a 32- or 64-bit unsigned integer (depending on whether or not a 32- or 64-bit build is being compiled) and the L2 is an +array of "cache lines", with each cache line being the same size as the L1. The L2 is a buffer of about 4KB and is where data +from onRead() is read into. +*/ +#define DRFLAC_CACHE_L1_SIZE_BYTES(bs) (sizeof((bs)->cache)) +#define DRFLAC_CACHE_L1_SIZE_BITS(bs) (sizeof((bs)->cache)*8) +#define DRFLAC_CACHE_L1_BITS_REMAINING(bs) (DRFLAC_CACHE_L1_SIZE_BITS(bs) - (bs)->consumedBits) +#define DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount) (~((~(drflac_cache_t)0) >> (_bitCount))) +#define DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, _bitCount) (DRFLAC_CACHE_L1_SIZE_BITS(bs) - (_bitCount)) +#define DRFLAC_CACHE_L1_SELECT(bs, _bitCount) (((bs)->cache) & DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount)) +#define DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, _bitCount) (DRFLAC_CACHE_L1_SELECT((bs), (_bitCount)) >> DRFLAC_CACHE_L1_SELECTION_SHIFT((bs), (_bitCount))) +#define DRFLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE(bs, _bitCount)(DRFLAC_CACHE_L1_SELECT((bs), (_bitCount)) >> (DRFLAC_CACHE_L1_SELECTION_SHIFT((bs), (_bitCount)) & (DRFLAC_CACHE_L1_SIZE_BITS(bs)-1))) +#define DRFLAC_CACHE_L2_SIZE_BYTES(bs) (sizeof((bs)->cacheL2)) +#define DRFLAC_CACHE_L2_LINE_COUNT(bs) (DRFLAC_CACHE_L2_SIZE_BYTES(bs) / sizeof((bs)->cacheL2[0])) +#define DRFLAC_CACHE_L2_LINES_REMAINING(bs) (DRFLAC_CACHE_L2_LINE_COUNT(bs) - (bs)->nextL2Line) + + +#ifndef DR_FLAC_NO_CRC +static DRFLAC_INLINE void drflac__reset_crc16(drflac_bs* bs) +{ + bs->crc16 = 0; + bs->crc16CacheIgnoredBytes = bs->consumedBits >> 3; +} + +static DRFLAC_INLINE void drflac__update_crc16(drflac_bs* bs) +{ + if (bs->crc16CacheIgnoredBytes == 0) { + bs->crc16 = drflac_crc16_cache(bs->crc16, bs->crc16Cache); + } else { + bs->crc16 = drflac_crc16_bytes(bs->crc16, bs->crc16Cache, DRFLAC_CACHE_L1_SIZE_BYTES(bs) - bs->crc16CacheIgnoredBytes); + bs->crc16CacheIgnoredBytes = 0; + } +} + +static DRFLAC_INLINE drflac_uint16 drflac__flush_crc16(drflac_bs* bs) +{ + /* We should never be flushing in a situation where we are not aligned on a byte boundary. */ + DRFLAC_ASSERT((DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7) == 0); + + /* + The bits that were read from the L1 cache need to be accumulated. The number of bytes needing to be accumulated is determined + by the number of bits that have been consumed. + */ + if (DRFLAC_CACHE_L1_BITS_REMAINING(bs) == 0) { + drflac__update_crc16(bs); + } else { + /* We only accumulate the consumed bits. */ + bs->crc16 = drflac_crc16_bytes(bs->crc16, bs->crc16Cache >> DRFLAC_CACHE_L1_BITS_REMAINING(bs), (bs->consumedBits >> 3) - bs->crc16CacheIgnoredBytes); + + /* + The bits that we just accumulated should never be accumulated again. We need to keep track of how many bytes were accumulated + so we can handle that later. + */ + bs->crc16CacheIgnoredBytes = bs->consumedBits >> 3; + } + + return bs->crc16; +} +#endif + +static DRFLAC_INLINE drflac_bool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs) +{ + size_t bytesRead; + size_t alignedL1LineCount; + + /* Fast path. Try loading straight from L2. */ + if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { + bs->cache = bs->cacheL2[bs->nextL2Line++]; + return DRFLAC_TRUE; + } + + /* + If we get here it means we've run out of data in the L2 cache. We'll need to fetch more from the client, if there's + any left. + */ + if (bs->unalignedByteCount > 0) { + return DRFLAC_FALSE; /* If we have any unaligned bytes it means there's no more aligned bytes left in the client. */ + } + + bytesRead = bs->onRead(bs->pUserData, bs->cacheL2, DRFLAC_CACHE_L2_SIZE_BYTES(bs)); + + bs->nextL2Line = 0; + if (bytesRead == DRFLAC_CACHE_L2_SIZE_BYTES(bs)) { + bs->cache = bs->cacheL2[bs->nextL2Line++]; + return DRFLAC_TRUE; + } + + + /* + If we get here it means we were unable to retrieve enough data to fill the entire L2 cache. It probably + means we've just reached the end of the file. We need to move the valid data down to the end of the buffer + and adjust the index of the next line accordingly. Also keep in mind that the L2 cache must be aligned to + the size of the L1 so we'll need to seek backwards by any misaligned bytes. + */ + alignedL1LineCount = bytesRead / DRFLAC_CACHE_L1_SIZE_BYTES(bs); + + /* We need to keep track of any unaligned bytes for later use. */ + bs->unalignedByteCount = bytesRead - (alignedL1LineCount * DRFLAC_CACHE_L1_SIZE_BYTES(bs)); + if (bs->unalignedByteCount > 0) { + bs->unalignedCache = bs->cacheL2[alignedL1LineCount]; + } + + if (alignedL1LineCount > 0) { + size_t offset = DRFLAC_CACHE_L2_LINE_COUNT(bs) - alignedL1LineCount; + size_t i; + for (i = alignedL1LineCount; i > 0; --i) { + bs->cacheL2[i-1 + offset] = bs->cacheL2[i-1]; + } + + bs->nextL2Line = (drflac_uint32)offset; + bs->cache = bs->cacheL2[bs->nextL2Line++]; + return DRFLAC_TRUE; + } else { + /* If we get into this branch it means we weren't able to load any L1-aligned data. */ + bs->nextL2Line = DRFLAC_CACHE_L2_LINE_COUNT(bs); + return DRFLAC_FALSE; + } +} + +static drflac_bool32 drflac__reload_cache(drflac_bs* bs) +{ + size_t bytesRead; + +#ifndef DR_FLAC_NO_CRC + drflac__update_crc16(bs); +#endif + + /* Fast path. Try just moving the next value in the L2 cache to the L1 cache. */ + if (drflac__reload_l1_cache_from_l2(bs)) { + bs->cache = drflac__be2host__cache_line(bs->cache); + bs->consumedBits = 0; +#ifndef DR_FLAC_NO_CRC + bs->crc16Cache = bs->cache; +#endif + return DRFLAC_TRUE; + } + + /* Slow path. */ + + /* + If we get here it means we have failed to load the L1 cache from the L2. Likely we've just reached the end of the stream and the last + few bytes did not meet the alignment requirements for the L2 cache. In this case we need to fall back to a slower path and read the + data from the unaligned cache. + */ + bytesRead = bs->unalignedByteCount; + if (bytesRead == 0) { + bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs); /* <-- The stream has been exhausted, so marked the bits as consumed. */ + return DRFLAC_FALSE; + } + + DRFLAC_ASSERT(bytesRead < DRFLAC_CACHE_L1_SIZE_BYTES(bs)); + bs->consumedBits = (drflac_uint32)(DRFLAC_CACHE_L1_SIZE_BYTES(bs) - bytesRead) * 8; + + bs->cache = drflac__be2host__cache_line(bs->unalignedCache); + bs->cache &= DRFLAC_CACHE_L1_SELECTION_MASK(DRFLAC_CACHE_L1_BITS_REMAINING(bs)); /* <-- Make sure the consumed bits are always set to zero. Other parts of the library depend on this property. */ + bs->unalignedByteCount = 0; /* <-- At this point the unaligned bytes have been moved into the cache and we thus have no more unaligned bytes. */ + +#ifndef DR_FLAC_NO_CRC + bs->crc16Cache = bs->cache >> bs->consumedBits; + bs->crc16CacheIgnoredBytes = bs->consumedBits >> 3; +#endif + return DRFLAC_TRUE; +} + +static void drflac__reset_cache(drflac_bs* bs) +{ + bs->nextL2Line = DRFLAC_CACHE_L2_LINE_COUNT(bs); /* <-- This clears the L2 cache. */ + bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs); /* <-- This clears the L1 cache. */ + bs->cache = 0; + bs->unalignedByteCount = 0; /* <-- This clears the trailing unaligned bytes. */ + bs->unalignedCache = 0; + +#ifndef DR_FLAC_NO_CRC + bs->crc16Cache = 0; + bs->crc16CacheIgnoredBytes = 0; +#endif +} + + +static DRFLAC_INLINE drflac_bool32 drflac__read_uint32(drflac_bs* bs, unsigned int bitCount, drflac_uint32* pResultOut) +{ + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pResultOut != NULL); + DRFLAC_ASSERT(bitCount > 0); + DRFLAC_ASSERT(bitCount <= 32); + + if (bs->consumedBits == DRFLAC_CACHE_L1_SIZE_BITS(bs)) { + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; + } + } + + if (bitCount <= DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + /* + If we want to load all 32-bits from a 32-bit cache we need to do it slightly differently because we can't do + a 32-bit shift on a 32-bit integer. This will never be the case on 64-bit caches, so we can have a slightly + more optimal solution for this. + */ +#ifdef DRFLAC_64BIT + *pResultOut = (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCount); + bs->consumedBits += bitCount; + bs->cache <<= bitCount; +#else + if (bitCount < DRFLAC_CACHE_L1_SIZE_BITS(bs)) { + *pResultOut = (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCount); + bs->consumedBits += bitCount; + bs->cache <<= bitCount; + } else { + /* Cannot shift by 32-bits, so need to do it differently. */ + *pResultOut = (drflac_uint32)bs->cache; + bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs); + bs->cache = 0; + } +#endif + + return DRFLAC_TRUE; + } else { + /* It straddles the cached data. It will never cover more than the next chunk. We just read the number in two parts and combine them. */ + drflac_uint32 bitCountHi = DRFLAC_CACHE_L1_BITS_REMAINING(bs); + drflac_uint32 bitCountLo = bitCount - bitCountHi; + drflac_uint32 resultHi; + + DRFLAC_ASSERT(bitCountHi > 0); + DRFLAC_ASSERT(bitCountHi < 32); + resultHi = (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountHi); + + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; + } + if (bitCountLo > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + /* This happens when we get to end of stream */ + return DRFLAC_FALSE; + } + + *pResultOut = (resultHi << bitCountLo) | (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountLo); + bs->consumedBits += bitCountLo; + bs->cache <<= bitCountLo; + return DRFLAC_TRUE; + } +} + +static drflac_bool32 drflac__read_int32(drflac_bs* bs, unsigned int bitCount, drflac_int32* pResult) +{ + drflac_uint32 result; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pResult != NULL); + DRFLAC_ASSERT(bitCount > 0); + DRFLAC_ASSERT(bitCount <= 32); + + if (!drflac__read_uint32(bs, bitCount, &result)) { + return DRFLAC_FALSE; + } + + /* Do not attempt to shift by 32 as it's undefined. */ + if (bitCount < 32) { + drflac_uint32 signbit; + signbit = ((result >> (bitCount-1)) & 0x01); + result |= (~signbit + 1) << bitCount; + } + + *pResult = (drflac_int32)result; + return DRFLAC_TRUE; +} + +#ifdef DRFLAC_64BIT +static drflac_bool32 drflac__read_uint64(drflac_bs* bs, unsigned int bitCount, drflac_uint64* pResultOut) +{ + drflac_uint32 resultHi; + drflac_uint32 resultLo; + + DRFLAC_ASSERT(bitCount <= 64); + DRFLAC_ASSERT(bitCount > 32); + + if (!drflac__read_uint32(bs, bitCount - 32, &resultHi)) { + return DRFLAC_FALSE; + } + + if (!drflac__read_uint32(bs, 32, &resultLo)) { + return DRFLAC_FALSE; + } + + *pResultOut = (((drflac_uint64)resultHi) << 32) | ((drflac_uint64)resultLo); + return DRFLAC_TRUE; +} +#endif + +/* Function below is unused, but leaving it here in case I need to quickly add it again. */ +#if 0 +static drflac_bool32 drflac__read_int64(drflac_bs* bs, unsigned int bitCount, drflac_int64* pResultOut) +{ + drflac_uint64 result; + drflac_uint64 signbit; + + DRFLAC_ASSERT(bitCount <= 64); + + if (!drflac__read_uint64(bs, bitCount, &result)) { + return DRFLAC_FALSE; + } + + signbit = ((result >> (bitCount-1)) & 0x01); + result |= (~signbit + 1) << bitCount; + + *pResultOut = (drflac_int64)result; + return DRFLAC_TRUE; +} +#endif + +static drflac_bool32 drflac__read_uint16(drflac_bs* bs, unsigned int bitCount, drflac_uint16* pResult) +{ + drflac_uint32 result; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pResult != NULL); + DRFLAC_ASSERT(bitCount > 0); + DRFLAC_ASSERT(bitCount <= 16); + + if (!drflac__read_uint32(bs, bitCount, &result)) { + return DRFLAC_FALSE; + } + + *pResult = (drflac_uint16)result; + return DRFLAC_TRUE; +} + +#if 0 +static drflac_bool32 drflac__read_int16(drflac_bs* bs, unsigned int bitCount, drflac_int16* pResult) +{ + drflac_int32 result; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pResult != NULL); + DRFLAC_ASSERT(bitCount > 0); + DRFLAC_ASSERT(bitCount <= 16); + + if (!drflac__read_int32(bs, bitCount, &result)) { + return DRFLAC_FALSE; + } + + *pResult = (drflac_int16)result; + return DRFLAC_TRUE; +} +#endif + +static drflac_bool32 drflac__read_uint8(drflac_bs* bs, unsigned int bitCount, drflac_uint8* pResult) +{ + drflac_uint32 result; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pResult != NULL); + DRFLAC_ASSERT(bitCount > 0); + DRFLAC_ASSERT(bitCount <= 8); + + if (!drflac__read_uint32(bs, bitCount, &result)) { + return DRFLAC_FALSE; + } + + *pResult = (drflac_uint8)result; + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__read_int8(drflac_bs* bs, unsigned int bitCount, drflac_int8* pResult) +{ + drflac_int32 result; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pResult != NULL); + DRFLAC_ASSERT(bitCount > 0); + DRFLAC_ASSERT(bitCount <= 8); + + if (!drflac__read_int32(bs, bitCount, &result)) { + return DRFLAC_FALSE; + } + + *pResult = (drflac_int8)result; + return DRFLAC_TRUE; +} + + +static drflac_bool32 drflac__seek_bits(drflac_bs* bs, size_t bitsToSeek) +{ + if (bitsToSeek <= DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + bs->consumedBits += (drflac_uint32)bitsToSeek; + bs->cache <<= bitsToSeek; + return DRFLAC_TRUE; + } else { + /* It straddles the cached data. This function isn't called too frequently so I'm favouring simplicity here. */ + bitsToSeek -= DRFLAC_CACHE_L1_BITS_REMAINING(bs); + bs->consumedBits += DRFLAC_CACHE_L1_BITS_REMAINING(bs); + bs->cache = 0; + + /* Simple case. Seek in groups of the same number as bits that fit within a cache line. */ +#ifdef DRFLAC_64BIT + while (bitsToSeek >= DRFLAC_CACHE_L1_SIZE_BITS(bs)) { + drflac_uint64 bin; + if (!drflac__read_uint64(bs, DRFLAC_CACHE_L1_SIZE_BITS(bs), &bin)) { + return DRFLAC_FALSE; + } + bitsToSeek -= DRFLAC_CACHE_L1_SIZE_BITS(bs); + } +#else + while (bitsToSeek >= DRFLAC_CACHE_L1_SIZE_BITS(bs)) { + drflac_uint32 bin; + if (!drflac__read_uint32(bs, DRFLAC_CACHE_L1_SIZE_BITS(bs), &bin)) { + return DRFLAC_FALSE; + } + bitsToSeek -= DRFLAC_CACHE_L1_SIZE_BITS(bs); + } +#endif + + /* Whole leftover bytes. */ + while (bitsToSeek >= 8) { + drflac_uint8 bin; + if (!drflac__read_uint8(bs, 8, &bin)) { + return DRFLAC_FALSE; + } + bitsToSeek -= 8; + } + + /* Leftover bits. */ + if (bitsToSeek > 0) { + drflac_uint8 bin; + if (!drflac__read_uint8(bs, (drflac_uint32)bitsToSeek, &bin)) { + return DRFLAC_FALSE; + } + bitsToSeek = 0; /* <-- Necessary for the assert below. */ + } + + DRFLAC_ASSERT(bitsToSeek == 0); + return DRFLAC_TRUE; + } +} + + +/* This function moves the bit streamer to the first bit after the sync code (bit 15 of the of the frame header). It will also update the CRC-16. */ +static drflac_bool32 drflac__find_and_seek_to_next_sync_code(drflac_bs* bs) +{ + DRFLAC_ASSERT(bs != NULL); + + /* + The sync code is always aligned to 8 bits. This is convenient for us because it means we can do byte-aligned movements. The first + thing to do is align to the next byte. + */ + if (!drflac__seek_bits(bs, DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7)) { + return DRFLAC_FALSE; + } + + for (;;) { + drflac_uint8 hi; + +#ifndef DR_FLAC_NO_CRC + drflac__reset_crc16(bs); +#endif + + if (!drflac__read_uint8(bs, 8, &hi)) { + return DRFLAC_FALSE; + } + + if (hi == 0xFF) { + drflac_uint8 lo; + if (!drflac__read_uint8(bs, 6, &lo)) { + return DRFLAC_FALSE; + } + + if (lo == 0x3E) { + return DRFLAC_TRUE; + } else { + if (!drflac__seek_bits(bs, DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7)) { + return DRFLAC_FALSE; + } + } + } + } + + /* Should never get here. */ + /*return DRFLAC_FALSE;*/ +} + + +#if defined(DRFLAC_HAS_LZCNT_INTRINSIC) +#define DRFLAC_IMPLEMENT_CLZ_LZCNT +#endif +#if defined(_MSC_VER) && _MSC_VER >= 1400 && (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(__clang__) +#define DRFLAC_IMPLEMENT_CLZ_MSVC +#endif +#if defined(__WATCOMC__) && defined(__386__) +#define DRFLAC_IMPLEMENT_CLZ_WATCOM +#endif +#ifdef __MRC__ +#include +#define DRFLAC_IMPLEMENT_CLZ_MRC +#endif + +static DRFLAC_INLINE drflac_uint32 drflac__clz_software(drflac_cache_t x) +{ + drflac_uint32 n; + static drflac_uint32 clz_table_4[] = { + 0, + 4, + 3, 3, + 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1 + }; + + if (x == 0) { + return sizeof(x)*8; + } + + n = clz_table_4[x >> (sizeof(x)*8 - 4)]; + if (n == 0) { +#ifdef DRFLAC_64BIT + if ((x & ((drflac_uint64)0xFFFFFFFF << 32)) == 0) { n = 32; x <<= 32; } + if ((x & ((drflac_uint64)0xFFFF0000 << 32)) == 0) { n += 16; x <<= 16; } + if ((x & ((drflac_uint64)0xFF000000 << 32)) == 0) { n += 8; x <<= 8; } + if ((x & ((drflac_uint64)0xF0000000 << 32)) == 0) { n += 4; x <<= 4; } +#else + if ((x & 0xFFFF0000) == 0) { n = 16; x <<= 16; } + if ((x & 0xFF000000) == 0) { n += 8; x <<= 8; } + if ((x & 0xF0000000) == 0) { n += 4; x <<= 4; } +#endif + n += clz_table_4[x >> (sizeof(x)*8 - 4)]; + } + + return n - 1; +} + +#ifdef DRFLAC_IMPLEMENT_CLZ_LZCNT +static DRFLAC_INLINE drflac_bool32 drflac__is_lzcnt_supported(void) +{ + /* Fast compile time check for ARM. */ +#if defined(DRFLAC_HAS_LZCNT_INTRINSIC) && defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) + return DRFLAC_TRUE; +#elif defined(__MRC__) + return DRFLAC_TRUE; +#else + /* If the compiler itself does not support the intrinsic then we'll need to return false. */ + #ifdef DRFLAC_HAS_LZCNT_INTRINSIC + return drflac__gIsLZCNTSupported; + #else + return DRFLAC_FALSE; + #endif +#endif +} + +static DRFLAC_INLINE drflac_uint32 drflac__clz_lzcnt(drflac_cache_t x) +{ + /* + It's critical for competitive decoding performance that this function be highly optimal. With MSVC we can use the __lzcnt64() and __lzcnt() intrinsics + to achieve good performance, however on GCC and Clang it's a little bit more annoying. The __builtin_clzl() and __builtin_clzll() intrinsics leave + it undefined as to the return value when `x` is 0. We need this to be well defined as returning 32 or 64, depending on whether or not it's a 32- or + 64-bit build. To work around this we would need to add a conditional to check for the x = 0 case, but this creates unnecessary inefficiency. To work + around this problem I have written some inline assembly to emit the LZCNT (x86) or CLZ (ARM) instruction directly which removes the need to include + the conditional. This has worked well in the past, but for some reason Clang's MSVC compatible driver, clang-cl, does not seem to be handling this + in the same way as the normal Clang driver. It seems that `clang-cl` is just outputting the wrong results sometimes, maybe due to some register + getting clobbered? + + I'm not sure if this is a bug with dr_flac's inlined assembly (most likely), a bug in `clang-cl` or just a misunderstanding on my part with inline + assembly rules for `clang-cl`. If somebody can identify an error in dr_flac's inlined assembly I'm happy to get that fixed. + + Fortunately there is an easy workaround for this. Clang implements MSVC-specific intrinsics for compatibility. It also defines _MSC_VER for extra + compatibility. We can therefore just check for _MSC_VER and use the MSVC intrinsic which, fortunately for us, Clang supports. It would still be nice + to know how to fix the inlined assembly for correctness sake, however. + */ + +#if defined(_MSC_VER) /*&& !defined(__clang__)*/ /* <-- Intentionally wanting Clang to use the MSVC __lzcnt64/__lzcnt intrinsics due to above ^. */ + #ifdef DRFLAC_64BIT + return (drflac_uint32)__lzcnt64(x); + #else + return (drflac_uint32)__lzcnt(x); + #endif +#else + #if defined(__GNUC__) || defined(__clang__) + #if defined(DRFLAC_X64) + { + drflac_uint64 r; + __asm__ __volatile__ ( + "lzcnt{ %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc" + ); + + return (drflac_uint32)r; + } + #elif defined(DRFLAC_X86) + { + drflac_uint32 r; + __asm__ __volatile__ ( + "lzcnt{l %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc" + ); + + return r; + } + #elif defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) && !defined(__ARM_ARCH_6M__) && !defined(DRFLAC_64BIT) /* <-- I haven't tested 64-bit inline assembly, so only enabling this for the 32-bit build for now. */ + { + unsigned int r; + __asm__ __volatile__ ( + #if defined(DRFLAC_64BIT) + "clz %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(x) /* <-- This is untested. If someone in the community could test this, that would be appreciated! */ + #else + "clz %[out], %[in]" : [out]"=r"(r) : [in]"r"(x) + #endif + ); + + return r; + } + #else + if (x == 0) { + return sizeof(x)*8; + } + #ifdef DRFLAC_64BIT + return (drflac_uint32)__builtin_clzll((drflac_uint64)x); + #else + return (drflac_uint32)__builtin_clzl((drflac_uint32)x); + #endif + #endif + #else + /* Unsupported compiler. */ + #error "This compiler does not support the lzcnt intrinsic." + #endif +#endif +} +#endif + +#ifdef DRFLAC_IMPLEMENT_CLZ_MSVC +#include /* For BitScanReverse(). */ + +static DRFLAC_INLINE drflac_uint32 drflac__clz_msvc(drflac_cache_t x) +{ + drflac_uint32 n; + + if (x == 0) { + return sizeof(x)*8; + } + +#ifdef DRFLAC_64BIT + _BitScanReverse64((unsigned long*)&n, x); +#else + _BitScanReverse((unsigned long*)&n, x); +#endif + return sizeof(x)*8 - n - 1; +} +#endif + +#ifdef DRFLAC_IMPLEMENT_CLZ_WATCOM +static __inline drflac_uint32 drflac__clz_watcom (drflac_uint32); +#ifdef DRFLAC_IMPLEMENT_CLZ_WATCOM_LZCNT +/* Use the LZCNT instruction (only available on some processors since the 2010s). */ +#pragma aux drflac__clz_watcom_lzcnt = \ + "db 0F3h, 0Fh, 0BDh, 0C0h" /* lzcnt eax, eax */ \ + parm [eax] \ + value [eax] \ + modify nomemory; +#else +/* Use the 386+-compatible implementation. */ +#pragma aux drflac__clz_watcom = \ + "bsr eax, eax" \ + "xor eax, 31" \ + parm [eax] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif +#endif + +static DRFLAC_INLINE drflac_uint32 drflac__clz(drflac_cache_t x) +{ +#ifdef DRFLAC_IMPLEMENT_CLZ_LZCNT + if (drflac__is_lzcnt_supported()) { + return drflac__clz_lzcnt(x); + } else +#endif + { +#ifdef DRFLAC_IMPLEMENT_CLZ_MSVC + return drflac__clz_msvc(x); +#elif defined(DRFLAC_IMPLEMENT_CLZ_WATCOM_LZCNT) + return drflac__clz_watcom_lzcnt(x); +#elif defined(DRFLAC_IMPLEMENT_CLZ_WATCOM) + return (x == 0) ? sizeof(x)*8 : drflac__clz_watcom(x); +#elif defined(__MRC__) + return __cntlzw(x); +#else + return drflac__clz_software(x); +#endif + } +} + + +static DRFLAC_INLINE drflac_bool32 drflac__seek_past_next_set_bit(drflac_bs* bs, unsigned int* pOffsetOut) +{ + drflac_uint32 zeroCounter = 0; + drflac_uint32 setBitOffsetPlus1; + + while (bs->cache == 0) { + zeroCounter += (drflac_uint32)DRFLAC_CACHE_L1_BITS_REMAINING(bs); + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; + } + } + + if (bs->cache == 1) { + /* Not catching this would lead to undefined behaviour: a shift of a 32-bit number by 32 or more is undefined */ + *pOffsetOut = zeroCounter + (drflac_uint32)DRFLAC_CACHE_L1_BITS_REMAINING(bs) - 1; + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; + } + + return DRFLAC_TRUE; + } + + setBitOffsetPlus1 = drflac__clz(bs->cache); + setBitOffsetPlus1 += 1; + + if (setBitOffsetPlus1 > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + /* This happens when we get to end of stream */ + return DRFLAC_FALSE; + } + + bs->consumedBits += setBitOffsetPlus1; + bs->cache <<= setBitOffsetPlus1; + + *pOffsetOut = zeroCounter + setBitOffsetPlus1 - 1; + return DRFLAC_TRUE; +} + + + +static drflac_bool32 drflac__seek_to_byte(drflac_bs* bs, drflac_uint64 offsetFromStart) +{ + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(offsetFromStart > 0); + + /* + Seeking from the start is not quite as trivial as it sounds because the onSeek callback takes a signed 32-bit integer (which + is intentional because it simplifies the implementation of the onSeek callbacks), however offsetFromStart is unsigned 64-bit. + To resolve we just need to do an initial seek from the start, and then a series of offset seeks to make up the remainder. + */ + if (offsetFromStart > 0x7FFFFFFF) { + drflac_uint64 bytesRemaining = offsetFromStart; + if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, drflac_seek_origin_start)) { + return DRFLAC_FALSE; + } + bytesRemaining -= 0x7FFFFFFF; + + while (bytesRemaining > 0x7FFFFFFF) { + if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, drflac_seek_origin_current)) { + return DRFLAC_FALSE; + } + bytesRemaining -= 0x7FFFFFFF; + } + + if (bytesRemaining > 0) { + if (!bs->onSeek(bs->pUserData, (int)bytesRemaining, drflac_seek_origin_current)) { + return DRFLAC_FALSE; + } + } + } else { + if (!bs->onSeek(bs->pUserData, (int)offsetFromStart, drflac_seek_origin_start)) { + return DRFLAC_FALSE; + } + } + + /* The cache should be reset to force a reload of fresh data from the client. */ + drflac__reset_cache(bs); + return DRFLAC_TRUE; +} + + +static drflac_result drflac__read_utf8_coded_number(drflac_bs* bs, drflac_uint64* pNumberOut, drflac_uint8* pCRCOut) +{ + drflac_uint8 crc; + drflac_uint64 result; + drflac_uint8 utf8[7] = {0}; + int byteCount; + int i; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pNumberOut != NULL); + DRFLAC_ASSERT(pCRCOut != NULL); + + crc = *pCRCOut; + + if (!drflac__read_uint8(bs, 8, utf8)) { + *pNumberOut = 0; + return DRFLAC_AT_END; + } + crc = drflac_crc8(crc, utf8[0], 8); + + if ((utf8[0] & 0x80) == 0) { + *pNumberOut = utf8[0]; + *pCRCOut = crc; + return DRFLAC_SUCCESS; + } + + /*byteCount = 1;*/ + if ((utf8[0] & 0xE0) == 0xC0) { + byteCount = 2; + } else if ((utf8[0] & 0xF0) == 0xE0) { + byteCount = 3; + } else if ((utf8[0] & 0xF8) == 0xF0) { + byteCount = 4; + } else if ((utf8[0] & 0xFC) == 0xF8) { + byteCount = 5; + } else if ((utf8[0] & 0xFE) == 0xFC) { + byteCount = 6; + } else if ((utf8[0] & 0xFF) == 0xFE) { + byteCount = 7; + } else { + *pNumberOut = 0; + return DRFLAC_CRC_MISMATCH; /* Bad UTF-8 encoding. */ + } + + /* Read extra bytes. */ + DRFLAC_ASSERT(byteCount > 1); + + result = (drflac_uint64)(utf8[0] & (0xFF >> (byteCount + 1))); + for (i = 1; i < byteCount; ++i) { + if (!drflac__read_uint8(bs, 8, utf8 + i)) { + *pNumberOut = 0; + return DRFLAC_AT_END; + } + crc = drflac_crc8(crc, utf8[i], 8); + + result = (result << 6) | (utf8[i] & 0x3F); + } + + *pNumberOut = result; + *pCRCOut = crc; + return DRFLAC_SUCCESS; +} + + +static DRFLAC_INLINE drflac_uint32 drflac__ilog2_u32(drflac_uint32 x) +{ +#if 1 /* Needs optimizing. */ + drflac_uint32 result = 0; + while (x > 0) { + result += 1; + x >>= 1; + } + + return result; +#endif +} + +static DRFLAC_INLINE drflac_bool32 drflac__use_64_bit_prediction(drflac_uint32 bitsPerSample, drflac_uint32 order, drflac_uint32 precision) +{ + /* https://web.archive.org/web/20220205005724/https://github.com/ietf-wg-cellar/flac-specification/blob/37a49aa48ba4ba12e8757badfc59c0df35435fec/rfc_backmatter.md */ + return bitsPerSample + precision + drflac__ilog2_u32(order) > 32; +} + + +/* +The next two functions are responsible for calculating the prediction. + +When the bits per sample is >16 we need to use 64-bit integer arithmetic because otherwise we'll run out of precision. It's +safe to assume this will be slower on 32-bit platforms so we use a more optimal solution when the bits per sample is <=16. +*/ +#if defined(__clang__) +__attribute__((no_sanitize("signed-integer-overflow"))) +#endif +static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_32(drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples) +{ + drflac_int32 prediction = 0; + + DRFLAC_ASSERT(order <= 32); + + /* 32-bit version. */ + + /* VC++ optimizes this to a single jmp. I've not yet verified this for other compilers. */ + switch (order) + { + case 32: prediction += coefficients[31] * pDecodedSamples[-32]; + case 31: prediction += coefficients[30] * pDecodedSamples[-31]; + case 30: prediction += coefficients[29] * pDecodedSamples[-30]; + case 29: prediction += coefficients[28] * pDecodedSamples[-29]; + case 28: prediction += coefficients[27] * pDecodedSamples[-28]; + case 27: prediction += coefficients[26] * pDecodedSamples[-27]; + case 26: prediction += coefficients[25] * pDecodedSamples[-26]; + case 25: prediction += coefficients[24] * pDecodedSamples[-25]; + case 24: prediction += coefficients[23] * pDecodedSamples[-24]; + case 23: prediction += coefficients[22] * pDecodedSamples[-23]; + case 22: prediction += coefficients[21] * pDecodedSamples[-22]; + case 21: prediction += coefficients[20] * pDecodedSamples[-21]; + case 20: prediction += coefficients[19] * pDecodedSamples[-20]; + case 19: prediction += coefficients[18] * pDecodedSamples[-19]; + case 18: prediction += coefficients[17] * pDecodedSamples[-18]; + case 17: prediction += coefficients[16] * pDecodedSamples[-17]; + case 16: prediction += coefficients[15] * pDecodedSamples[-16]; + case 15: prediction += coefficients[14] * pDecodedSamples[-15]; + case 14: prediction += coefficients[13] * pDecodedSamples[-14]; + case 13: prediction += coefficients[12] * pDecodedSamples[-13]; + case 12: prediction += coefficients[11] * pDecodedSamples[-12]; + case 11: prediction += coefficients[10] * pDecodedSamples[-11]; + case 10: prediction += coefficients[ 9] * pDecodedSamples[-10]; + case 9: prediction += coefficients[ 8] * pDecodedSamples[- 9]; + case 8: prediction += coefficients[ 7] * pDecodedSamples[- 8]; + case 7: prediction += coefficients[ 6] * pDecodedSamples[- 7]; + case 6: prediction += coefficients[ 5] * pDecodedSamples[- 6]; + case 5: prediction += coefficients[ 4] * pDecodedSamples[- 5]; + case 4: prediction += coefficients[ 3] * pDecodedSamples[- 4]; + case 3: prediction += coefficients[ 2] * pDecodedSamples[- 3]; + case 2: prediction += coefficients[ 1] * pDecodedSamples[- 2]; + case 1: prediction += coefficients[ 0] * pDecodedSamples[- 1]; + } + + return (drflac_int32)(prediction >> shift); +} + +static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_64(drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples) +{ + drflac_int64 prediction; + + DRFLAC_ASSERT(order <= 32); + + /* 64-bit version. */ + + /* This method is faster on the 32-bit build when compiling with VC++. See note below. */ +#ifndef DRFLAC_64BIT + if (order == 8) + { + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6]; + prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7]; + prediction += coefficients[7] * (drflac_int64)pDecodedSamples[-8]; + } + else if (order == 7) + { + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6]; + prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7]; + } + else if (order == 3) + { + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + } + else if (order == 6) + { + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6]; + } + else if (order == 5) + { + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + } + else if (order == 4) + { + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + } + else if (order == 12) + { + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6]; + prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7]; + prediction += coefficients[7] * (drflac_int64)pDecodedSamples[-8]; + prediction += coefficients[8] * (drflac_int64)pDecodedSamples[-9]; + prediction += coefficients[9] * (drflac_int64)pDecodedSamples[-10]; + prediction += coefficients[10] * (drflac_int64)pDecodedSamples[-11]; + prediction += coefficients[11] * (drflac_int64)pDecodedSamples[-12]; + } + else if (order == 2) + { + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + } + else if (order == 1) + { + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + } + else if (order == 10) + { + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6]; + prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7]; + prediction += coefficients[7] * (drflac_int64)pDecodedSamples[-8]; + prediction += coefficients[8] * (drflac_int64)pDecodedSamples[-9]; + prediction += coefficients[9] * (drflac_int64)pDecodedSamples[-10]; + } + else if (order == 9) + { + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6]; + prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7]; + prediction += coefficients[7] * (drflac_int64)pDecodedSamples[-8]; + prediction += coefficients[8] * (drflac_int64)pDecodedSamples[-9]; + } + else if (order == 11) + { + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6]; + prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7]; + prediction += coefficients[7] * (drflac_int64)pDecodedSamples[-8]; + prediction += coefficients[8] * (drflac_int64)pDecodedSamples[-9]; + prediction += coefficients[9] * (drflac_int64)pDecodedSamples[-10]; + prediction += coefficients[10] * (drflac_int64)pDecodedSamples[-11]; + } + else + { + int j; + + prediction = 0; + for (j = 0; j < (int)order; ++j) { + prediction += coefficients[j] * (drflac_int64)pDecodedSamples[-j-1]; + } + } +#endif + + /* + VC++ optimizes this to a single jmp instruction, but only the 64-bit build. The 32-bit build generates less efficient code for some + reason. The ugly version above is faster so we'll just switch between the two depending on the target platform. + */ +#ifdef DRFLAC_64BIT + prediction = 0; + switch (order) + { + case 32: prediction += coefficients[31] * (drflac_int64)pDecodedSamples[-32]; + case 31: prediction += coefficients[30] * (drflac_int64)pDecodedSamples[-31]; + case 30: prediction += coefficients[29] * (drflac_int64)pDecodedSamples[-30]; + case 29: prediction += coefficients[28] * (drflac_int64)pDecodedSamples[-29]; + case 28: prediction += coefficients[27] * (drflac_int64)pDecodedSamples[-28]; + case 27: prediction += coefficients[26] * (drflac_int64)pDecodedSamples[-27]; + case 26: prediction += coefficients[25] * (drflac_int64)pDecodedSamples[-26]; + case 25: prediction += coefficients[24] * (drflac_int64)pDecodedSamples[-25]; + case 24: prediction += coefficients[23] * (drflac_int64)pDecodedSamples[-24]; + case 23: prediction += coefficients[22] * (drflac_int64)pDecodedSamples[-23]; + case 22: prediction += coefficients[21] * (drflac_int64)pDecodedSamples[-22]; + case 21: prediction += coefficients[20] * (drflac_int64)pDecodedSamples[-21]; + case 20: prediction += coefficients[19] * (drflac_int64)pDecodedSamples[-20]; + case 19: prediction += coefficients[18] * (drflac_int64)pDecodedSamples[-19]; + case 18: prediction += coefficients[17] * (drflac_int64)pDecodedSamples[-18]; + case 17: prediction += coefficients[16] * (drflac_int64)pDecodedSamples[-17]; + case 16: prediction += coefficients[15] * (drflac_int64)pDecodedSamples[-16]; + case 15: prediction += coefficients[14] * (drflac_int64)pDecodedSamples[-15]; + case 14: prediction += coefficients[13] * (drflac_int64)pDecodedSamples[-14]; + case 13: prediction += coefficients[12] * (drflac_int64)pDecodedSamples[-13]; + case 12: prediction += coefficients[11] * (drflac_int64)pDecodedSamples[-12]; + case 11: prediction += coefficients[10] * (drflac_int64)pDecodedSamples[-11]; + case 10: prediction += coefficients[ 9] * (drflac_int64)pDecodedSamples[-10]; + case 9: prediction += coefficients[ 8] * (drflac_int64)pDecodedSamples[- 9]; + case 8: prediction += coefficients[ 7] * (drflac_int64)pDecodedSamples[- 8]; + case 7: prediction += coefficients[ 6] * (drflac_int64)pDecodedSamples[- 7]; + case 6: prediction += coefficients[ 5] * (drflac_int64)pDecodedSamples[- 6]; + case 5: prediction += coefficients[ 4] * (drflac_int64)pDecodedSamples[- 5]; + case 4: prediction += coefficients[ 3] * (drflac_int64)pDecodedSamples[- 4]; + case 3: prediction += coefficients[ 2] * (drflac_int64)pDecodedSamples[- 3]; + case 2: prediction += coefficients[ 1] * (drflac_int64)pDecodedSamples[- 2]; + case 1: prediction += coefficients[ 0] * (drflac_int64)pDecodedSamples[- 1]; + } +#endif + + return (drflac_int32)(prediction >> shift); +} + + +#if 0 +/* +Reference implementation for reading and decoding samples with residual. This is intentionally left unoptimized for the +sake of readability and should only be used as a reference. +*/ +static drflac_bool32 drflac__decode_samples_with_residual__rice__reference(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +{ + drflac_uint32 i; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pSamplesOut != NULL); + + for (i = 0; i < count; ++i) { + drflac_uint32 zeroCounter = 0; + for (;;) { + drflac_uint8 bit; + if (!drflac__read_uint8(bs, 1, &bit)) { + return DRFLAC_FALSE; + } + + if (bit == 0) { + zeroCounter += 1; + } else { + break; + } + } + + drflac_uint32 decodedRice; + if (riceParam > 0) { + if (!drflac__read_uint32(bs, riceParam, &decodedRice)) { + return DRFLAC_FALSE; + } + } else { + decodedRice = 0; + } + + decodedRice |= (zeroCounter << riceParam); + if ((decodedRice & 0x01)) { + decodedRice = ~(decodedRice >> 1); + } else { + decodedRice = (decodedRice >> 1); + } + + + if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { + pSamplesOut[i] = decodedRice + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + i); + } else { + pSamplesOut[i] = decodedRice + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + i); + } + } + + return DRFLAC_TRUE; +} +#endif + +#if 0 +static drflac_bool32 drflac__read_rice_parts__reference(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut) +{ + drflac_uint32 zeroCounter = 0; + drflac_uint32 decodedRice; + + for (;;) { + drflac_uint8 bit; + if (!drflac__read_uint8(bs, 1, &bit)) { + return DRFLAC_FALSE; + } + + if (bit == 0) { + zeroCounter += 1; + } else { + break; + } + } + + if (riceParam > 0) { + if (!drflac__read_uint32(bs, riceParam, &decodedRice)) { + return DRFLAC_FALSE; + } + } else { + decodedRice = 0; + } + + *pZeroCounterOut = zeroCounter; + *pRiceParamPartOut = decodedRice; + return DRFLAC_TRUE; +} +#endif + +#if 0 +static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut) +{ + drflac_cache_t riceParamMask; + drflac_uint32 zeroCounter; + drflac_uint32 setBitOffsetPlus1; + drflac_uint32 riceParamPart; + drflac_uint32 riceLength; + + DRFLAC_ASSERT(riceParam > 0); /* <-- riceParam should never be 0. drflac__read_rice_parts__param_equals_zero() should be used instead for this case. */ + + riceParamMask = DRFLAC_CACHE_L1_SELECTION_MASK(riceParam); + + zeroCounter = 0; + while (bs->cache == 0) { + zeroCounter += (drflac_uint32)DRFLAC_CACHE_L1_BITS_REMAINING(bs); + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; + } + } + + setBitOffsetPlus1 = drflac__clz(bs->cache); + zeroCounter += setBitOffsetPlus1; + setBitOffsetPlus1 += 1; + + riceLength = setBitOffsetPlus1 + riceParam; + if (riceLength < DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + riceParamPart = (drflac_uint32)((bs->cache & (riceParamMask >> setBitOffsetPlus1)) >> DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceLength)); + + bs->consumedBits += riceLength; + bs->cache <<= riceLength; + } else { + drflac_uint32 bitCountLo; + drflac_cache_t resultHi; + + bs->consumedBits += riceLength; + bs->cache <<= setBitOffsetPlus1 & (DRFLAC_CACHE_L1_SIZE_BITS(bs)-1); /* <-- Equivalent to "if (setBitOffsetPlus1 < DRFLAC_CACHE_L1_SIZE_BITS(bs)) { bs->cache <<= setBitOffsetPlus1; }" */ + + /* It straddles the cached data. It will never cover more than the next chunk. We just read the number in two parts and combine them. */ + bitCountLo = bs->consumedBits - DRFLAC_CACHE_L1_SIZE_BITS(bs); + resultHi = DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, riceParam); /* <-- Use DRFLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE() if ever this function allows riceParam=0. */ + + if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { +#ifndef DR_FLAC_NO_CRC + drflac__update_crc16(bs); +#endif + bs->cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); + bs->consumedBits = 0; +#ifndef DR_FLAC_NO_CRC + bs->crc16Cache = bs->cache; +#endif + } else { + /* Slow path. We need to fetch more data from the client. */ + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; + } + if (bitCountLo > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + /* This happens when we get to end of stream */ + return DRFLAC_FALSE; + } + } + + riceParamPart = (drflac_uint32)(resultHi | DRFLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE(bs, bitCountLo)); + + bs->consumedBits += bitCountLo; + bs->cache <<= bitCountLo; + } + + pZeroCounterOut[0] = zeroCounter; + pRiceParamPartOut[0] = riceParamPart; + + return DRFLAC_TRUE; +} +#endif + +static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts_x1(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut) +{ + drflac_uint32 riceParamPlus1 = riceParam + 1; + /*drflac_cache_t riceParamPlus1Mask = DRFLAC_CACHE_L1_SELECTION_MASK(riceParamPlus1);*/ + drflac_uint32 riceParamPlus1Shift = DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceParamPlus1); + drflac_uint32 riceParamPlus1MaxConsumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceParamPlus1; + + /* + The idea here is to use local variables for the cache in an attempt to encourage the compiler to store them in registers. I have + no idea how this will work in practice... + */ + drflac_cache_t bs_cache = bs->cache; + drflac_uint32 bs_consumedBits = bs->consumedBits; + + /* The first thing to do is find the first unset bit. Most likely a bit will be set in the current cache line. */ + drflac_uint32 lzcount = drflac__clz(bs_cache); + if (lzcount < sizeof(bs_cache)*8) { + pZeroCounterOut[0] = lzcount; + + /* + It is most likely that the riceParam part (which comes after the zero counter) is also on this cache line. When extracting + this, we include the set bit from the unary coded part because it simplifies cache management. This bit will be handled + outside of this function at a higher level. + */ + extract_rice_param_part: + bs_cache <<= lzcount; + bs_consumedBits += lzcount; + + if (bs_consumedBits <= riceParamPlus1MaxConsumedBits) { + /* Getting here means the rice parameter part is wholly contained within the current cache line. */ + pRiceParamPartOut[0] = (drflac_uint32)(bs_cache >> riceParamPlus1Shift); + bs_cache <<= riceParamPlus1; + bs_consumedBits += riceParamPlus1; + } else { + drflac_uint32 riceParamPartHi; + drflac_uint32 riceParamPartLo; + drflac_uint32 riceParamPartLoBitCount; + + /* + Getting here means the rice parameter part straddles the cache line. We need to read from the tail of the current cache + line, reload the cache, and then combine it with the head of the next cache line. + */ + + /* Grab the high part of the rice parameter part. */ + riceParamPartHi = (drflac_uint32)(bs_cache >> riceParamPlus1Shift); + + /* Before reloading the cache we need to grab the size in bits of the low part. */ + riceParamPartLoBitCount = bs_consumedBits - riceParamPlus1MaxConsumedBits; + DRFLAC_ASSERT(riceParamPartLoBitCount > 0 && riceParamPartLoBitCount < 32); + + /* Now reload the cache. */ + if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { + #ifndef DR_FLAC_NO_CRC + drflac__update_crc16(bs); + #endif + bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); + bs_consumedBits = riceParamPartLoBitCount; + #ifndef DR_FLAC_NO_CRC + bs->crc16Cache = bs_cache; + #endif + } else { + /* Slow path. We need to fetch more data from the client. */ + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; + } + if (riceParamPartLoBitCount > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + /* This happens when we get to end of stream */ + return DRFLAC_FALSE; + } + + bs_cache = bs->cache; + bs_consumedBits = bs->consumedBits + riceParamPartLoBitCount; + } + + /* We should now have enough information to construct the rice parameter part. */ + riceParamPartLo = (drflac_uint32)(bs_cache >> (DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceParamPartLoBitCount))); + pRiceParamPartOut[0] = riceParamPartHi | riceParamPartLo; + + bs_cache <<= riceParamPartLoBitCount; + } + } else { + /* + Getting here means there are no bits set on the cache line. This is a less optimal case because we just wasted a call + to drflac__clz() and we need to reload the cache. + */ + drflac_uint32 zeroCounter = (drflac_uint32)(DRFLAC_CACHE_L1_SIZE_BITS(bs) - bs_consumedBits); + for (;;) { + if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { + #ifndef DR_FLAC_NO_CRC + drflac__update_crc16(bs); + #endif + bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); + bs_consumedBits = 0; + #ifndef DR_FLAC_NO_CRC + bs->crc16Cache = bs_cache; + #endif + } else { + /* Slow path. We need to fetch more data from the client. */ + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; + } + + bs_cache = bs->cache; + bs_consumedBits = bs->consumedBits; + } + + lzcount = drflac__clz(bs_cache); + zeroCounter += lzcount; + + if (lzcount < sizeof(bs_cache)*8) { + break; + } + } + + pZeroCounterOut[0] = zeroCounter; + goto extract_rice_param_part; + } + + /* Make sure the cache is restored at the end of it all. */ + bs->cache = bs_cache; + bs->consumedBits = bs_consumedBits; + + return DRFLAC_TRUE; +} + +static DRFLAC_INLINE drflac_bool32 drflac__seek_rice_parts(drflac_bs* bs, drflac_uint8 riceParam) +{ + drflac_uint32 riceParamPlus1 = riceParam + 1; + drflac_uint32 riceParamPlus1MaxConsumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceParamPlus1; + + /* + The idea here is to use local variables for the cache in an attempt to encourage the compiler to store them in registers. I have + no idea how this will work in practice... + */ + drflac_cache_t bs_cache = bs->cache; + drflac_uint32 bs_consumedBits = bs->consumedBits; + + /* The first thing to do is find the first unset bit. Most likely a bit will be set in the current cache line. */ + drflac_uint32 lzcount = drflac__clz(bs_cache); + if (lzcount < sizeof(bs_cache)*8) { + /* + It is most likely that the riceParam part (which comes after the zero counter) is also on this cache line. When extracting + this, we include the set bit from the unary coded part because it simplifies cache management. This bit will be handled + outside of this function at a higher level. + */ + extract_rice_param_part: + bs_cache <<= lzcount; + bs_consumedBits += lzcount; + + if (bs_consumedBits <= riceParamPlus1MaxConsumedBits) { + /* Getting here means the rice parameter part is wholly contained within the current cache line. */ + bs_cache <<= riceParamPlus1; + bs_consumedBits += riceParamPlus1; + } else { + /* + Getting here means the rice parameter part straddles the cache line. We need to read from the tail of the current cache + line, reload the cache, and then combine it with the head of the next cache line. + */ + + /* Before reloading the cache we need to grab the size in bits of the low part. */ + drflac_uint32 riceParamPartLoBitCount = bs_consumedBits - riceParamPlus1MaxConsumedBits; + DRFLAC_ASSERT(riceParamPartLoBitCount > 0 && riceParamPartLoBitCount < 32); + + /* Now reload the cache. */ + if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { + #ifndef DR_FLAC_NO_CRC + drflac__update_crc16(bs); + #endif + bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); + bs_consumedBits = riceParamPartLoBitCount; + #ifndef DR_FLAC_NO_CRC + bs->crc16Cache = bs_cache; + #endif + } else { + /* Slow path. We need to fetch more data from the client. */ + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; + } + + if (riceParamPartLoBitCount > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + /* This happens when we get to end of stream */ + return DRFLAC_FALSE; + } + + bs_cache = bs->cache; + bs_consumedBits = bs->consumedBits + riceParamPartLoBitCount; + } + + bs_cache <<= riceParamPartLoBitCount; + } + } else { + /* + Getting here means there are no bits set on the cache line. This is a less optimal case because we just wasted a call + to drflac__clz() and we need to reload the cache. + */ + for (;;) { + if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { + #ifndef DR_FLAC_NO_CRC + drflac__update_crc16(bs); + #endif + bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); + bs_consumedBits = 0; + #ifndef DR_FLAC_NO_CRC + bs->crc16Cache = bs_cache; + #endif + } else { + /* Slow path. We need to fetch more data from the client. */ + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; + } + + bs_cache = bs->cache; + bs_consumedBits = bs->consumedBits; + } + + lzcount = drflac__clz(bs_cache); + if (lzcount < sizeof(bs_cache)*8) { + break; + } + } + + goto extract_rice_param_part; + } + + /* Make sure the cache is restored at the end of it all. */ + bs->cache = bs_cache; + bs->consumedBits = bs_consumedBits; + + return DRFLAC_TRUE; +} + + +static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar_zeroorder(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +{ + drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; + drflac_uint32 zeroCountPart0; + drflac_uint32 riceParamPart0; + drflac_uint32 riceParamMask; + drflac_uint32 i; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pSamplesOut != NULL); + + (void)bitsPerSample; + (void)order; + (void)shift; + (void)coefficients; + + riceParamMask = (drflac_uint32)~((~0UL) << riceParam); + + i = 0; + while (i < count) { + /* Rice extraction. */ + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0)) { + return DRFLAC_FALSE; + } + + /* Rice reconstruction. */ + riceParamPart0 &= riceParamMask; + riceParamPart0 |= (zeroCountPart0 << riceParam); + riceParamPart0 = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01]; + + pSamplesOut[i] = riceParamPart0; + + i += 1; + } + + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +{ + drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; + drflac_uint32 zeroCountPart0 = 0; + drflac_uint32 zeroCountPart1 = 0; + drflac_uint32 zeroCountPart2 = 0; + drflac_uint32 zeroCountPart3 = 0; + drflac_uint32 riceParamPart0 = 0; + drflac_uint32 riceParamPart1 = 0; + drflac_uint32 riceParamPart2 = 0; + drflac_uint32 riceParamPart3 = 0; + drflac_uint32 riceParamMask; + const drflac_int32* pSamplesOutEnd; + drflac_uint32 i; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pSamplesOut != NULL); + + if (lpcOrder == 0) { + return drflac__decode_samples_with_residual__rice__scalar_zeroorder(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); + } + + riceParamMask = (drflac_uint32)~((~0UL) << riceParam); + pSamplesOutEnd = pSamplesOut + (count & ~3); + + if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { + while (pSamplesOut < pSamplesOutEnd) { + /* + Rice extraction. It's faster to do this one at a time against local variables than it is to use the x4 version + against an array. Not sure why, but perhaps it's making more efficient use of registers? + */ + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart1, &riceParamPart1) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart2, &riceParamPart2) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart3, &riceParamPart3)) { + return DRFLAC_FALSE; + } + + riceParamPart0 &= riceParamMask; + riceParamPart1 &= riceParamMask; + riceParamPart2 &= riceParamMask; + riceParamPart3 &= riceParamMask; + + riceParamPart0 |= (zeroCountPart0 << riceParam); + riceParamPart1 |= (zeroCountPart1 << riceParam); + riceParamPart2 |= (zeroCountPart2 << riceParam); + riceParamPart3 |= (zeroCountPart3 << riceParam); + + riceParamPart0 = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01]; + riceParamPart1 = (riceParamPart1 >> 1) ^ t[riceParamPart1 & 0x01]; + riceParamPart2 = (riceParamPart2 >> 1) ^ t[riceParamPart2 & 0x01]; + riceParamPart3 = (riceParamPart3 >> 1) ^ t[riceParamPart3 & 0x01]; + + pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 0); + pSamplesOut[1] = riceParamPart1 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 1); + pSamplesOut[2] = riceParamPart2 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 2); + pSamplesOut[3] = riceParamPart3 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 3); + + pSamplesOut += 4; + } + } else { + while (pSamplesOut < pSamplesOutEnd) { + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart1, &riceParamPart1) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart2, &riceParamPart2) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart3, &riceParamPart3)) { + return DRFLAC_FALSE; + } + + riceParamPart0 &= riceParamMask; + riceParamPart1 &= riceParamMask; + riceParamPart2 &= riceParamMask; + riceParamPart3 &= riceParamMask; + + riceParamPart0 |= (zeroCountPart0 << riceParam); + riceParamPart1 |= (zeroCountPart1 << riceParam); + riceParamPart2 |= (zeroCountPart2 << riceParam); + riceParamPart3 |= (zeroCountPart3 << riceParam); + + riceParamPart0 = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01]; + riceParamPart1 = (riceParamPart1 >> 1) ^ t[riceParamPart1 & 0x01]; + riceParamPart2 = (riceParamPart2 >> 1) ^ t[riceParamPart2 & 0x01]; + riceParamPart3 = (riceParamPart3 >> 1) ^ t[riceParamPart3 & 0x01]; + + pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 0); + pSamplesOut[1] = riceParamPart1 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 1); + pSamplesOut[2] = riceParamPart2 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 2); + pSamplesOut[3] = riceParamPart3 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 3); + + pSamplesOut += 4; + } + } + + i = (count & ~3); + while (i < count) { + /* Rice extraction. */ + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0)) { + return DRFLAC_FALSE; + } + + /* Rice reconstruction. */ + riceParamPart0 &= riceParamMask; + riceParamPart0 |= (zeroCountPart0 << riceParam); + riceParamPart0 = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01]; + /*riceParamPart0 = (riceParamPart0 >> 1) ^ (~(riceParamPart0 & 0x01) + 1);*/ + + /* Sample reconstruction. */ + if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { + pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 0); + } else { + pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 0); + } + + i += 1; + pSamplesOut += 1; + } + + return DRFLAC_TRUE; +} + +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE __m128i drflac__mm_packs_interleaved_epi32(__m128i a, __m128i b) +{ + __m128i r; + + /* Pack. */ + r = _mm_packs_epi32(a, b); + + /* a3a2 a1a0 b3b2 b1b0 -> a3a2 b3b2 a1a0 b1b0 */ + r = _mm_shuffle_epi32(r, _MM_SHUFFLE(3, 1, 2, 0)); + + /* a3a2 b3b2 a1a0 b1b0 -> a3b3 a2b2 a1b1 a0b0 */ + r = _mm_shufflehi_epi16(r, _MM_SHUFFLE(3, 1, 2, 0)); + r = _mm_shufflelo_epi16(r, _MM_SHUFFLE(3, 1, 2, 0)); + + return r; +} +#endif + +#if defined(DRFLAC_SUPPORT_SSE41) +static DRFLAC_INLINE __m128i drflac__mm_not_si128(__m128i a) +{ + return _mm_xor_si128(a, _mm_cmpeq_epi32(_mm_setzero_si128(), _mm_setzero_si128())); +} + +static DRFLAC_INLINE __m128i drflac__mm_hadd_epi32(__m128i x) +{ + __m128i x64 = _mm_add_epi32(x, _mm_shuffle_epi32(x, _MM_SHUFFLE(1, 0, 3, 2))); + __m128i x32 = _mm_shufflelo_epi16(x64, _MM_SHUFFLE(1, 0, 3, 2)); + return _mm_add_epi32(x64, x32); +} + +static DRFLAC_INLINE __m128i drflac__mm_hadd_epi64(__m128i x) +{ + return _mm_add_epi64(x, _mm_shuffle_epi32(x, _MM_SHUFFLE(1, 0, 3, 2))); +} + +static DRFLAC_INLINE __m128i drflac__mm_srai_epi64(__m128i x, int count) +{ + /* + To simplify this we are assuming count < 32. This restriction allows us to work on a low side and a high side. The low side + is shifted with zero bits, whereas the right side is shifted with sign bits. + */ + __m128i lo = _mm_srli_epi64(x, count); + __m128i hi = _mm_srai_epi32(x, count); + + hi = _mm_and_si128(hi, _mm_set_epi32(0xFFFFFFFF, 0, 0xFFFFFFFF, 0)); /* The high part needs to have the low part cleared. */ + + return _mm_or_si128(lo, hi); +} + +static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41_32(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +{ + int i; + drflac_uint32 riceParamMask; + drflac_int32* pDecodedSamples = pSamplesOut; + drflac_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3); + drflac_uint32 zeroCountParts0 = 0; + drflac_uint32 zeroCountParts1 = 0; + drflac_uint32 zeroCountParts2 = 0; + drflac_uint32 zeroCountParts3 = 0; + drflac_uint32 riceParamParts0 = 0; + drflac_uint32 riceParamParts1 = 0; + drflac_uint32 riceParamParts2 = 0; + drflac_uint32 riceParamParts3 = 0; + __m128i coefficients128_0; + __m128i coefficients128_4; + __m128i coefficients128_8; + __m128i samples128_0; + __m128i samples128_4; + __m128i samples128_8; + __m128i riceParamMask128; + + const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; + + riceParamMask = (drflac_uint32)~((~0UL) << riceParam); + riceParamMask128 = _mm_set1_epi32(riceParamMask); + + /* Pre-load. */ + coefficients128_0 = _mm_setzero_si128(); + coefficients128_4 = _mm_setzero_si128(); + coefficients128_8 = _mm_setzero_si128(); + + samples128_0 = _mm_setzero_si128(); + samples128_4 = _mm_setzero_si128(); + samples128_8 = _mm_setzero_si128(); + + /* + Pre-loading the coefficients and prior samples is annoying because we need to ensure we don't try reading more than + what's available in the input buffers. It would be convenient to use a fall-through switch to do this, but this results + in strict aliasing warnings with GCC. To work around this I'm just doing something hacky. This feels a bit convoluted + so I think there's opportunity for this to be simplified. + */ +#if 1 + { + int runningOrder = order; + + /* 0 - 3. */ + if (runningOrder >= 4) { + coefficients128_0 = _mm_loadu_si128((const __m128i*)(coefficients + 0)); + samples128_0 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 4)); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: coefficients128_0 = _mm_set_epi32(0, coefficients[2], coefficients[1], coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], pSamplesOut[-2], pSamplesOut[-3], 0); break; + case 2: coefficients128_0 = _mm_set_epi32(0, 0, coefficients[1], coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], pSamplesOut[-2], 0, 0); break; + case 1: coefficients128_0 = _mm_set_epi32(0, 0, 0, coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], 0, 0, 0); break; + } + runningOrder = 0; + } + + /* 4 - 7 */ + if (runningOrder >= 4) { + coefficients128_4 = _mm_loadu_si128((const __m128i*)(coefficients + 4)); + samples128_4 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 8)); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: coefficients128_4 = _mm_set_epi32(0, coefficients[6], coefficients[5], coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], pSamplesOut[-6], pSamplesOut[-7], 0); break; + case 2: coefficients128_4 = _mm_set_epi32(0, 0, coefficients[5], coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], pSamplesOut[-6], 0, 0); break; + case 1: coefficients128_4 = _mm_set_epi32(0, 0, 0, coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], 0, 0, 0); break; + } + runningOrder = 0; + } + + /* 8 - 11 */ + if (runningOrder == 4) { + coefficients128_8 = _mm_loadu_si128((const __m128i*)(coefficients + 8)); + samples128_8 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 12)); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: coefficients128_8 = _mm_set_epi32(0, coefficients[10], coefficients[9], coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], pSamplesOut[-10], pSamplesOut[-11], 0); break; + case 2: coefficients128_8 = _mm_set_epi32(0, 0, coefficients[9], coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], pSamplesOut[-10], 0, 0); break; + case 1: coefficients128_8 = _mm_set_epi32(0, 0, 0, coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], 0, 0, 0); break; + } + runningOrder = 0; + } + + /* Coefficients need to be shuffled for our streaming algorithm below to work. Samples are already in the correct order from the loading routine above. */ + coefficients128_0 = _mm_shuffle_epi32(coefficients128_0, _MM_SHUFFLE(0, 1, 2, 3)); + coefficients128_4 = _mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(0, 1, 2, 3)); + coefficients128_8 = _mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(0, 1, 2, 3)); + } +#else + /* This causes strict-aliasing warnings with GCC. */ + switch (order) + { + case 12: ((drflac_int32*)&coefficients128_8)[0] = coefficients[11]; ((drflac_int32*)&samples128_8)[0] = pDecodedSamples[-12]; + case 11: ((drflac_int32*)&coefficients128_8)[1] = coefficients[10]; ((drflac_int32*)&samples128_8)[1] = pDecodedSamples[-11]; + case 10: ((drflac_int32*)&coefficients128_8)[2] = coefficients[ 9]; ((drflac_int32*)&samples128_8)[2] = pDecodedSamples[-10]; + case 9: ((drflac_int32*)&coefficients128_8)[3] = coefficients[ 8]; ((drflac_int32*)&samples128_8)[3] = pDecodedSamples[- 9]; + case 8: ((drflac_int32*)&coefficients128_4)[0] = coefficients[ 7]; ((drflac_int32*)&samples128_4)[0] = pDecodedSamples[- 8]; + case 7: ((drflac_int32*)&coefficients128_4)[1] = coefficients[ 6]; ((drflac_int32*)&samples128_4)[1] = pDecodedSamples[- 7]; + case 6: ((drflac_int32*)&coefficients128_4)[2] = coefficients[ 5]; ((drflac_int32*)&samples128_4)[2] = pDecodedSamples[- 6]; + case 5: ((drflac_int32*)&coefficients128_4)[3] = coefficients[ 4]; ((drflac_int32*)&samples128_4)[3] = pDecodedSamples[- 5]; + case 4: ((drflac_int32*)&coefficients128_0)[0] = coefficients[ 3]; ((drflac_int32*)&samples128_0)[0] = pDecodedSamples[- 4]; + case 3: ((drflac_int32*)&coefficients128_0)[1] = coefficients[ 2]; ((drflac_int32*)&samples128_0)[1] = pDecodedSamples[- 3]; + case 2: ((drflac_int32*)&coefficients128_0)[2] = coefficients[ 1]; ((drflac_int32*)&samples128_0)[2] = pDecodedSamples[- 2]; + case 1: ((drflac_int32*)&coefficients128_0)[3] = coefficients[ 0]; ((drflac_int32*)&samples128_0)[3] = pDecodedSamples[- 1]; + } +#endif + + /* For this version we are doing one sample at a time. */ + while (pDecodedSamples < pDecodedSamplesEnd) { + __m128i prediction128; + __m128i zeroCountPart128; + __m128i riceParamPart128; + + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts1, &riceParamParts1) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts2, &riceParamParts2) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts3, &riceParamParts3)) { + return DRFLAC_FALSE; + } + + zeroCountPart128 = _mm_set_epi32(zeroCountParts3, zeroCountParts2, zeroCountParts1, zeroCountParts0); + riceParamPart128 = _mm_set_epi32(riceParamParts3, riceParamParts2, riceParamParts1, riceParamParts0); + + riceParamPart128 = _mm_and_si128(riceParamPart128, riceParamMask128); + riceParamPart128 = _mm_or_si128(riceParamPart128, _mm_slli_epi32(zeroCountPart128, riceParam)); + riceParamPart128 = _mm_xor_si128(_mm_srli_epi32(riceParamPart128, 1), _mm_add_epi32(drflac__mm_not_si128(_mm_and_si128(riceParamPart128, _mm_set1_epi32(0x01))), _mm_set1_epi32(0x01))); /* <-- SSE2 compatible */ + /*riceParamPart128 = _mm_xor_si128(_mm_srli_epi32(riceParamPart128, 1), _mm_mullo_epi32(_mm_and_si128(riceParamPart128, _mm_set1_epi32(0x01)), _mm_set1_epi32(0xFFFFFFFF)));*/ /* <-- Only supported from SSE4.1 and is slower in my testing... */ + + if (order <= 4) { + for (i = 0; i < 4; i += 1) { + prediction128 = _mm_mullo_epi32(coefficients128_0, samples128_0); + + /* Horizontal add and shift. */ + prediction128 = drflac__mm_hadd_epi32(prediction128); + prediction128 = _mm_srai_epi32(prediction128, shift); + prediction128 = _mm_add_epi32(riceParamPart128, prediction128); + + samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4); + riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4); + } + } else if (order <= 8) { + for (i = 0; i < 4; i += 1) { + prediction128 = _mm_mullo_epi32(coefficients128_4, samples128_4); + prediction128 = _mm_add_epi32(prediction128, _mm_mullo_epi32(coefficients128_0, samples128_0)); + + /* Horizontal add and shift. */ + prediction128 = drflac__mm_hadd_epi32(prediction128); + prediction128 = _mm_srai_epi32(prediction128, shift); + prediction128 = _mm_add_epi32(riceParamPart128, prediction128); + + samples128_4 = _mm_alignr_epi8(samples128_0, samples128_4, 4); + samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4); + riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4); + } + } else { + for (i = 0; i < 4; i += 1) { + prediction128 = _mm_mullo_epi32(coefficients128_8, samples128_8); + prediction128 = _mm_add_epi32(prediction128, _mm_mullo_epi32(coefficients128_4, samples128_4)); + prediction128 = _mm_add_epi32(prediction128, _mm_mullo_epi32(coefficients128_0, samples128_0)); + + /* Horizontal add and shift. */ + prediction128 = drflac__mm_hadd_epi32(prediction128); + prediction128 = _mm_srai_epi32(prediction128, shift); + prediction128 = _mm_add_epi32(riceParamPart128, prediction128); + + samples128_8 = _mm_alignr_epi8(samples128_4, samples128_8, 4); + samples128_4 = _mm_alignr_epi8(samples128_0, samples128_4, 4); + samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4); + riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4); + } + } + + /* We store samples in groups of 4. */ + _mm_storeu_si128((__m128i*)pDecodedSamples, samples128_0); + pDecodedSamples += 4; + } + + /* Make sure we process the last few samples. */ + i = (count & ~3); + while (i < (int)count) { + /* Rice extraction. */ + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0)) { + return DRFLAC_FALSE; + } + + /* Rice reconstruction. */ + riceParamParts0 &= riceParamMask; + riceParamParts0 |= (zeroCountParts0 << riceParam); + riceParamParts0 = (riceParamParts0 >> 1) ^ t[riceParamParts0 & 0x01]; + + /* Sample reconstruction. */ + pDecodedSamples[0] = riceParamParts0 + drflac__calculate_prediction_32(order, shift, coefficients, pDecodedSamples); + + i += 1; + pDecodedSamples += 1; + } + + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41_64(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +{ + int i; + drflac_uint32 riceParamMask; + drflac_int32* pDecodedSamples = pSamplesOut; + drflac_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3); + drflac_uint32 zeroCountParts0 = 0; + drflac_uint32 zeroCountParts1 = 0; + drflac_uint32 zeroCountParts2 = 0; + drflac_uint32 zeroCountParts3 = 0; + drflac_uint32 riceParamParts0 = 0; + drflac_uint32 riceParamParts1 = 0; + drflac_uint32 riceParamParts2 = 0; + drflac_uint32 riceParamParts3 = 0; + __m128i coefficients128_0; + __m128i coefficients128_4; + __m128i coefficients128_8; + __m128i samples128_0; + __m128i samples128_4; + __m128i samples128_8; + __m128i prediction128; + __m128i riceParamMask128; + + const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; + + DRFLAC_ASSERT(order <= 12); + + riceParamMask = (drflac_uint32)~((~0UL) << riceParam); + riceParamMask128 = _mm_set1_epi32(riceParamMask); + + prediction128 = _mm_setzero_si128(); + + /* Pre-load. */ + coefficients128_0 = _mm_setzero_si128(); + coefficients128_4 = _mm_setzero_si128(); + coefficients128_8 = _mm_setzero_si128(); + + samples128_0 = _mm_setzero_si128(); + samples128_4 = _mm_setzero_si128(); + samples128_8 = _mm_setzero_si128(); + +#if 1 + { + int runningOrder = order; + + /* 0 - 3. */ + if (runningOrder >= 4) { + coefficients128_0 = _mm_loadu_si128((const __m128i*)(coefficients + 0)); + samples128_0 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 4)); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: coefficients128_0 = _mm_set_epi32(0, coefficients[2], coefficients[1], coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], pSamplesOut[-2], pSamplesOut[-3], 0); break; + case 2: coefficients128_0 = _mm_set_epi32(0, 0, coefficients[1], coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], pSamplesOut[-2], 0, 0); break; + case 1: coefficients128_0 = _mm_set_epi32(0, 0, 0, coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], 0, 0, 0); break; + } + runningOrder = 0; + } + + /* 4 - 7 */ + if (runningOrder >= 4) { + coefficients128_4 = _mm_loadu_si128((const __m128i*)(coefficients + 4)); + samples128_4 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 8)); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: coefficients128_4 = _mm_set_epi32(0, coefficients[6], coefficients[5], coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], pSamplesOut[-6], pSamplesOut[-7], 0); break; + case 2: coefficients128_4 = _mm_set_epi32(0, 0, coefficients[5], coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], pSamplesOut[-6], 0, 0); break; + case 1: coefficients128_4 = _mm_set_epi32(0, 0, 0, coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], 0, 0, 0); break; + } + runningOrder = 0; + } + + /* 8 - 11 */ + if (runningOrder == 4) { + coefficients128_8 = _mm_loadu_si128((const __m128i*)(coefficients + 8)); + samples128_8 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 12)); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: coefficients128_8 = _mm_set_epi32(0, coefficients[10], coefficients[9], coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], pSamplesOut[-10], pSamplesOut[-11], 0); break; + case 2: coefficients128_8 = _mm_set_epi32(0, 0, coefficients[9], coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], pSamplesOut[-10], 0, 0); break; + case 1: coefficients128_8 = _mm_set_epi32(0, 0, 0, coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], 0, 0, 0); break; + } + runningOrder = 0; + } + + /* Coefficients need to be shuffled for our streaming algorithm below to work. Samples are already in the correct order from the loading routine above. */ + coefficients128_0 = _mm_shuffle_epi32(coefficients128_0, _MM_SHUFFLE(0, 1, 2, 3)); + coefficients128_4 = _mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(0, 1, 2, 3)); + coefficients128_8 = _mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(0, 1, 2, 3)); + } +#else + switch (order) + { + case 12: ((drflac_int32*)&coefficients128_8)[0] = coefficients[11]; ((drflac_int32*)&samples128_8)[0] = pDecodedSamples[-12]; + case 11: ((drflac_int32*)&coefficients128_8)[1] = coefficients[10]; ((drflac_int32*)&samples128_8)[1] = pDecodedSamples[-11]; + case 10: ((drflac_int32*)&coefficients128_8)[2] = coefficients[ 9]; ((drflac_int32*)&samples128_8)[2] = pDecodedSamples[-10]; + case 9: ((drflac_int32*)&coefficients128_8)[3] = coefficients[ 8]; ((drflac_int32*)&samples128_8)[3] = pDecodedSamples[- 9]; + case 8: ((drflac_int32*)&coefficients128_4)[0] = coefficients[ 7]; ((drflac_int32*)&samples128_4)[0] = pDecodedSamples[- 8]; + case 7: ((drflac_int32*)&coefficients128_4)[1] = coefficients[ 6]; ((drflac_int32*)&samples128_4)[1] = pDecodedSamples[- 7]; + case 6: ((drflac_int32*)&coefficients128_4)[2] = coefficients[ 5]; ((drflac_int32*)&samples128_4)[2] = pDecodedSamples[- 6]; + case 5: ((drflac_int32*)&coefficients128_4)[3] = coefficients[ 4]; ((drflac_int32*)&samples128_4)[3] = pDecodedSamples[- 5]; + case 4: ((drflac_int32*)&coefficients128_0)[0] = coefficients[ 3]; ((drflac_int32*)&samples128_0)[0] = pDecodedSamples[- 4]; + case 3: ((drflac_int32*)&coefficients128_0)[1] = coefficients[ 2]; ((drflac_int32*)&samples128_0)[1] = pDecodedSamples[- 3]; + case 2: ((drflac_int32*)&coefficients128_0)[2] = coefficients[ 1]; ((drflac_int32*)&samples128_0)[2] = pDecodedSamples[- 2]; + case 1: ((drflac_int32*)&coefficients128_0)[3] = coefficients[ 0]; ((drflac_int32*)&samples128_0)[3] = pDecodedSamples[- 1]; + } +#endif + + /* For this version we are doing one sample at a time. */ + while (pDecodedSamples < pDecodedSamplesEnd) { + __m128i zeroCountPart128; + __m128i riceParamPart128; + + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts1, &riceParamParts1) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts2, &riceParamParts2) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts3, &riceParamParts3)) { + return DRFLAC_FALSE; + } + + zeroCountPart128 = _mm_set_epi32(zeroCountParts3, zeroCountParts2, zeroCountParts1, zeroCountParts0); + riceParamPart128 = _mm_set_epi32(riceParamParts3, riceParamParts2, riceParamParts1, riceParamParts0); + + riceParamPart128 = _mm_and_si128(riceParamPart128, riceParamMask128); + riceParamPart128 = _mm_or_si128(riceParamPart128, _mm_slli_epi32(zeroCountPart128, riceParam)); + riceParamPart128 = _mm_xor_si128(_mm_srli_epi32(riceParamPart128, 1), _mm_add_epi32(drflac__mm_not_si128(_mm_and_si128(riceParamPart128, _mm_set1_epi32(1))), _mm_set1_epi32(1))); + + for (i = 0; i < 4; i += 1) { + prediction128 = _mm_xor_si128(prediction128, prediction128); /* Reset to 0. */ + + switch (order) + { + case 12: + case 11: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(1, 1, 0, 0)), _mm_shuffle_epi32(samples128_8, _MM_SHUFFLE(1, 1, 0, 0)))); + case 10: + case 9: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(3, 3, 2, 2)), _mm_shuffle_epi32(samples128_8, _MM_SHUFFLE(3, 3, 2, 2)))); + case 8: + case 7: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(1, 1, 0, 0)), _mm_shuffle_epi32(samples128_4, _MM_SHUFFLE(1, 1, 0, 0)))); + case 6: + case 5: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(3, 3, 2, 2)), _mm_shuffle_epi32(samples128_4, _MM_SHUFFLE(3, 3, 2, 2)))); + case 4: + case 3: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_0, _MM_SHUFFLE(1, 1, 0, 0)), _mm_shuffle_epi32(samples128_0, _MM_SHUFFLE(1, 1, 0, 0)))); + case 2: + case 1: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_0, _MM_SHUFFLE(3, 3, 2, 2)), _mm_shuffle_epi32(samples128_0, _MM_SHUFFLE(3, 3, 2, 2)))); + } + + /* Horizontal add and shift. */ + prediction128 = drflac__mm_hadd_epi64(prediction128); + prediction128 = drflac__mm_srai_epi64(prediction128, shift); + prediction128 = _mm_add_epi32(riceParamPart128, prediction128); + + /* Our value should be sitting in prediction128[0]. We need to combine this with our SSE samples. */ + samples128_8 = _mm_alignr_epi8(samples128_4, samples128_8, 4); + samples128_4 = _mm_alignr_epi8(samples128_0, samples128_4, 4); + samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4); + + /* Slide our rice parameter down so that the value in position 0 contains the next one to process. */ + riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4); + } + + /* We store samples in groups of 4. */ + _mm_storeu_si128((__m128i*)pDecodedSamples, samples128_0); + pDecodedSamples += 4; + } + + /* Make sure we process the last few samples. */ + i = (count & ~3); + while (i < (int)count) { + /* Rice extraction. */ + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0)) { + return DRFLAC_FALSE; + } + + /* Rice reconstruction. */ + riceParamParts0 &= riceParamMask; + riceParamParts0 |= (zeroCountParts0 << riceParam); + riceParamParts0 = (riceParamParts0 >> 1) ^ t[riceParamParts0 & 0x01]; + + /* Sample reconstruction. */ + pDecodedSamples[0] = riceParamParts0 + drflac__calculate_prediction_64(order, shift, coefficients, pDecodedSamples); + + i += 1; + pDecodedSamples += 1; + } + + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +{ + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pSamplesOut != NULL); + + /* In my testing the order is rarely > 12, so in this case I'm going to simplify the SSE implementation by only handling order <= 12. */ + if (lpcOrder > 0 && lpcOrder <= 12) { + if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { + return drflac__decode_samples_with_residual__rice__sse41_64(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); + } else { + return drflac__decode_samples_with_residual__rice__sse41_32(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); + } + } else { + return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); + } +} +#endif + +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac__vst2q_s32(drflac_int32* p, int32x4x2_t x) +{ + vst1q_s32(p+0, x.val[0]); + vst1q_s32(p+4, x.val[1]); +} + +static DRFLAC_INLINE void drflac__vst2q_u32(drflac_uint32* p, uint32x4x2_t x) +{ + vst1q_u32(p+0, x.val[0]); + vst1q_u32(p+4, x.val[1]); +} + +static DRFLAC_INLINE void drflac__vst2q_f32(float* p, float32x4x2_t x) +{ + vst1q_f32(p+0, x.val[0]); + vst1q_f32(p+4, x.val[1]); +} + +static DRFLAC_INLINE void drflac__vst2q_s16(drflac_int16* p, int16x4x2_t x) +{ + vst1q_s16(p, vcombine_s16(x.val[0], x.val[1])); +} + +static DRFLAC_INLINE void drflac__vst2q_u16(drflac_uint16* p, uint16x4x2_t x) +{ + vst1q_u16(p, vcombine_u16(x.val[0], x.val[1])); +} + +static DRFLAC_INLINE int32x4_t drflac__vdupq_n_s32x4(drflac_int32 x3, drflac_int32 x2, drflac_int32 x1, drflac_int32 x0) +{ + drflac_int32 x[4]; + x[3] = x3; + x[2] = x2; + x[1] = x1; + x[0] = x0; + return vld1q_s32(x); +} + +static DRFLAC_INLINE int32x4_t drflac__valignrq_s32_1(int32x4_t a, int32x4_t b) +{ + /* Equivalent to SSE's _mm_alignr_epi8(a, b, 4) */ + + /* Reference */ + /*return drflac__vdupq_n_s32x4( + vgetq_lane_s32(a, 0), + vgetq_lane_s32(b, 3), + vgetq_lane_s32(b, 2), + vgetq_lane_s32(b, 1) + );*/ + + return vextq_s32(b, a, 1); +} + +static DRFLAC_INLINE uint32x4_t drflac__valignrq_u32_1(uint32x4_t a, uint32x4_t b) +{ + /* Equivalent to SSE's _mm_alignr_epi8(a, b, 4) */ + + /* Reference */ + /*return drflac__vdupq_n_s32x4( + vgetq_lane_s32(a, 0), + vgetq_lane_s32(b, 3), + vgetq_lane_s32(b, 2), + vgetq_lane_s32(b, 1) + );*/ + + return vextq_u32(b, a, 1); +} + +static DRFLAC_INLINE int32x2_t drflac__vhaddq_s32(int32x4_t x) +{ + /* The sum must end up in position 0. */ + + /* Reference */ + /*return vdupq_n_s32( + vgetq_lane_s32(x, 3) + + vgetq_lane_s32(x, 2) + + vgetq_lane_s32(x, 1) + + vgetq_lane_s32(x, 0) + );*/ + + int32x2_t r = vadd_s32(vget_high_s32(x), vget_low_s32(x)); + return vpadd_s32(r, r); +} + +static DRFLAC_INLINE int64x1_t drflac__vhaddq_s64(int64x2_t x) +{ + return vadd_s64(vget_high_s64(x), vget_low_s64(x)); +} + +static DRFLAC_INLINE int32x4_t drflac__vrevq_s32(int32x4_t x) +{ + /* Reference */ + /*return drflac__vdupq_n_s32x4( + vgetq_lane_s32(x, 0), + vgetq_lane_s32(x, 1), + vgetq_lane_s32(x, 2), + vgetq_lane_s32(x, 3) + );*/ + + return vrev64q_s32(vcombine_s32(vget_high_s32(x), vget_low_s32(x))); +} + +static DRFLAC_INLINE int32x4_t drflac__vnotq_s32(int32x4_t x) +{ + return veorq_s32(x, vdupq_n_s32(0xFFFFFFFF)); +} + +static DRFLAC_INLINE uint32x4_t drflac__vnotq_u32(uint32x4_t x) +{ + return veorq_u32(x, vdupq_n_u32(0xFFFFFFFF)); +} + +static drflac_bool32 drflac__decode_samples_with_residual__rice__neon_32(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +{ + int i; + drflac_uint32 riceParamMask; + drflac_int32* pDecodedSamples = pSamplesOut; + drflac_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3); + drflac_uint32 zeroCountParts[4]; + drflac_uint32 riceParamParts[4]; + int32x4_t coefficients128_0; + int32x4_t coefficients128_4; + int32x4_t coefficients128_8; + int32x4_t samples128_0; + int32x4_t samples128_4; + int32x4_t samples128_8; + uint32x4_t riceParamMask128; + int32x4_t riceParam128; + int32x2_t shift64; + uint32x4_t one128; + + const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; + + riceParamMask = (drflac_uint32)~((~0UL) << riceParam); + riceParamMask128 = vdupq_n_u32(riceParamMask); + + riceParam128 = vdupq_n_s32(riceParam); + shift64 = vdup_n_s32(-shift); /* Negate the shift because we'll be doing a variable shift using vshlq_s32(). */ + one128 = vdupq_n_u32(1); + + /* + Pre-loading the coefficients and prior samples is annoying because we need to ensure we don't try reading more than + what's available in the input buffers. It would be conenient to use a fall-through switch to do this, but this results + in strict aliasing warnings with GCC. To work around this I'm just doing something hacky. This feels a bit convoluted + so I think there's opportunity for this to be simplified. + */ + { + int runningOrder = order; + drflac_int32 tempC[4] = {0, 0, 0, 0}; + drflac_int32 tempS[4] = {0, 0, 0, 0}; + + /* 0 - 3. */ + if (runningOrder >= 4) { + coefficients128_0 = vld1q_s32(coefficients + 0); + samples128_0 = vld1q_s32(pSamplesOut - 4); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: tempC[2] = coefficients[2]; tempS[1] = pSamplesOut[-3]; /* fallthrough */ + case 2: tempC[1] = coefficients[1]; tempS[2] = pSamplesOut[-2]; /* fallthrough */ + case 1: tempC[0] = coefficients[0]; tempS[3] = pSamplesOut[-1]; /* fallthrough */ + } + + coefficients128_0 = vld1q_s32(tempC); + samples128_0 = vld1q_s32(tempS); + runningOrder = 0; + } + + /* 4 - 7 */ + if (runningOrder >= 4) { + coefficients128_4 = vld1q_s32(coefficients + 4); + samples128_4 = vld1q_s32(pSamplesOut - 8); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: tempC[2] = coefficients[6]; tempS[1] = pSamplesOut[-7]; /* fallthrough */ + case 2: tempC[1] = coefficients[5]; tempS[2] = pSamplesOut[-6]; /* fallthrough */ + case 1: tempC[0] = coefficients[4]; tempS[3] = pSamplesOut[-5]; /* fallthrough */ + } + + coefficients128_4 = vld1q_s32(tempC); + samples128_4 = vld1q_s32(tempS); + runningOrder = 0; + } + + /* 8 - 11 */ + if (runningOrder == 4) { + coefficients128_8 = vld1q_s32(coefficients + 8); + samples128_8 = vld1q_s32(pSamplesOut - 12); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: tempC[2] = coefficients[10]; tempS[1] = pSamplesOut[-11]; /* fallthrough */ + case 2: tempC[1] = coefficients[ 9]; tempS[2] = pSamplesOut[-10]; /* fallthrough */ + case 1: tempC[0] = coefficients[ 8]; tempS[3] = pSamplesOut[- 9]; /* fallthrough */ + } + + coefficients128_8 = vld1q_s32(tempC); + samples128_8 = vld1q_s32(tempS); + runningOrder = 0; + } + + /* Coefficients need to be shuffled for our streaming algorithm below to work. Samples are already in the correct order from the loading routine above. */ + coefficients128_0 = drflac__vrevq_s32(coefficients128_0); + coefficients128_4 = drflac__vrevq_s32(coefficients128_4); + coefficients128_8 = drflac__vrevq_s32(coefficients128_8); + } + + /* For this version we are doing one sample at a time. */ + while (pDecodedSamples < pDecodedSamplesEnd) { + int32x4_t prediction128; + int32x2_t prediction64; + uint32x4_t zeroCountPart128; + uint32x4_t riceParamPart128; + + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0]) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[1], &riceParamParts[1]) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[2], &riceParamParts[2]) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[3], &riceParamParts[3])) { + return DRFLAC_FALSE; + } + + zeroCountPart128 = vld1q_u32(zeroCountParts); + riceParamPart128 = vld1q_u32(riceParamParts); + + riceParamPart128 = vandq_u32(riceParamPart128, riceParamMask128); + riceParamPart128 = vorrq_u32(riceParamPart128, vshlq_u32(zeroCountPart128, riceParam128)); + riceParamPart128 = veorq_u32(vshrq_n_u32(riceParamPart128, 1), vaddq_u32(drflac__vnotq_u32(vandq_u32(riceParamPart128, one128)), one128)); + + if (order <= 4) { + for (i = 0; i < 4; i += 1) { + prediction128 = vmulq_s32(coefficients128_0, samples128_0); + + /* Horizontal add and shift. */ + prediction64 = drflac__vhaddq_s32(prediction128); + prediction64 = vshl_s32(prediction64, shift64); + prediction64 = vadd_s32(prediction64, vget_low_s32(vreinterpretq_s32_u32(riceParamPart128))); + + samples128_0 = drflac__valignrq_s32_1(vcombine_s32(prediction64, vdup_n_s32(0)), samples128_0); + riceParamPart128 = drflac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128); + } + } else if (order <= 8) { + for (i = 0; i < 4; i += 1) { + prediction128 = vmulq_s32(coefficients128_4, samples128_4); + prediction128 = vmlaq_s32(prediction128, coefficients128_0, samples128_0); + + /* Horizontal add and shift. */ + prediction64 = drflac__vhaddq_s32(prediction128); + prediction64 = vshl_s32(prediction64, shift64); + prediction64 = vadd_s32(prediction64, vget_low_s32(vreinterpretq_s32_u32(riceParamPart128))); + + samples128_4 = drflac__valignrq_s32_1(samples128_0, samples128_4); + samples128_0 = drflac__valignrq_s32_1(vcombine_s32(prediction64, vdup_n_s32(0)), samples128_0); + riceParamPart128 = drflac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128); + } + } else { + for (i = 0; i < 4; i += 1) { + prediction128 = vmulq_s32(coefficients128_8, samples128_8); + prediction128 = vmlaq_s32(prediction128, coefficients128_4, samples128_4); + prediction128 = vmlaq_s32(prediction128, coefficients128_0, samples128_0); + + /* Horizontal add and shift. */ + prediction64 = drflac__vhaddq_s32(prediction128); + prediction64 = vshl_s32(prediction64, shift64); + prediction64 = vadd_s32(prediction64, vget_low_s32(vreinterpretq_s32_u32(riceParamPart128))); + + samples128_8 = drflac__valignrq_s32_1(samples128_4, samples128_8); + samples128_4 = drflac__valignrq_s32_1(samples128_0, samples128_4); + samples128_0 = drflac__valignrq_s32_1(vcombine_s32(prediction64, vdup_n_s32(0)), samples128_0); + riceParamPart128 = drflac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128); + } + } + + /* We store samples in groups of 4. */ + vst1q_s32(pDecodedSamples, samples128_0); + pDecodedSamples += 4; + } + + /* Make sure we process the last few samples. */ + i = (count & ~3); + while (i < (int)count) { + /* Rice extraction. */ + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0])) { + return DRFLAC_FALSE; + } + + /* Rice reconstruction. */ + riceParamParts[0] &= riceParamMask; + riceParamParts[0] |= (zeroCountParts[0] << riceParam); + riceParamParts[0] = (riceParamParts[0] >> 1) ^ t[riceParamParts[0] & 0x01]; + + /* Sample reconstruction. */ + pDecodedSamples[0] = riceParamParts[0] + drflac__calculate_prediction_32(order, shift, coefficients, pDecodedSamples); + + i += 1; + pDecodedSamples += 1; + } + + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__decode_samples_with_residual__rice__neon_64(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +{ + int i; + drflac_uint32 riceParamMask; + drflac_int32* pDecodedSamples = pSamplesOut; + drflac_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3); + drflac_uint32 zeroCountParts[4]; + drflac_uint32 riceParamParts[4]; + int32x4_t coefficients128_0; + int32x4_t coefficients128_4; + int32x4_t coefficients128_8; + int32x4_t samples128_0; + int32x4_t samples128_4; + int32x4_t samples128_8; + uint32x4_t riceParamMask128; + int32x4_t riceParam128; + int64x1_t shift64; + uint32x4_t one128; + int64x2_t prediction128 = { 0 }; + uint32x4_t zeroCountPart128; + uint32x4_t riceParamPart128; + + const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; + + riceParamMask = (drflac_uint32)~((~0UL) << riceParam); + riceParamMask128 = vdupq_n_u32(riceParamMask); + + riceParam128 = vdupq_n_s32(riceParam); + shift64 = vdup_n_s64(-shift); /* Negate the shift because we'll be doing a variable shift using vshlq_s32(). */ + one128 = vdupq_n_u32(1); + + /* + Pre-loading the coefficients and prior samples is annoying because we need to ensure we don't try reading more than + what's available in the input buffers. It would be convenient to use a fall-through switch to do this, but this results + in strict aliasing warnings with GCC. To work around this I'm just doing something hacky. This feels a bit convoluted + so I think there's opportunity for this to be simplified. + */ + { + int runningOrder = order; + drflac_int32 tempC[4] = {0, 0, 0, 0}; + drflac_int32 tempS[4] = {0, 0, 0, 0}; + + /* 0 - 3. */ + if (runningOrder >= 4) { + coefficients128_0 = vld1q_s32(coefficients + 0); + samples128_0 = vld1q_s32(pSamplesOut - 4); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: tempC[2] = coefficients[2]; tempS[1] = pSamplesOut[-3]; /* fallthrough */ + case 2: tempC[1] = coefficients[1]; tempS[2] = pSamplesOut[-2]; /* fallthrough */ + case 1: tempC[0] = coefficients[0]; tempS[3] = pSamplesOut[-1]; /* fallthrough */ + } + + coefficients128_0 = vld1q_s32(tempC); + samples128_0 = vld1q_s32(tempS); + runningOrder = 0; + } + + /* 4 - 7 */ + if (runningOrder >= 4) { + coefficients128_4 = vld1q_s32(coefficients + 4); + samples128_4 = vld1q_s32(pSamplesOut - 8); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: tempC[2] = coefficients[6]; tempS[1] = pSamplesOut[-7]; /* fallthrough */ + case 2: tempC[1] = coefficients[5]; tempS[2] = pSamplesOut[-6]; /* fallthrough */ + case 1: tempC[0] = coefficients[4]; tempS[3] = pSamplesOut[-5]; /* fallthrough */ + } + + coefficients128_4 = vld1q_s32(tempC); + samples128_4 = vld1q_s32(tempS); + runningOrder = 0; + } + + /* 8 - 11 */ + if (runningOrder == 4) { + coefficients128_8 = vld1q_s32(coefficients + 8); + samples128_8 = vld1q_s32(pSamplesOut - 12); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: tempC[2] = coefficients[10]; tempS[1] = pSamplesOut[-11]; /* fallthrough */ + case 2: tempC[1] = coefficients[ 9]; tempS[2] = pSamplesOut[-10]; /* fallthrough */ + case 1: tempC[0] = coefficients[ 8]; tempS[3] = pSamplesOut[- 9]; /* fallthrough */ + } + + coefficients128_8 = vld1q_s32(tempC); + samples128_8 = vld1q_s32(tempS); + runningOrder = 0; + } + + /* Coefficients need to be shuffled for our streaming algorithm below to work. Samples are already in the correct order from the loading routine above. */ + coefficients128_0 = drflac__vrevq_s32(coefficients128_0); + coefficients128_4 = drflac__vrevq_s32(coefficients128_4); + coefficients128_8 = drflac__vrevq_s32(coefficients128_8); + } + + /* For this version we are doing one sample at a time. */ + while (pDecodedSamples < pDecodedSamplesEnd) { + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0]) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[1], &riceParamParts[1]) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[2], &riceParamParts[2]) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[3], &riceParamParts[3])) { + return DRFLAC_FALSE; + } + + zeroCountPart128 = vld1q_u32(zeroCountParts); + riceParamPart128 = vld1q_u32(riceParamParts); + + riceParamPart128 = vandq_u32(riceParamPart128, riceParamMask128); + riceParamPart128 = vorrq_u32(riceParamPart128, vshlq_u32(zeroCountPart128, riceParam128)); + riceParamPart128 = veorq_u32(vshrq_n_u32(riceParamPart128, 1), vaddq_u32(drflac__vnotq_u32(vandq_u32(riceParamPart128, one128)), one128)); + + for (i = 0; i < 4; i += 1) { + int64x1_t prediction64; + + prediction128 = veorq_s64(prediction128, prediction128); /* Reset to 0. */ + switch (order) + { + case 12: + case 11: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_low_s32(coefficients128_8), vget_low_s32(samples128_8))); + case 10: + case 9: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_high_s32(coefficients128_8), vget_high_s32(samples128_8))); + case 8: + case 7: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_low_s32(coefficients128_4), vget_low_s32(samples128_4))); + case 6: + case 5: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_high_s32(coefficients128_4), vget_high_s32(samples128_4))); + case 4: + case 3: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_low_s32(coefficients128_0), vget_low_s32(samples128_0))); + case 2: + case 1: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_high_s32(coefficients128_0), vget_high_s32(samples128_0))); + } + + /* Horizontal add and shift. */ + prediction64 = drflac__vhaddq_s64(prediction128); + prediction64 = vshl_s64(prediction64, shift64); + prediction64 = vadd_s64(prediction64, vdup_n_s64(vgetq_lane_u32(riceParamPart128, 0))); + + /* Our value should be sitting in prediction64[0]. We need to combine this with our SSE samples. */ + samples128_8 = drflac__valignrq_s32_1(samples128_4, samples128_8); + samples128_4 = drflac__valignrq_s32_1(samples128_0, samples128_4); + samples128_0 = drflac__valignrq_s32_1(vcombine_s32(vreinterpret_s32_s64(prediction64), vdup_n_s32(0)), samples128_0); + + /* Slide our rice parameter down so that the value in position 0 contains the next one to process. */ + riceParamPart128 = drflac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128); + } + + /* We store samples in groups of 4. */ + vst1q_s32(pDecodedSamples, samples128_0); + pDecodedSamples += 4; + } + + /* Make sure we process the last few samples. */ + i = (count & ~3); + while (i < (int)count) { + /* Rice extraction. */ + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0])) { + return DRFLAC_FALSE; + } + + /* Rice reconstruction. */ + riceParamParts[0] &= riceParamMask; + riceParamParts[0] |= (zeroCountParts[0] << riceParam); + riceParamParts[0] = (riceParamParts[0] >> 1) ^ t[riceParamParts[0] & 0x01]; + + /* Sample reconstruction. */ + pDecodedSamples[0] = riceParamParts[0] + drflac__calculate_prediction_64(order, shift, coefficients, pDecodedSamples); + + i += 1; + pDecodedSamples += 1; + } + + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__decode_samples_with_residual__rice__neon(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +{ + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pSamplesOut != NULL); + + /* In my testing the order is rarely > 12, so in this case I'm going to simplify the NEON implementation by only handling order <= 12. */ + if (lpcOrder > 0 && lpcOrder <= 12) { + if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { + return drflac__decode_samples_with_residual__rice__neon_64(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); + } else { + return drflac__decode_samples_with_residual__rice__neon_32(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); + } + } else { + return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); + } +} +#endif + +static drflac_bool32 drflac__decode_samples_with_residual__rice(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +{ +#if defined(DRFLAC_SUPPORT_SSE41) + if (drflac__gIsSSE41Supported) { + return drflac__decode_samples_with_residual__rice__sse41(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); + } else +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported) { + return drflac__decode_samples_with_residual__rice__neon(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); + } else +#endif + { + /* Scalar fallback. */ + #if 0 + return drflac__decode_samples_with_residual__rice__reference(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); + #else + return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); + #endif + } +} + +/* Reads and seeks past a string of residual values as Rice codes. The decoder should be sitting on the first bit of the Rice codes. */ +static drflac_bool32 drflac__read_and_seek_residual__rice(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam) +{ + drflac_uint32 i; + + DRFLAC_ASSERT(bs != NULL); + + for (i = 0; i < count; ++i) { + if (!drflac__seek_rice_parts(bs, riceParam)) { + return DRFLAC_FALSE; + } + } + + return DRFLAC_TRUE; +} + +#if defined(__clang__) +__attribute__((no_sanitize("signed-integer-overflow"))) +#endif +static drflac_bool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 unencodedBitsPerSample, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +{ + drflac_uint32 i; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(unencodedBitsPerSample <= 31); /* <-- unencodedBitsPerSample is a 5 bit number, so cannot exceed 31. */ + DRFLAC_ASSERT(pSamplesOut != NULL); + + for (i = 0; i < count; ++i) { + if (unencodedBitsPerSample > 0) { + if (!drflac__read_int32(bs, unencodedBitsPerSample, pSamplesOut + i)) { + return DRFLAC_FALSE; + } + } else { + pSamplesOut[i] = 0; + } + + if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { + pSamplesOut[i] += drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + i); + } else { + pSamplesOut[i] += drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + i); + } + } + + return DRFLAC_TRUE; +} + + +/* +Reads and decodes the residual for the sub-frame the decoder is currently sitting on. This function should be called +when the decoder is sitting at the very start of the RESIDUAL block. The first residuals will be ignored. The + and parameters are used to determine how many residual values need to be decoded. +*/ +static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 blockSize, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pDecodedSamples) +{ + drflac_uint8 residualMethod; + drflac_uint8 partitionOrder; + drflac_uint32 samplesInPartition; + drflac_uint32 partitionsRemaining; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(blockSize != 0); + DRFLAC_ASSERT(pDecodedSamples != NULL); /* <-- Should we allow NULL, in which case we just seek past the residual rather than do a full decode? */ + + if (!drflac__read_uint8(bs, 2, &residualMethod)) { + return DRFLAC_FALSE; + } + + if (residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE && residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) { + return DRFLAC_FALSE; /* Unknown or unsupported residual coding method. */ + } + + /* Ignore the first values. */ + pDecodedSamples += lpcOrder; + + if (!drflac__read_uint8(bs, 4, &partitionOrder)) { + return DRFLAC_FALSE; + } + + /* + From the FLAC spec: + The Rice partition order in a Rice-coded residual section must be less than or equal to 8. + */ + if (partitionOrder > 8) { + return DRFLAC_FALSE; + } + + /* Validation check. */ + if ((blockSize / (1 << partitionOrder)) < lpcOrder) { + return DRFLAC_FALSE; + } + + samplesInPartition = (blockSize / (1 << partitionOrder)) - lpcOrder; + partitionsRemaining = (1 << partitionOrder); + for (;;) { + drflac_uint8 riceParam = 0; + if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE) { + if (!drflac__read_uint8(bs, 4, &riceParam)) { + return DRFLAC_FALSE; + } + if (riceParam == 15) { + riceParam = 0xFF; + } + } else if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) { + if (!drflac__read_uint8(bs, 5, &riceParam)) { + return DRFLAC_FALSE; + } + if (riceParam == 31) { + riceParam = 0xFF; + } + } + + if (riceParam != 0xFF) { + if (!drflac__decode_samples_with_residual__rice(bs, bitsPerSample, samplesInPartition, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pDecodedSamples)) { + return DRFLAC_FALSE; + } + } else { + drflac_uint8 unencodedBitsPerSample = 0; + if (!drflac__read_uint8(bs, 5, &unencodedBitsPerSample)) { + return DRFLAC_FALSE; + } + + if (!drflac__decode_samples_with_residual__unencoded(bs, bitsPerSample, samplesInPartition, unencodedBitsPerSample, lpcOrder, lpcShift, lpcPrecision, coefficients, pDecodedSamples)) { + return DRFLAC_FALSE; + } + } + + pDecodedSamples += samplesInPartition; + + if (partitionsRemaining == 1) { + break; + } + + partitionsRemaining -= 1; + + if (partitionOrder != 0) { + samplesInPartition = blockSize / (1 << partitionOrder); + } + } + + return DRFLAC_TRUE; +} + +/* +Reads and seeks past the residual for the sub-frame the decoder is currently sitting on. This function should be called +when the decoder is sitting at the very start of the RESIDUAL block. The first residuals will be set to 0. The + and parameters are used to determine how many residual values need to be decoded. +*/ +static drflac_bool32 drflac__read_and_seek_residual(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 order) +{ + drflac_uint8 residualMethod; + drflac_uint8 partitionOrder; + drflac_uint32 samplesInPartition; + drflac_uint32 partitionsRemaining; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(blockSize != 0); + + if (!drflac__read_uint8(bs, 2, &residualMethod)) { + return DRFLAC_FALSE; + } + + if (residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE && residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) { + return DRFLAC_FALSE; /* Unknown or unsupported residual coding method. */ + } + + if (!drflac__read_uint8(bs, 4, &partitionOrder)) { + return DRFLAC_FALSE; + } + + /* + From the FLAC spec: + The Rice partition order in a Rice-coded residual section must be less than or equal to 8. + */ + if (partitionOrder > 8) { + return DRFLAC_FALSE; + } + + /* Validation check. */ + if ((blockSize / (1 << partitionOrder)) <= order) { + return DRFLAC_FALSE; + } + + samplesInPartition = (blockSize / (1 << partitionOrder)) - order; + partitionsRemaining = (1 << partitionOrder); + for (;;) + { + drflac_uint8 riceParam = 0; + if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE) { + if (!drflac__read_uint8(bs, 4, &riceParam)) { + return DRFLAC_FALSE; + } + if (riceParam == 15) { + riceParam = 0xFF; + } + } else if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) { + if (!drflac__read_uint8(bs, 5, &riceParam)) { + return DRFLAC_FALSE; + } + if (riceParam == 31) { + riceParam = 0xFF; + } + } + + if (riceParam != 0xFF) { + if (!drflac__read_and_seek_residual__rice(bs, samplesInPartition, riceParam)) { + return DRFLAC_FALSE; + } + } else { + drflac_uint8 unencodedBitsPerSample = 0; + if (!drflac__read_uint8(bs, 5, &unencodedBitsPerSample)) { + return DRFLAC_FALSE; + } + + if (!drflac__seek_bits(bs, unencodedBitsPerSample * samplesInPartition)) { + return DRFLAC_FALSE; + } + } + + + if (partitionsRemaining == 1) { + break; + } + + partitionsRemaining -= 1; + samplesInPartition = blockSize / (1 << partitionOrder); + } + + return DRFLAC_TRUE; +} + + +static drflac_bool32 drflac__decode_samples__constant(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 subframeBitsPerSample, drflac_int32* pDecodedSamples) +{ + drflac_uint32 i; + + /* Only a single sample needs to be decoded here. */ + drflac_int32 sample; + if (!drflac__read_int32(bs, subframeBitsPerSample, &sample)) { + return DRFLAC_FALSE; + } + + /* + We don't really need to expand this, but it does simplify the process of reading samples. If this becomes a performance issue (unlikely) + we'll want to look at a more efficient way. + */ + for (i = 0; i < blockSize; ++i) { + pDecodedSamples[i] = sample; + } + + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__decode_samples__verbatim(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 subframeBitsPerSample, drflac_int32* pDecodedSamples) +{ + drflac_uint32 i; + + for (i = 0; i < blockSize; ++i) { + drflac_int32 sample; + if (!drflac__read_int32(bs, subframeBitsPerSample, &sample)) { + return DRFLAC_FALSE; + } + + pDecodedSamples[i] = sample; + } + + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__decode_samples__fixed(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 subframeBitsPerSample, drflac_uint8 lpcOrder, drflac_int32* pDecodedSamples) +{ + drflac_uint32 i; + + static drflac_int32 lpcCoefficientsTable[5][4] = { + {0, 0, 0, 0}, + {1, 0, 0, 0}, + {2, -1, 0, 0}, + {3, -3, 1, 0}, + {4, -6, 4, -1} + }; + + /* Warm up samples and coefficients. */ + for (i = 0; i < lpcOrder; ++i) { + drflac_int32 sample; + if (!drflac__read_int32(bs, subframeBitsPerSample, &sample)) { + return DRFLAC_FALSE; + } + + pDecodedSamples[i] = sample; + } + + if (!drflac__decode_samples_with_residual(bs, subframeBitsPerSample, blockSize, lpcOrder, 0, 4, lpcCoefficientsTable[lpcOrder], pDecodedSamples)) { + return DRFLAC_FALSE; + } + + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__decode_samples__lpc(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 bitsPerSample, drflac_uint8 lpcOrder, drflac_int32* pDecodedSamples) +{ + drflac_uint8 i; + drflac_uint8 lpcPrecision; + drflac_int8 lpcShift; + drflac_int32 coefficients[32]; + + /* Warm up samples. */ + for (i = 0; i < lpcOrder; ++i) { + drflac_int32 sample; + if (!drflac__read_int32(bs, bitsPerSample, &sample)) { + return DRFLAC_FALSE; + } + + pDecodedSamples[i] = sample; + } + + if (!drflac__read_uint8(bs, 4, &lpcPrecision)) { + return DRFLAC_FALSE; + } + if (lpcPrecision == 15) { + return DRFLAC_FALSE; /* Invalid. */ + } + lpcPrecision += 1; + + if (!drflac__read_int8(bs, 5, &lpcShift)) { + return DRFLAC_FALSE; + } + + /* + From the FLAC specification: + + Quantized linear predictor coefficient shift needed in bits (NOTE: this number is signed two's-complement) + + Emphasis on the "signed two's-complement". In practice there does not seem to be any encoders nor decoders supporting negative shifts. For now dr_flac is + not going to support negative shifts as I don't have any reference files. However, when a reference file comes through I will consider adding support. + */ + if (lpcShift < 0) { + return DRFLAC_FALSE; + } + + DRFLAC_ZERO_MEMORY(coefficients, sizeof(coefficients)); + for (i = 0; i < lpcOrder; ++i) { + if (!drflac__read_int32(bs, lpcPrecision, coefficients + i)) { + return DRFLAC_FALSE; + } + } + + if (!drflac__decode_samples_with_residual(bs, bitsPerSample, blockSize, lpcOrder, lpcShift, lpcPrecision, coefficients, pDecodedSamples)) { + return DRFLAC_FALSE; + } + + return DRFLAC_TRUE; +} + + +static drflac_bool32 drflac__read_next_flac_frame_header(drflac_bs* bs, drflac_uint8 streaminfoBitsPerSample, drflac_frame_header* header) +{ + const drflac_uint32 sampleRateTable[12] = {0, 88200, 176400, 192000, 8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000}; + const drflac_uint8 bitsPerSampleTable[8] = {0, 8, 12, (drflac_uint8)-1, 16, 20, 24, (drflac_uint8)-1}; /* -1 = reserved. */ + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(header != NULL); + + /* Keep looping until we find a valid sync code. */ + for (;;) { + drflac_uint8 crc8 = 0xCE; /* 0xCE = drflac_crc8(0, 0x3FFE, 14); */ + drflac_uint8 reserved = 0; + drflac_uint8 blockingStrategy = 0; + drflac_uint8 blockSize = 0; + drflac_uint8 sampleRate = 0; + drflac_uint8 channelAssignment = 0; + drflac_uint8 bitsPerSample = 0; + drflac_bool32 isVariableBlockSize; + + if (!drflac__find_and_seek_to_next_sync_code(bs)) { + return DRFLAC_FALSE; + } + + if (!drflac__read_uint8(bs, 1, &reserved)) { + return DRFLAC_FALSE; + } + if (reserved == 1) { + continue; + } + crc8 = drflac_crc8(crc8, reserved, 1); + + if (!drflac__read_uint8(bs, 1, &blockingStrategy)) { + return DRFLAC_FALSE; + } + crc8 = drflac_crc8(crc8, blockingStrategy, 1); + + if (!drflac__read_uint8(bs, 4, &blockSize)) { + return DRFLAC_FALSE; + } + if (blockSize == 0) { + continue; + } + crc8 = drflac_crc8(crc8, blockSize, 4); + + if (!drflac__read_uint8(bs, 4, &sampleRate)) { + return DRFLAC_FALSE; + } + crc8 = drflac_crc8(crc8, sampleRate, 4); + + if (!drflac__read_uint8(bs, 4, &channelAssignment)) { + return DRFLAC_FALSE; + } + if (channelAssignment > 10) { + continue; + } + crc8 = drflac_crc8(crc8, channelAssignment, 4); + + if (!drflac__read_uint8(bs, 3, &bitsPerSample)) { + return DRFLAC_FALSE; + } + if (bitsPerSample == 3 || bitsPerSample == 7) { + continue; + } + crc8 = drflac_crc8(crc8, bitsPerSample, 3); + + + if (!drflac__read_uint8(bs, 1, &reserved)) { + return DRFLAC_FALSE; + } + if (reserved == 1) { + continue; + } + crc8 = drflac_crc8(crc8, reserved, 1); + + + isVariableBlockSize = blockingStrategy == 1; + if (isVariableBlockSize) { + drflac_uint64 pcmFrameNumber; + drflac_result result = drflac__read_utf8_coded_number(bs, &pcmFrameNumber, &crc8); + if (result != DRFLAC_SUCCESS) { + if (result == DRFLAC_AT_END) { + return DRFLAC_FALSE; + } else { + continue; + } + } + header->flacFrameNumber = 0; + header->pcmFrameNumber = pcmFrameNumber; + } else { + drflac_uint64 flacFrameNumber = 0; + drflac_result result = drflac__read_utf8_coded_number(bs, &flacFrameNumber, &crc8); + if (result != DRFLAC_SUCCESS) { + if (result == DRFLAC_AT_END) { + return DRFLAC_FALSE; + } else { + continue; + } + } + header->flacFrameNumber = (drflac_uint32)flacFrameNumber; /* <-- Safe cast. */ + header->pcmFrameNumber = 0; + } + + + DRFLAC_ASSERT(blockSize > 0); + if (blockSize == 1) { + header->blockSizeInPCMFrames = 192; + } else if (blockSize <= 5) { + DRFLAC_ASSERT(blockSize >= 2); + header->blockSizeInPCMFrames = 576 * (1 << (blockSize - 2)); + } else if (blockSize == 6) { + if (!drflac__read_uint16(bs, 8, &header->blockSizeInPCMFrames)) { + return DRFLAC_FALSE; + } + crc8 = drflac_crc8(crc8, header->blockSizeInPCMFrames, 8); + header->blockSizeInPCMFrames += 1; + } else if (blockSize == 7) { + if (!drflac__read_uint16(bs, 16, &header->blockSizeInPCMFrames)) { + return DRFLAC_FALSE; + } + crc8 = drflac_crc8(crc8, header->blockSizeInPCMFrames, 16); + if (header->blockSizeInPCMFrames == 0xFFFF) { + return DRFLAC_FALSE; /* Frame is too big. This is the size of the frame minus 1. The STREAMINFO block defines the max block size which is 16-bits. Adding one will make it 17 bits and therefore too big. */ + } + header->blockSizeInPCMFrames += 1; + } else { + DRFLAC_ASSERT(blockSize >= 8); + header->blockSizeInPCMFrames = 256 * (1 << (blockSize - 8)); + } + + + if (sampleRate <= 11) { + header->sampleRate = sampleRateTable[sampleRate]; + } else if (sampleRate == 12) { + if (!drflac__read_uint32(bs, 8, &header->sampleRate)) { + return DRFLAC_FALSE; + } + crc8 = drflac_crc8(crc8, header->sampleRate, 8); + header->sampleRate *= 1000; + } else if (sampleRate == 13) { + if (!drflac__read_uint32(bs, 16, &header->sampleRate)) { + return DRFLAC_FALSE; + } + crc8 = drflac_crc8(crc8, header->sampleRate, 16); + } else if (sampleRate == 14) { + if (!drflac__read_uint32(bs, 16, &header->sampleRate)) { + return DRFLAC_FALSE; + } + crc8 = drflac_crc8(crc8, header->sampleRate, 16); + header->sampleRate *= 10; + } else { + continue; /* Invalid. Assume an invalid block. */ + } + + + header->channelAssignment = channelAssignment; + + header->bitsPerSample = bitsPerSampleTable[bitsPerSample]; + if (header->bitsPerSample == 0) { + header->bitsPerSample = streaminfoBitsPerSample; + } + + if (header->bitsPerSample != streaminfoBitsPerSample) { + /* If this subframe has a different bitsPerSample then streaminfo or the first frame, reject it */ + return DRFLAC_FALSE; + } + + if (!drflac__read_uint8(bs, 8, &header->crc8)) { + return DRFLAC_FALSE; + } + +#ifndef DR_FLAC_NO_CRC + if (header->crc8 != crc8) { + continue; /* CRC mismatch. Loop back to the top and find the next sync code. */ + } +#endif + return DRFLAC_TRUE; + } +} + +static drflac_bool32 drflac__read_subframe_header(drflac_bs* bs, drflac_subframe* pSubframe) +{ + drflac_uint8 header; + int type; + + if (!drflac__read_uint8(bs, 8, &header)) { + return DRFLAC_FALSE; + } + + /* First bit should always be 0. */ + if ((header & 0x80) != 0) { + return DRFLAC_FALSE; + } + + type = (header & 0x7E) >> 1; + if (type == 0) { + pSubframe->subframeType = DRFLAC_SUBFRAME_CONSTANT; + } else if (type == 1) { + pSubframe->subframeType = DRFLAC_SUBFRAME_VERBATIM; + } else { + if ((type & 0x20) != 0) { + pSubframe->subframeType = DRFLAC_SUBFRAME_LPC; + pSubframe->lpcOrder = (drflac_uint8)(type & 0x1F) + 1; + } else if ((type & 0x08) != 0) { + pSubframe->subframeType = DRFLAC_SUBFRAME_FIXED; + pSubframe->lpcOrder = (drflac_uint8)(type & 0x07); + if (pSubframe->lpcOrder > 4) { + pSubframe->subframeType = DRFLAC_SUBFRAME_RESERVED; + pSubframe->lpcOrder = 0; + } + } else { + pSubframe->subframeType = DRFLAC_SUBFRAME_RESERVED; + } + } + + if (pSubframe->subframeType == DRFLAC_SUBFRAME_RESERVED) { + return DRFLAC_FALSE; + } + + /* Wasted bits per sample. */ + pSubframe->wastedBitsPerSample = 0; + if ((header & 0x01) == 1) { + unsigned int wastedBitsPerSample; + if (!drflac__seek_past_next_set_bit(bs, &wastedBitsPerSample)) { + return DRFLAC_FALSE; + } + pSubframe->wastedBitsPerSample = (drflac_uint8)wastedBitsPerSample + 1; + } + + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex, drflac_int32* pDecodedSamplesOut) +{ + drflac_subframe* pSubframe; + drflac_uint32 subframeBitsPerSample; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(frame != NULL); + + pSubframe = frame->subframes + subframeIndex; + if (!drflac__read_subframe_header(bs, pSubframe)) { + return DRFLAC_FALSE; + } + + /* Side channels require an extra bit per sample. Took a while to figure that one out... */ + subframeBitsPerSample = frame->header.bitsPerSample; + if ((frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE || frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE) && subframeIndex == 1) { + subframeBitsPerSample += 1; + } else if (frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE && subframeIndex == 0) { + subframeBitsPerSample += 1; + } + + if (subframeBitsPerSample > 32) { + /* libFLAC and ffmpeg reject 33-bit subframes as well */ + return DRFLAC_FALSE; + } + + /* Need to handle wasted bits per sample. */ + if (pSubframe->wastedBitsPerSample >= subframeBitsPerSample) { + return DRFLAC_FALSE; + } + subframeBitsPerSample -= pSubframe->wastedBitsPerSample; + + pSubframe->pSamplesS32 = pDecodedSamplesOut; + + switch (pSubframe->subframeType) + { + case DRFLAC_SUBFRAME_CONSTANT: + { + drflac__decode_samples__constant(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->pSamplesS32); + } break; + + case DRFLAC_SUBFRAME_VERBATIM: + { + drflac__decode_samples__verbatim(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->pSamplesS32); + } break; + + case DRFLAC_SUBFRAME_FIXED: + { + drflac__decode_samples__fixed(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->lpcOrder, pSubframe->pSamplesS32); + } break; + + case DRFLAC_SUBFRAME_LPC: + { + drflac__decode_samples__lpc(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->lpcOrder, pSubframe->pSamplesS32); + } break; + + default: return DRFLAC_FALSE; + } + + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__seek_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex) +{ + drflac_subframe* pSubframe; + drflac_uint32 subframeBitsPerSample; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(frame != NULL); + + pSubframe = frame->subframes + subframeIndex; + if (!drflac__read_subframe_header(bs, pSubframe)) { + return DRFLAC_FALSE; + } + + /* Side channels require an extra bit per sample. Took a while to figure that one out... */ + subframeBitsPerSample = frame->header.bitsPerSample; + if ((frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE || frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE) && subframeIndex == 1) { + subframeBitsPerSample += 1; + } else if (frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE && subframeIndex == 0) { + subframeBitsPerSample += 1; + } + + /* Need to handle wasted bits per sample. */ + if (pSubframe->wastedBitsPerSample >= subframeBitsPerSample) { + return DRFLAC_FALSE; + } + subframeBitsPerSample -= pSubframe->wastedBitsPerSample; + + pSubframe->pSamplesS32 = NULL; + + switch (pSubframe->subframeType) + { + case DRFLAC_SUBFRAME_CONSTANT: + { + if (!drflac__seek_bits(bs, subframeBitsPerSample)) { + return DRFLAC_FALSE; + } + } break; + + case DRFLAC_SUBFRAME_VERBATIM: + { + unsigned int bitsToSeek = frame->header.blockSizeInPCMFrames * subframeBitsPerSample; + if (!drflac__seek_bits(bs, bitsToSeek)) { + return DRFLAC_FALSE; + } + } break; + + case DRFLAC_SUBFRAME_FIXED: + { + unsigned int bitsToSeek = pSubframe->lpcOrder * subframeBitsPerSample; + if (!drflac__seek_bits(bs, bitsToSeek)) { + return DRFLAC_FALSE; + } + + if (!drflac__read_and_seek_residual(bs, frame->header.blockSizeInPCMFrames, pSubframe->lpcOrder)) { + return DRFLAC_FALSE; + } + } break; + + case DRFLAC_SUBFRAME_LPC: + { + drflac_uint8 lpcPrecision; + + unsigned int bitsToSeek = pSubframe->lpcOrder * subframeBitsPerSample; + if (!drflac__seek_bits(bs, bitsToSeek)) { + return DRFLAC_FALSE; + } + + if (!drflac__read_uint8(bs, 4, &lpcPrecision)) { + return DRFLAC_FALSE; + } + if (lpcPrecision == 15) { + return DRFLAC_FALSE; /* Invalid. */ + } + lpcPrecision += 1; + + + bitsToSeek = (pSubframe->lpcOrder * lpcPrecision) + 5; /* +5 for shift. */ + if (!drflac__seek_bits(bs, bitsToSeek)) { + return DRFLAC_FALSE; + } + + if (!drflac__read_and_seek_residual(bs, frame->header.blockSizeInPCMFrames, pSubframe->lpcOrder)) { + return DRFLAC_FALSE; + } + } break; + + default: return DRFLAC_FALSE; + } + + return DRFLAC_TRUE; +} + + +static DRFLAC_INLINE drflac_uint8 drflac__get_channel_count_from_channel_assignment(drflac_int8 channelAssignment) +{ + drflac_uint8 lookup[] = {1, 2, 3, 4, 5, 6, 7, 8, 2, 2, 2}; + + DRFLAC_ASSERT(channelAssignment <= 10); + return lookup[channelAssignment]; +} + +static drflac_result drflac__decode_flac_frame(drflac* pFlac) +{ + int channelCount; + int i; + drflac_uint8 paddingSizeInBits; + drflac_uint16 desiredCRC16; +#ifndef DR_FLAC_NO_CRC + drflac_uint16 actualCRC16; +#endif + + /* This function should be called while the stream is sitting on the first byte after the frame header. */ + DRFLAC_ZERO_MEMORY(pFlac->currentFLACFrame.subframes, sizeof(pFlac->currentFLACFrame.subframes)); + + /* The frame block size must never be larger than the maximum block size defined by the FLAC stream. */ + if (pFlac->currentFLACFrame.header.blockSizeInPCMFrames > pFlac->maxBlockSizeInPCMFrames) { + return DRFLAC_ERROR; + } + + /* The number of channels in the frame must match the channel count from the STREAMINFO block. */ + channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment); + if (channelCount != (int)pFlac->channels) { + return DRFLAC_ERROR; + } + + for (i = 0; i < channelCount; ++i) { + if (!drflac__decode_subframe(&pFlac->bs, &pFlac->currentFLACFrame, i, pFlac->pDecodedSamples + (pFlac->currentFLACFrame.header.blockSizeInPCMFrames * i))) { + return DRFLAC_ERROR; + } + } + + paddingSizeInBits = (drflac_uint8)(DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7); + if (paddingSizeInBits > 0) { + drflac_uint8 padding = 0; + if (!drflac__read_uint8(&pFlac->bs, paddingSizeInBits, &padding)) { + return DRFLAC_AT_END; + } + } + +#ifndef DR_FLAC_NO_CRC + actualCRC16 = drflac__flush_crc16(&pFlac->bs); +#endif + if (!drflac__read_uint16(&pFlac->bs, 16, &desiredCRC16)) { + return DRFLAC_AT_END; + } + +#ifndef DR_FLAC_NO_CRC + if (actualCRC16 != desiredCRC16) { + return DRFLAC_CRC_MISMATCH; /* CRC mismatch. */ + } +#endif + + pFlac->currentFLACFrame.pcmFramesRemaining = pFlac->currentFLACFrame.header.blockSizeInPCMFrames; + + return DRFLAC_SUCCESS; +} + +static drflac_result drflac__seek_flac_frame(drflac* pFlac) +{ + int channelCount; + int i; + drflac_uint16 desiredCRC16; +#ifndef DR_FLAC_NO_CRC + drflac_uint16 actualCRC16; +#endif + + channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment); + for (i = 0; i < channelCount; ++i) { + if (!drflac__seek_subframe(&pFlac->bs, &pFlac->currentFLACFrame, i)) { + return DRFLAC_ERROR; + } + } + + /* Padding. */ + if (!drflac__seek_bits(&pFlac->bs, DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7)) { + return DRFLAC_ERROR; + } + + /* CRC. */ +#ifndef DR_FLAC_NO_CRC + actualCRC16 = drflac__flush_crc16(&pFlac->bs); +#endif + if (!drflac__read_uint16(&pFlac->bs, 16, &desiredCRC16)) { + return DRFLAC_AT_END; + } + +#ifndef DR_FLAC_NO_CRC + if (actualCRC16 != desiredCRC16) { + return DRFLAC_CRC_MISMATCH; /* CRC mismatch. */ + } +#endif + + return DRFLAC_SUCCESS; +} + +static drflac_bool32 drflac__read_and_decode_next_flac_frame(drflac* pFlac) +{ + DRFLAC_ASSERT(pFlac != NULL); + + for (;;) { + drflac_result result; + + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; + } + + result = drflac__decode_flac_frame(pFlac); + if (result != DRFLAC_SUCCESS) { + if (result == DRFLAC_CRC_MISMATCH) { + continue; /* CRC mismatch. Skip to the next frame. */ + } else { + return DRFLAC_FALSE; + } + } + + return DRFLAC_TRUE; + } +} + +static void drflac__get_pcm_frame_range_of_current_flac_frame(drflac* pFlac, drflac_uint64* pFirstPCMFrame, drflac_uint64* pLastPCMFrame) +{ + drflac_uint64 firstPCMFrame; + drflac_uint64 lastPCMFrame; + + DRFLAC_ASSERT(pFlac != NULL); + + firstPCMFrame = pFlac->currentFLACFrame.header.pcmFrameNumber; + if (firstPCMFrame == 0) { + firstPCMFrame = ((drflac_uint64)pFlac->currentFLACFrame.header.flacFrameNumber) * pFlac->maxBlockSizeInPCMFrames; + } + + lastPCMFrame = firstPCMFrame + pFlac->currentFLACFrame.header.blockSizeInPCMFrames; + if (lastPCMFrame > 0) { + lastPCMFrame -= 1; /* Needs to be zero based. */ + } + + if (pFirstPCMFrame) { + *pFirstPCMFrame = firstPCMFrame; + } + if (pLastPCMFrame) { + *pLastPCMFrame = lastPCMFrame; + } +} + +static drflac_bool32 drflac__seek_to_first_frame(drflac* pFlac) +{ + drflac_bool32 result; + + DRFLAC_ASSERT(pFlac != NULL); + + result = drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes); + + DRFLAC_ZERO_MEMORY(&pFlac->currentFLACFrame, sizeof(pFlac->currentFLACFrame)); + pFlac->currentPCMFrame = 0; + + return result; +} + +static DRFLAC_INLINE drflac_result drflac__seek_to_next_flac_frame(drflac* pFlac) +{ + /* This function should only ever be called while the decoder is sitting on the first byte past the FRAME_HEADER section. */ + DRFLAC_ASSERT(pFlac != NULL); + return drflac__seek_flac_frame(pFlac); +} + + +static drflac_uint64 drflac__seek_forward_by_pcm_frames(drflac* pFlac, drflac_uint64 pcmFramesToSeek) +{ + drflac_uint64 pcmFramesRead = 0; + while (pcmFramesToSeek > 0) { + if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) { + if (!drflac__read_and_decode_next_flac_frame(pFlac)) { + break; /* Couldn't read the next frame, so just break from the loop and return. */ + } + } else { + if (pFlac->currentFLACFrame.pcmFramesRemaining > pcmFramesToSeek) { + pcmFramesRead += pcmFramesToSeek; + pFlac->currentFLACFrame.pcmFramesRemaining -= (drflac_uint32)pcmFramesToSeek; /* <-- Safe cast. Will always be < currentFrame.pcmFramesRemaining < 65536. */ + pcmFramesToSeek = 0; + } else { + pcmFramesRead += pFlac->currentFLACFrame.pcmFramesRemaining; + pcmFramesToSeek -= pFlac->currentFLACFrame.pcmFramesRemaining; + pFlac->currentFLACFrame.pcmFramesRemaining = 0; + } + } + } + + pFlac->currentPCMFrame += pcmFramesRead; + return pcmFramesRead; +} + + +static drflac_bool32 drflac__seek_to_pcm_frame__brute_force(drflac* pFlac, drflac_uint64 pcmFrameIndex) +{ + drflac_bool32 isMidFrame = DRFLAC_FALSE; + drflac_uint64 runningPCMFrameCount; + + DRFLAC_ASSERT(pFlac != NULL); + + /* If we are seeking forward we start from the current position. Otherwise we need to start all the way from the start of the file. */ + if (pcmFrameIndex >= pFlac->currentPCMFrame) { + /* Seeking forward. Need to seek from the current position. */ + runningPCMFrameCount = pFlac->currentPCMFrame; + + /* The frame header for the first frame may not yet have been read. We need to do that if necessary. */ + if (pFlac->currentPCMFrame == 0 && pFlac->currentFLACFrame.pcmFramesRemaining == 0) { + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; + } + } else { + isMidFrame = DRFLAC_TRUE; + } + } else { + /* Seeking backwards. Need to seek from the start of the file. */ + runningPCMFrameCount = 0; + + /* Move back to the start. */ + if (!drflac__seek_to_first_frame(pFlac)) { + return DRFLAC_FALSE; + } + + /* Decode the first frame in preparation for sample-exact seeking below. */ + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; + } + } + + /* + We need to as quickly as possible find the frame that contains the target sample. To do this, we iterate over each frame and inspect its + header. If based on the header we can determine that the frame contains the sample, we do a full decode of that frame. + */ + for (;;) { + drflac_uint64 pcmFrameCountInThisFLACFrame; + drflac_uint64 firstPCMFrameInFLACFrame = 0; + drflac_uint64 lastPCMFrameInFLACFrame = 0; + + drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &firstPCMFrameInFLACFrame, &lastPCMFrameInFLACFrame); + + pcmFrameCountInThisFLACFrame = (lastPCMFrameInFLACFrame - firstPCMFrameInFLACFrame) + 1; + if (pcmFrameIndex < (runningPCMFrameCount + pcmFrameCountInThisFLACFrame)) { + /* + The sample should be in this frame. We need to fully decode it, however if it's an invalid frame (a CRC mismatch), we need to pretend + it never existed and keep iterating. + */ + drflac_uint64 pcmFramesToDecode = pcmFrameIndex - runningPCMFrameCount; + + if (!isMidFrame) { + drflac_result result = drflac__decode_flac_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + /* The frame is valid. We just need to skip over some samples to ensure it's sample-exact. */ + return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; /* <-- If this fails, something bad has happened (it should never fail). */ + } else { + if (result == DRFLAC_CRC_MISMATCH) { + goto next_iteration; /* CRC mismatch. Pretend this frame never existed. */ + } else { + return DRFLAC_FALSE; + } + } + } else { + /* We started seeking mid-frame which means we need to skip the frame decoding part. */ + return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; + } + } else { + /* + It's not in this frame. We need to seek past the frame, but check if there was a CRC mismatch. If so, we pretend this + frame never existed and leave the running sample count untouched. + */ + if (!isMidFrame) { + drflac_result result = drflac__seek_to_next_flac_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + runningPCMFrameCount += pcmFrameCountInThisFLACFrame; + } else { + if (result == DRFLAC_CRC_MISMATCH) { + goto next_iteration; /* CRC mismatch. Pretend this frame never existed. */ + } else { + return DRFLAC_FALSE; + } + } + } else { + /* + We started seeking mid-frame which means we need to seek by reading to the end of the frame instead of with + drflac__seek_to_next_flac_frame() which only works if the decoder is sitting on the byte just after the frame header. + */ + runningPCMFrameCount += pFlac->currentFLACFrame.pcmFramesRemaining; + pFlac->currentFLACFrame.pcmFramesRemaining = 0; + isMidFrame = DRFLAC_FALSE; + } + + /* If we are seeking to the end of the file and we've just hit it, we're done. */ + if (pcmFrameIndex == pFlac->totalPCMFrameCount && runningPCMFrameCount == pFlac->totalPCMFrameCount) { + return DRFLAC_TRUE; + } + } + + next_iteration: + /* Grab the next frame in preparation for the next iteration. */ + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; + } + } +} + + +#if !defined(DR_FLAC_NO_CRC) +/* +We use an average compression ratio to determine our approximate start location. FLAC files are generally about 50%-70% the size of their +uncompressed counterparts so we'll use this as a basis. I'm going to split the middle and use a factor of 0.6 to determine the starting +location. +*/ +#define DRFLAC_BINARY_SEARCH_APPROX_COMPRESSION_RATIO 0.6f + +static drflac_bool32 drflac__seek_to_approximate_flac_frame_to_byte(drflac* pFlac, drflac_uint64 targetByte, drflac_uint64 rangeLo, drflac_uint64 rangeHi, drflac_uint64* pLastSuccessfulSeekOffset) +{ + DRFLAC_ASSERT(pFlac != NULL); + DRFLAC_ASSERT(pLastSuccessfulSeekOffset != NULL); + DRFLAC_ASSERT(targetByte >= rangeLo); + DRFLAC_ASSERT(targetByte <= rangeHi); + + *pLastSuccessfulSeekOffset = pFlac->firstFLACFramePosInBytes; + + for (;;) { + /* After rangeLo == rangeHi == targetByte fails, we need to break out. */ + drflac_uint64 lastTargetByte = targetByte; + + /* When seeking to a byte, failure probably means we've attempted to seek beyond the end of the stream. To counter this we just halve it each attempt. */ + if (!drflac__seek_to_byte(&pFlac->bs, targetByte)) { + /* If we couldn't even seek to the first byte in the stream we have a problem. Just abandon the whole thing. */ + if (targetByte == 0) { + drflac__seek_to_first_frame(pFlac); /* Try to recover. */ + return DRFLAC_FALSE; + } + + /* Halve the byte location and continue. */ + targetByte = rangeLo + ((rangeHi - rangeLo)/2); + rangeHi = targetByte; + } else { + /* Getting here should mean that we have seeked to an appropriate byte. */ + + /* Clear the details of the FLAC frame so we don't misreport data. */ + DRFLAC_ZERO_MEMORY(&pFlac->currentFLACFrame, sizeof(pFlac->currentFLACFrame)); + + /* + Now seek to the next FLAC frame. We need to decode the entire frame (not just the header) because it's possible for the header to incorrectly pass the + CRC check and return bad data. We need to decode the entire frame to be more certain. Although this seems unlikely, this has happened to me in testing + so it needs to stay this way for now. + */ +#if 1 + if (!drflac__read_and_decode_next_flac_frame(pFlac)) { + /* Halve the byte location and continue. */ + targetByte = rangeLo + ((rangeHi - rangeLo)/2); + rangeHi = targetByte; + } else { + break; + } +#else + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + /* Halve the byte location and continue. */ + targetByte = rangeLo + ((rangeHi - rangeLo)/2); + rangeHi = targetByte; + } else { + break; + } +#endif + } + + /* We already tried this byte and there are no more to try, break out. */ + if(targetByte == lastTargetByte) { + return DRFLAC_FALSE; + } + } + + /* The current PCM frame needs to be updated based on the frame we just seeked to. */ + drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &pFlac->currentPCMFrame, NULL); + + DRFLAC_ASSERT(targetByte <= rangeHi); + + *pLastSuccessfulSeekOffset = targetByte; + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(drflac* pFlac, drflac_uint64 offset) +{ + /* This section of code would be used if we were only decoding the FLAC frame header when calling drflac__seek_to_approximate_flac_frame_to_byte(). */ +#if 0 + if (drflac__decode_flac_frame(pFlac) != DRFLAC_SUCCESS) { + /* We failed to decode this frame which may be due to it being corrupt. We'll just use the next valid FLAC frame. */ + if (drflac__read_and_decode_next_flac_frame(pFlac) == DRFLAC_FALSE) { + return DRFLAC_FALSE; + } + } +#endif + + return drflac__seek_forward_by_pcm_frames(pFlac, offset) == offset; +} + + +static drflac_bool32 drflac__seek_to_pcm_frame__binary_search_internal(drflac* pFlac, drflac_uint64 pcmFrameIndex, drflac_uint64 byteRangeLo, drflac_uint64 byteRangeHi) +{ + /* This assumes pFlac->currentPCMFrame is sitting on byteRangeLo upon entry. */ + + drflac_uint64 targetByte; + drflac_uint64 pcmRangeLo = pFlac->totalPCMFrameCount; + drflac_uint64 pcmRangeHi = 0; + drflac_uint64 lastSuccessfulSeekOffset = (drflac_uint64)-1; + drflac_uint64 closestSeekOffsetBeforeTargetPCMFrame = byteRangeLo; + drflac_uint32 seekForwardThreshold = (pFlac->maxBlockSizeInPCMFrames != 0) ? pFlac->maxBlockSizeInPCMFrames*2 : 4096; + + targetByte = byteRangeLo + (drflac_uint64)(((drflac_int64)((pcmFrameIndex - pFlac->currentPCMFrame) * pFlac->channels * pFlac->bitsPerSample)/8.0f) * DRFLAC_BINARY_SEARCH_APPROX_COMPRESSION_RATIO); + if (targetByte > byteRangeHi) { + targetByte = byteRangeHi; + } + + for (;;) { + if (drflac__seek_to_approximate_flac_frame_to_byte(pFlac, targetByte, byteRangeLo, byteRangeHi, &lastSuccessfulSeekOffset)) { + /* We found a FLAC frame. We need to check if it contains the sample we're looking for. */ + drflac_uint64 newPCMRangeLo; + drflac_uint64 newPCMRangeHi; + drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &newPCMRangeLo, &newPCMRangeHi); + + /* If we selected the same frame, it means we should be pretty close. Just decode the rest. */ + if (pcmRangeLo == newPCMRangeLo) { + if (!drflac__seek_to_approximate_flac_frame_to_byte(pFlac, closestSeekOffsetBeforeTargetPCMFrame, closestSeekOffsetBeforeTargetPCMFrame, byteRangeHi, &lastSuccessfulSeekOffset)) { + break; /* Failed to seek to closest frame. */ + } + + if (drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame)) { + return DRFLAC_TRUE; + } else { + break; /* Failed to seek forward. */ + } + } + + pcmRangeLo = newPCMRangeLo; + pcmRangeHi = newPCMRangeHi; + + if (pcmRangeLo <= pcmFrameIndex && pcmRangeHi >= pcmFrameIndex) { + /* The target PCM frame is in this FLAC frame. */ + if (drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame) ) { + return DRFLAC_TRUE; + } else { + break; /* Failed to seek to FLAC frame. */ + } + } else { + const float approxCompressionRatio = (drflac_int64)(lastSuccessfulSeekOffset - pFlac->firstFLACFramePosInBytes) / ((drflac_int64)(pcmRangeLo * pFlac->channels * pFlac->bitsPerSample)/8.0f); + + if (pcmRangeLo > pcmFrameIndex) { + /* We seeked too far forward. We need to move our target byte backward and try again. */ + byteRangeHi = lastSuccessfulSeekOffset; + if (byteRangeLo > byteRangeHi) { + byteRangeLo = byteRangeHi; + } + + targetByte = byteRangeLo + ((byteRangeHi - byteRangeLo) / 2); + if (targetByte < byteRangeLo) { + targetByte = byteRangeLo; + } + } else /*if (pcmRangeHi < pcmFrameIndex)*/ { + /* We didn't seek far enough. We need to move our target byte forward and try again. */ + + /* If we're close enough we can just seek forward. */ + if ((pcmFrameIndex - pcmRangeLo) < seekForwardThreshold) { + if (drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame)) { + return DRFLAC_TRUE; + } else { + break; /* Failed to seek to FLAC frame. */ + } + } else { + byteRangeLo = lastSuccessfulSeekOffset; + if (byteRangeHi < byteRangeLo) { + byteRangeHi = byteRangeLo; + } + + targetByte = lastSuccessfulSeekOffset + (drflac_uint64)(((drflac_int64)((pcmFrameIndex-pcmRangeLo) * pFlac->channels * pFlac->bitsPerSample)/8.0f) * approxCompressionRatio); + if (targetByte > byteRangeHi) { + targetByte = byteRangeHi; + } + + if (closestSeekOffsetBeforeTargetPCMFrame < lastSuccessfulSeekOffset) { + closestSeekOffsetBeforeTargetPCMFrame = lastSuccessfulSeekOffset; + } + } + } + } + } else { + /* Getting here is really bad. We just recover as best we can, but moving to the first frame in the stream, and then abort. */ + break; + } + } + + drflac__seek_to_first_frame(pFlac); /* <-- Try to recover. */ + return DRFLAC_FALSE; +} + +static drflac_bool32 drflac__seek_to_pcm_frame__binary_search(drflac* pFlac, drflac_uint64 pcmFrameIndex) +{ + drflac_uint64 byteRangeLo; + drflac_uint64 byteRangeHi; + drflac_uint32 seekForwardThreshold = (pFlac->maxBlockSizeInPCMFrames != 0) ? pFlac->maxBlockSizeInPCMFrames*2 : 4096; + + /* Our algorithm currently assumes the FLAC stream is currently sitting at the start. */ + if (drflac__seek_to_first_frame(pFlac) == DRFLAC_FALSE) { + return DRFLAC_FALSE; + } + + /* If we're close enough to the start, just move to the start and seek forward. */ + if (pcmFrameIndex < seekForwardThreshold) { + return drflac__seek_forward_by_pcm_frames(pFlac, pcmFrameIndex) == pcmFrameIndex; + } + + /* + Our starting byte range is the byte position of the first FLAC frame and the approximate end of the file as if it were completely uncompressed. This ensures + the entire file is included, even though most of the time it'll exceed the end of the actual stream. This is OK as the frame searching logic will handle it. + */ + byteRangeLo = pFlac->firstFLACFramePosInBytes; + byteRangeHi = pFlac->firstFLACFramePosInBytes + (drflac_uint64)((drflac_int64)(pFlac->totalPCMFrameCount * pFlac->channels * pFlac->bitsPerSample)/8.0f); + + return drflac__seek_to_pcm_frame__binary_search_internal(pFlac, pcmFrameIndex, byteRangeLo, byteRangeHi); +} +#endif /* !DR_FLAC_NO_CRC */ + +static drflac_bool32 drflac__seek_to_pcm_frame__seek_table(drflac* pFlac, drflac_uint64 pcmFrameIndex) +{ + drflac_uint32 iClosestSeekpoint = 0; + drflac_bool32 isMidFrame = DRFLAC_FALSE; + drflac_uint64 runningPCMFrameCount; + drflac_uint32 iSeekpoint; + + + DRFLAC_ASSERT(pFlac != NULL); + + if (pFlac->pSeekpoints == NULL || pFlac->seekpointCount == 0) { + return DRFLAC_FALSE; + } + + /* Do not use the seektable if pcmFramIndex is not coverd by it. */ + if (pFlac->pSeekpoints[0].firstPCMFrame > pcmFrameIndex) { + return DRFLAC_FALSE; + } + + for (iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) { + if (pFlac->pSeekpoints[iSeekpoint].firstPCMFrame >= pcmFrameIndex) { + break; + } + + iClosestSeekpoint = iSeekpoint; + } + + /* There's been cases where the seek table contains only zeros. We need to do some basic validation on the closest seekpoint. */ + if (pFlac->pSeekpoints[iClosestSeekpoint].pcmFrameCount == 0 || pFlac->pSeekpoints[iClosestSeekpoint].pcmFrameCount > pFlac->maxBlockSizeInPCMFrames) { + return DRFLAC_FALSE; + } + if (pFlac->pSeekpoints[iClosestSeekpoint].firstPCMFrame > pFlac->totalPCMFrameCount && pFlac->totalPCMFrameCount > 0) { + return DRFLAC_FALSE; + } + +#if !defined(DR_FLAC_NO_CRC) + /* At this point we should know the closest seek point. We can use a binary search for this. We need to know the total sample count for this. */ + if (pFlac->totalPCMFrameCount > 0) { + drflac_uint64 byteRangeLo; + drflac_uint64 byteRangeHi; + + byteRangeHi = pFlac->firstFLACFramePosInBytes + (drflac_uint64)((drflac_int64)(pFlac->totalPCMFrameCount * pFlac->channels * pFlac->bitsPerSample)/8.0f); + byteRangeLo = pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset; + + /* + If our closest seek point is not the last one, we only need to search between it and the next one. The section below calculates an appropriate starting + value for byteRangeHi which will clamp it appropriately. + + Note that the next seekpoint must have an offset greater than the closest seekpoint because otherwise our binary search algorithm will break down. There + have been cases where a seektable consists of seek points where every byte offset is set to 0 which causes problems. If this happens we need to abort. + */ + if (iClosestSeekpoint < pFlac->seekpointCount-1) { + drflac_uint32 iNextSeekpoint = iClosestSeekpoint + 1; + + /* Basic validation on the seekpoints to ensure they're usable. */ + if (pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset >= pFlac->pSeekpoints[iNextSeekpoint].flacFrameOffset || pFlac->pSeekpoints[iNextSeekpoint].pcmFrameCount == 0) { + return DRFLAC_FALSE; /* The next seekpoint doesn't look right. The seek table cannot be trusted from here. Abort. */ + } + + if (pFlac->pSeekpoints[iNextSeekpoint].firstPCMFrame != (((drflac_uint64)0xFFFFFFFF << 32) | 0xFFFFFFFF)) { /* Make sure it's not a placeholder seekpoint. */ + byteRangeHi = pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iNextSeekpoint].flacFrameOffset - 1; /* byteRangeHi must be zero based. */ + } + } + + if (drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset)) { + if (drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &pFlac->currentPCMFrame, NULL); + + if (drflac__seek_to_pcm_frame__binary_search_internal(pFlac, pcmFrameIndex, byteRangeLo, byteRangeHi)) { + return DRFLAC_TRUE; + } + } + } + } +#endif /* !DR_FLAC_NO_CRC */ + + /* Getting here means we need to use a slower algorithm because the binary search method failed or cannot be used. */ + + /* + If we are seeking forward and the closest seekpoint is _before_ the current sample, we just seek forward from where we are. Otherwise we start seeking + from the seekpoint's first sample. + */ + if (pcmFrameIndex >= pFlac->currentPCMFrame && pFlac->pSeekpoints[iClosestSeekpoint].firstPCMFrame <= pFlac->currentPCMFrame) { + /* Optimized case. Just seek forward from where we are. */ + runningPCMFrameCount = pFlac->currentPCMFrame; + + /* The frame header for the first frame may not yet have been read. We need to do that if necessary. */ + if (pFlac->currentPCMFrame == 0 && pFlac->currentFLACFrame.pcmFramesRemaining == 0) { + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; + } + } else { + isMidFrame = DRFLAC_TRUE; + } + } else { + /* Slower case. Seek to the start of the seekpoint and then seek forward from there. */ + runningPCMFrameCount = pFlac->pSeekpoints[iClosestSeekpoint].firstPCMFrame; + + if (!drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset)) { + return DRFLAC_FALSE; + } + + /* Grab the frame the seekpoint is sitting on in preparation for the sample-exact seeking below. */ + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; + } + } + + for (;;) { + drflac_uint64 pcmFrameCountInThisFLACFrame; + drflac_uint64 firstPCMFrameInFLACFrame = 0; + drflac_uint64 lastPCMFrameInFLACFrame = 0; + + drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &firstPCMFrameInFLACFrame, &lastPCMFrameInFLACFrame); + + pcmFrameCountInThisFLACFrame = (lastPCMFrameInFLACFrame - firstPCMFrameInFLACFrame) + 1; + if (pcmFrameIndex < (runningPCMFrameCount + pcmFrameCountInThisFLACFrame)) { + /* + The sample should be in this frame. We need to fully decode it, but if it's an invalid frame (a CRC mismatch) we need to pretend + it never existed and keep iterating. + */ + drflac_uint64 pcmFramesToDecode = pcmFrameIndex - runningPCMFrameCount; + + if (!isMidFrame) { + drflac_result result = drflac__decode_flac_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + /* The frame is valid. We just need to skip over some samples to ensure it's sample-exact. */ + return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; /* <-- If this fails, something bad has happened (it should never fail). */ + } else { + if (result == DRFLAC_CRC_MISMATCH) { + goto next_iteration; /* CRC mismatch. Pretend this frame never existed. */ + } else { + return DRFLAC_FALSE; + } + } + } else { + /* We started seeking mid-frame which means we need to skip the frame decoding part. */ + return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; + } + } else { + /* + It's not in this frame. We need to seek past the frame, but check if there was a CRC mismatch. If so, we pretend this + frame never existed and leave the running sample count untouched. + */ + if (!isMidFrame) { + drflac_result result = drflac__seek_to_next_flac_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + runningPCMFrameCount += pcmFrameCountInThisFLACFrame; + } else { + if (result == DRFLAC_CRC_MISMATCH) { + goto next_iteration; /* CRC mismatch. Pretend this frame never existed. */ + } else { + return DRFLAC_FALSE; + } + } + } else { + /* + We started seeking mid-frame which means we need to seek by reading to the end of the frame instead of with + drflac__seek_to_next_flac_frame() which only works if the decoder is sitting on the byte just after the frame header. + */ + runningPCMFrameCount += pFlac->currentFLACFrame.pcmFramesRemaining; + pFlac->currentFLACFrame.pcmFramesRemaining = 0; + isMidFrame = DRFLAC_FALSE; + } + + /* If we are seeking to the end of the file and we've just hit it, we're done. */ + if (pcmFrameIndex == pFlac->totalPCMFrameCount && runningPCMFrameCount == pFlac->totalPCMFrameCount) { + return DRFLAC_TRUE; + } + } + + next_iteration: + /* Grab the next frame in preparation for the next iteration. */ + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; + } + } +} + + +#ifndef DR_FLAC_NO_OGG +typedef struct +{ + drflac_uint8 capturePattern[4]; /* Should be "OggS" */ + drflac_uint8 structureVersion; /* Always 0. */ + drflac_uint8 headerType; + drflac_uint64 granulePosition; + drflac_uint32 serialNumber; + drflac_uint32 sequenceNumber; + drflac_uint32 checksum; + drflac_uint8 segmentCount; + drflac_uint8 segmentTable[255]; +} drflac_ogg_page_header; +#endif + +typedef struct +{ + drflac_read_proc onRead; + drflac_seek_proc onSeek; + drflac_meta_proc onMeta; + drflac_container container; + void* pUserData; + void* pUserDataMD; + drflac_uint32 sampleRate; + drflac_uint8 channels; + drflac_uint8 bitsPerSample; + drflac_uint64 totalPCMFrameCount; + drflac_uint16 maxBlockSizeInPCMFrames; + drflac_uint64 runningFilePos; + drflac_bool32 hasStreamInfoBlock; + drflac_bool32 hasMetadataBlocks; + drflac_bs bs; /* <-- A bit streamer is required for loading data during initialization. */ + drflac_frame_header firstFrameHeader; /* <-- The header of the first frame that was read during relaxed initalization. Only set if there is no STREAMINFO block. */ + +#ifndef DR_FLAC_NO_OGG + drflac_uint32 oggSerial; + drflac_uint64 oggFirstBytePos; + drflac_ogg_page_header oggBosHeader; +#endif +} drflac_init_info; + +static DRFLAC_INLINE void drflac__decode_block_header(drflac_uint32 blockHeader, drflac_uint8* isLastBlock, drflac_uint8* blockType, drflac_uint32* blockSize) +{ + blockHeader = drflac__be2host_32(blockHeader); + *isLastBlock = (drflac_uint8)((blockHeader & 0x80000000UL) >> 31); + *blockType = (drflac_uint8)((blockHeader & 0x7F000000UL) >> 24); + *blockSize = (blockHeader & 0x00FFFFFFUL); +} + +static DRFLAC_INLINE drflac_bool32 drflac__read_and_decode_block_header(drflac_read_proc onRead, void* pUserData, drflac_uint8* isLastBlock, drflac_uint8* blockType, drflac_uint32* blockSize) +{ + drflac_uint32 blockHeader; + + *blockSize = 0; + if (onRead(pUserData, &blockHeader, 4) != 4) { + return DRFLAC_FALSE; + } + + drflac__decode_block_header(blockHeader, isLastBlock, blockType, blockSize); + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__read_streaminfo(drflac_read_proc onRead, void* pUserData, drflac_streaminfo* pStreamInfo) +{ + drflac_uint32 blockSizes; + drflac_uint64 frameSizes = 0; + drflac_uint64 importantProps; + drflac_uint8 md5[16]; + + /* min/max block size. */ + if (onRead(pUserData, &blockSizes, 4) != 4) { + return DRFLAC_FALSE; + } + + /* min/max frame size. */ + if (onRead(pUserData, &frameSizes, 6) != 6) { + return DRFLAC_FALSE; + } + + /* Sample rate, channels, bits per sample and total sample count. */ + if (onRead(pUserData, &importantProps, 8) != 8) { + return DRFLAC_FALSE; + } + + /* MD5 */ + if (onRead(pUserData, md5, sizeof(md5)) != sizeof(md5)) { + return DRFLAC_FALSE; + } + + blockSizes = drflac__be2host_32(blockSizes); + frameSizes = drflac__be2host_64(frameSizes); + importantProps = drflac__be2host_64(importantProps); + + pStreamInfo->minBlockSizeInPCMFrames = (drflac_uint16)((blockSizes & 0xFFFF0000) >> 16); + pStreamInfo->maxBlockSizeInPCMFrames = (drflac_uint16) (blockSizes & 0x0000FFFF); + pStreamInfo->minFrameSizeInPCMFrames = (drflac_uint32)((frameSizes & (((drflac_uint64)0x00FFFFFF << 16) << 24)) >> 40); + pStreamInfo->maxFrameSizeInPCMFrames = (drflac_uint32)((frameSizes & (((drflac_uint64)0x00FFFFFF << 16) << 0)) >> 16); + pStreamInfo->sampleRate = (drflac_uint32)((importantProps & (((drflac_uint64)0x000FFFFF << 16) << 28)) >> 44); + pStreamInfo->channels = (drflac_uint8 )((importantProps & (((drflac_uint64)0x0000000E << 16) << 24)) >> 41) + 1; + pStreamInfo->bitsPerSample = (drflac_uint8 )((importantProps & (((drflac_uint64)0x0000001F << 16) << 20)) >> 36) + 1; + pStreamInfo->totalPCMFrameCount = ((importantProps & ((((drflac_uint64)0x0000000F << 16) << 16) | 0xFFFFFFFF))); + DRFLAC_COPY_MEMORY(pStreamInfo->md5, md5, sizeof(md5)); + + return DRFLAC_TRUE; +} + + +static void* drflac__malloc_default(size_t sz, void* pUserData) +{ + (void)pUserData; + return DRFLAC_MALLOC(sz); +} + +static void* drflac__realloc_default(void* p, size_t sz, void* pUserData) +{ + (void)pUserData; + return DRFLAC_REALLOC(p, sz); +} + +static void drflac__free_default(void* p, void* pUserData) +{ + (void)pUserData; + DRFLAC_FREE(p); +} + + +static void* drflac__malloc_from_callbacks(size_t sz, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + if (pAllocationCallbacks == NULL) { + return NULL; + } + + if (pAllocationCallbacks->onMalloc != NULL) { + return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData); + } + + /* Try using realloc(). */ + if (pAllocationCallbacks->onRealloc != NULL) { + return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData); + } + + return NULL; +} + +static void* drflac__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + if (pAllocationCallbacks == NULL) { + return NULL; + } + + if (pAllocationCallbacks->onRealloc != NULL) { + return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData); + } + + /* Try emulating realloc() in terms of malloc()/free(). */ + if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) { + void* p2; + + p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData); + if (p2 == NULL) { + return NULL; + } + + if (p != NULL) { + DRFLAC_COPY_MEMORY(p2, p, szOld); + pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); + } + + return p2; + } + + return NULL; +} + +static void drflac__free_from_callbacks(void* p, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + if (p == NULL || pAllocationCallbacks == NULL) { + return; + } + + if (pAllocationCallbacks->onFree != NULL) { + pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); + } +} + + +static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_uint64* pFirstFramePos, drflac_uint64* pSeektablePos, drflac_uint32* pSeekpointCount, drflac_allocation_callbacks* pAllocationCallbacks) +{ + /* + We want to keep track of the byte position in the stream of the seektable. At the time of calling this function we know that + we'll be sitting on byte 42. + */ + drflac_uint64 runningFilePos = 42; + drflac_uint64 seektablePos = 0; + drflac_uint32 seektableSize = 0; + + for (;;) { + drflac_metadata metadata; + drflac_uint8 isLastBlock = 0; + drflac_uint8 blockType = 0; + drflac_uint32 blockSize; + if (drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize) == DRFLAC_FALSE) { + return DRFLAC_FALSE; + } + runningFilePos += 4; + + metadata.type = blockType; + metadata.pRawData = NULL; + metadata.rawDataSize = 0; + + switch (blockType) + { + case DRFLAC_METADATA_BLOCK_TYPE_APPLICATION: + { + if (blockSize < 4) { + return DRFLAC_FALSE; + } + + if (onMeta) { + void* pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks); + if (pRawData == NULL) { + return DRFLAC_FALSE; + } + + if (onRead(pUserData, pRawData, blockSize) != blockSize) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + + metadata.pRawData = pRawData; + metadata.rawDataSize = blockSize; + metadata.data.application.id = drflac__be2host_32(*(drflac_uint32*)pRawData); + metadata.data.application.pData = (const void*)((drflac_uint8*)pRawData + sizeof(drflac_uint32)); + metadata.data.application.dataSize = blockSize - sizeof(drflac_uint32); + onMeta(pUserDataMD, &metadata); + + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + } + } break; + + case DRFLAC_METADATA_BLOCK_TYPE_SEEKTABLE: + { + seektablePos = runningFilePos; + seektableSize = blockSize; + + if (onMeta) { + drflac_uint32 seekpointCount; + drflac_uint32 iSeekpoint; + void* pRawData; + + seekpointCount = blockSize/DRFLAC_SEEKPOINT_SIZE_IN_BYTES; + + pRawData = drflac__malloc_from_callbacks(seekpointCount * sizeof(drflac_seekpoint), pAllocationCallbacks); + if (pRawData == NULL) { + return DRFLAC_FALSE; + } + + /* We need to read seekpoint by seekpoint and do some processing. */ + for (iSeekpoint = 0; iSeekpoint < seekpointCount; ++iSeekpoint) { + drflac_seekpoint* pSeekpoint = (drflac_seekpoint*)pRawData + iSeekpoint; + + if (onRead(pUserData, pSeekpoint, DRFLAC_SEEKPOINT_SIZE_IN_BYTES) != DRFLAC_SEEKPOINT_SIZE_IN_BYTES) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + + /* Endian swap. */ + pSeekpoint->firstPCMFrame = drflac__be2host_64(pSeekpoint->firstPCMFrame); + pSeekpoint->flacFrameOffset = drflac__be2host_64(pSeekpoint->flacFrameOffset); + pSeekpoint->pcmFrameCount = drflac__be2host_16(pSeekpoint->pcmFrameCount); + } + + metadata.pRawData = pRawData; + metadata.rawDataSize = blockSize; + metadata.data.seektable.seekpointCount = seekpointCount; + metadata.data.seektable.pSeekpoints = (const drflac_seekpoint*)pRawData; + + onMeta(pUserDataMD, &metadata); + + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + } + } break; + + case DRFLAC_METADATA_BLOCK_TYPE_VORBIS_COMMENT: + { + if (blockSize < 8) { + return DRFLAC_FALSE; + } + + if (onMeta) { + void* pRawData; + const char* pRunningData; + const char* pRunningDataEnd; + drflac_uint32 i; + + pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks); + if (pRawData == NULL) { + return DRFLAC_FALSE; + } + + if (onRead(pUserData, pRawData, blockSize) != blockSize) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + + metadata.pRawData = pRawData; + metadata.rawDataSize = blockSize; + + pRunningData = (const char*)pRawData; + pRunningDataEnd = (const char*)pRawData + blockSize; + + metadata.data.vorbis_comment.vendorLength = drflac__le2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + + /* Need space for the rest of the block */ + if ((pRunningDataEnd - pRunningData) - 4 < (drflac_int64)metadata.data.vorbis_comment.vendorLength) { /* <-- Note the order of operations to avoid overflow to a valid value */ + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + metadata.data.vorbis_comment.vendor = pRunningData; pRunningData += metadata.data.vorbis_comment.vendorLength; + metadata.data.vorbis_comment.commentCount = drflac__le2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + + /* Need space for 'commentCount' comments after the block, which at minimum is a drflac_uint32 per comment */ + if ((pRunningDataEnd - pRunningData) / sizeof(drflac_uint32) < metadata.data.vorbis_comment.commentCount) { /* <-- Note the order of operations to avoid overflow to a valid value */ + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + metadata.data.vorbis_comment.pComments = pRunningData; + + /* Check that the comments section is valid before passing it to the callback */ + for (i = 0; i < metadata.data.vorbis_comment.commentCount; ++i) { + drflac_uint32 commentLength; + + if (pRunningDataEnd - pRunningData < 4) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + + commentLength = drflac__le2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + if (pRunningDataEnd - pRunningData < (drflac_int64)commentLength) { /* <-- Note the order of operations to avoid overflow to a valid value */ + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + pRunningData += commentLength; + } + + onMeta(pUserDataMD, &metadata); + + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + } + } break; + + case DRFLAC_METADATA_BLOCK_TYPE_CUESHEET: + { + if (blockSize < 396) { + return DRFLAC_FALSE; + } + + if (onMeta) { + void* pRawData; + const char* pRunningData; + const char* pRunningDataEnd; + size_t bufferSize; + drflac_uint8 iTrack; + drflac_uint8 iIndex; + void* pTrackData; + + /* + This needs to be loaded in two passes. The first pass is used to calculate the size of the memory allocation + we need for storing the necessary data. The second pass will fill that buffer with usable data. + */ + pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks); + if (pRawData == NULL) { + return DRFLAC_FALSE; + } + + if (onRead(pUserData, pRawData, blockSize) != blockSize) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + + metadata.pRawData = pRawData; + metadata.rawDataSize = blockSize; + + pRunningData = (const char*)pRawData; + pRunningDataEnd = (const char*)pRawData + blockSize; + + DRFLAC_COPY_MEMORY(metadata.data.cuesheet.catalog, pRunningData, 128); pRunningData += 128; + metadata.data.cuesheet.leadInSampleCount = drflac__be2host_64(*(const drflac_uint64*)pRunningData); pRunningData += 8; + metadata.data.cuesheet.isCD = (pRunningData[0] & 0x80) != 0; pRunningData += 259; + metadata.data.cuesheet.trackCount = pRunningData[0]; pRunningData += 1; + metadata.data.cuesheet.pTrackData = NULL; /* Will be filled later. */ + + /* Pass 1: Calculate the size of the buffer for the track data. */ + { + const char* pRunningDataSaved = pRunningData; /* Will be restored at the end in preparation for the second pass. */ + + bufferSize = metadata.data.cuesheet.trackCount * DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES; + + for (iTrack = 0; iTrack < metadata.data.cuesheet.trackCount; ++iTrack) { + drflac_uint8 indexCount; + drflac_uint32 indexPointSize; + + if (pRunningDataEnd - pRunningData < DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + + /* Skip to the index point count */ + pRunningData += 35; + + indexCount = pRunningData[0]; + pRunningData += 1; + + bufferSize += indexCount * sizeof(drflac_cuesheet_track_index); + + /* Quick validation check. */ + indexPointSize = indexCount * DRFLAC_CUESHEET_TRACK_INDEX_SIZE_IN_BYTES; + if (pRunningDataEnd - pRunningData < (drflac_int64)indexPointSize) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + + pRunningData += indexPointSize; + } + + pRunningData = pRunningDataSaved; + } + + /* Pass 2: Allocate a buffer and fill the data. Validation was done in the step above so can be skipped. */ + { + char* pRunningTrackData; + + pTrackData = drflac__malloc_from_callbacks(bufferSize, pAllocationCallbacks); + if (pTrackData == NULL) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + + pRunningTrackData = (char*)pTrackData; + + for (iTrack = 0; iTrack < metadata.data.cuesheet.trackCount; ++iTrack) { + drflac_uint8 indexCount; + + DRFLAC_COPY_MEMORY(pRunningTrackData, pRunningData, DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES); + pRunningData += DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES-1; /* Skip forward, but not beyond the last byte in the CUESHEET_TRACK block which is the index count. */ + pRunningTrackData += DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES-1; + + /* Grab the index count for the next part. */ + indexCount = pRunningData[0]; + pRunningData += 1; + pRunningTrackData += 1; + + /* Extract each track index. */ + for (iIndex = 0; iIndex < indexCount; ++iIndex) { + drflac_cuesheet_track_index* pTrackIndex = (drflac_cuesheet_track_index*)pRunningTrackData; + + DRFLAC_COPY_MEMORY(pRunningTrackData, pRunningData, DRFLAC_CUESHEET_TRACK_INDEX_SIZE_IN_BYTES); + pRunningData += DRFLAC_CUESHEET_TRACK_INDEX_SIZE_IN_BYTES; + pRunningTrackData += sizeof(drflac_cuesheet_track_index); + + pTrackIndex->offset = drflac__be2host_64(pTrackIndex->offset); + } + } + + metadata.data.cuesheet.pTrackData = pTrackData; + } + + /* The original data is no longer needed. */ + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + pRawData = NULL; + + onMeta(pUserDataMD, &metadata); + + drflac__free_from_callbacks(pTrackData, pAllocationCallbacks); + pTrackData = NULL; + } + } break; + + case DRFLAC_METADATA_BLOCK_TYPE_PICTURE: + { + if (blockSize < 32) { + return DRFLAC_FALSE; + } + + if (onMeta) { + void* pRawData; + const char* pRunningData; + const char* pRunningDataEnd; + + pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks); + if (pRawData == NULL) { + return DRFLAC_FALSE; + } + + if (onRead(pUserData, pRawData, blockSize) != blockSize) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + + metadata.pRawData = pRawData; + metadata.rawDataSize = blockSize; + + pRunningData = (const char*)pRawData; + pRunningDataEnd = (const char*)pRawData + blockSize; + + metadata.data.picture.type = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + metadata.data.picture.mimeLength = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + + /* Need space for the rest of the block */ + if ((pRunningDataEnd - pRunningData) - 24 < (drflac_int64)metadata.data.picture.mimeLength) { /* <-- Note the order of operations to avoid overflow to a valid value */ + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + metadata.data.picture.mime = pRunningData; pRunningData += metadata.data.picture.mimeLength; + metadata.data.picture.descriptionLength = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + + /* Need space for the rest of the block */ + if ((pRunningDataEnd - pRunningData) - 20 < (drflac_int64)metadata.data.picture.descriptionLength) { /* <-- Note the order of operations to avoid overflow to a valid value */ + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + metadata.data.picture.description = pRunningData; pRunningData += metadata.data.picture.descriptionLength; + metadata.data.picture.width = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + metadata.data.picture.height = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + metadata.data.picture.colorDepth = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + metadata.data.picture.indexColorCount = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + metadata.data.picture.pictureDataSize = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + metadata.data.picture.pPictureData = (const drflac_uint8*)pRunningData; + + /* Need space for the picture after the block */ + if (pRunningDataEnd - pRunningData < (drflac_int64)metadata.data.picture.pictureDataSize) { /* <-- Note the order of operations to avoid overflow to a valid value */ + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + + onMeta(pUserDataMD, &metadata); + + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + } + } break; + + case DRFLAC_METADATA_BLOCK_TYPE_PADDING: + { + if (onMeta) { + metadata.data.padding.unused = 0; + + /* Padding doesn't have anything meaningful in it, so just skip over it, but make sure the caller is aware of it by firing the callback. */ + if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) { + isLastBlock = DRFLAC_TRUE; /* An error occurred while seeking. Attempt to recover by treating this as the last block which will in turn terminate the loop. */ + } else { + onMeta(pUserDataMD, &metadata); + } + } + } break; + + case DRFLAC_METADATA_BLOCK_TYPE_INVALID: + { + /* Invalid chunk. Just skip over this one. */ + if (onMeta) { + if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) { + isLastBlock = DRFLAC_TRUE; /* An error occurred while seeking. Attempt to recover by treating this as the last block which will in turn terminate the loop. */ + } + } + } break; + + default: + { + /* + It's an unknown chunk, but not necessarily invalid. There's a chance more metadata blocks might be defined later on, so we + can at the very least report the chunk to the application and let it look at the raw data. + */ + if (onMeta) { + void* pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks); + if (pRawData == NULL) { + return DRFLAC_FALSE; + } + + if (onRead(pUserData, pRawData, blockSize) != blockSize) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + + metadata.pRawData = pRawData; + metadata.rawDataSize = blockSize; + onMeta(pUserDataMD, &metadata); + + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + } + } break; + } + + /* If we're not handling metadata, just skip over the block. If we are, it will have been handled earlier in the switch statement above. */ + if (onMeta == NULL && blockSize > 0) { + if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) { + isLastBlock = DRFLAC_TRUE; + } + } + + runningFilePos += blockSize; + if (isLastBlock) { + break; + } + } + + *pSeektablePos = seektablePos; + *pSeekpointCount = seektableSize / DRFLAC_SEEKPOINT_SIZE_IN_BYTES; + *pFirstFramePos = runningFilePos; + + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__init_private__native(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_bool32 relaxed) +{ + /* Pre Condition: The bit stream should be sitting just past the 4-byte id header. */ + + drflac_uint8 isLastBlock; + drflac_uint8 blockType; + drflac_uint32 blockSize; + + (void)onSeek; + + pInit->container = drflac_container_native; + + /* The first metadata block should be the STREAMINFO block. */ + if (!drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize)) { + return DRFLAC_FALSE; + } + + if (blockType != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO || blockSize != 34) { + if (!relaxed) { + /* We're opening in strict mode and the first block is not the STREAMINFO block. Error. */ + return DRFLAC_FALSE; + } else { + /* + Relaxed mode. To open from here we need to just find the first frame and set the sample rate, etc. to whatever is defined + for that frame. + */ + pInit->hasStreamInfoBlock = DRFLAC_FALSE; + pInit->hasMetadataBlocks = DRFLAC_FALSE; + + if (!drflac__read_next_flac_frame_header(&pInit->bs, 0, &pInit->firstFrameHeader)) { + return DRFLAC_FALSE; /* Couldn't find a frame. */ + } + + if (pInit->firstFrameHeader.bitsPerSample == 0) { + return DRFLAC_FALSE; /* Failed to initialize because the first frame depends on the STREAMINFO block, which does not exist. */ + } + + pInit->sampleRate = pInit->firstFrameHeader.sampleRate; + pInit->channels = drflac__get_channel_count_from_channel_assignment(pInit->firstFrameHeader.channelAssignment); + pInit->bitsPerSample = pInit->firstFrameHeader.bitsPerSample; + pInit->maxBlockSizeInPCMFrames = 65535; /* <-- See notes here: https://xiph.org/flac/format.html#metadata_block_streaminfo */ + return DRFLAC_TRUE; + } + } else { + drflac_streaminfo streaminfo; + if (!drflac__read_streaminfo(onRead, pUserData, &streaminfo)) { + return DRFLAC_FALSE; + } + + pInit->hasStreamInfoBlock = DRFLAC_TRUE; + pInit->sampleRate = streaminfo.sampleRate; + pInit->channels = streaminfo.channels; + pInit->bitsPerSample = streaminfo.bitsPerSample; + pInit->totalPCMFrameCount = streaminfo.totalPCMFrameCount; + pInit->maxBlockSizeInPCMFrames = streaminfo.maxBlockSizeInPCMFrames; /* Don't care about the min block size - only the max (used for determining the size of the memory allocation). */ + pInit->hasMetadataBlocks = !isLastBlock; + + if (onMeta) { + drflac_metadata metadata; + metadata.type = DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO; + metadata.pRawData = NULL; + metadata.rawDataSize = 0; + metadata.data.streaminfo = streaminfo; + onMeta(pUserDataMD, &metadata); + } + + return DRFLAC_TRUE; + } +} + +#ifndef DR_FLAC_NO_OGG +#define DRFLAC_OGG_MAX_PAGE_SIZE 65307 +#define DRFLAC_OGG_CAPTURE_PATTERN_CRC32 1605413199 /* CRC-32 of "OggS". */ + +typedef enum +{ + drflac_ogg_recover_on_crc_mismatch, + drflac_ogg_fail_on_crc_mismatch +} drflac_ogg_crc_mismatch_recovery; + +#ifndef DR_FLAC_NO_CRC +static drflac_uint32 drflac__crc32_table[] = { + 0x00000000L, 0x04C11DB7L, 0x09823B6EL, 0x0D4326D9L, + 0x130476DCL, 0x17C56B6BL, 0x1A864DB2L, 0x1E475005L, + 0x2608EDB8L, 0x22C9F00FL, 0x2F8AD6D6L, 0x2B4BCB61L, + 0x350C9B64L, 0x31CD86D3L, 0x3C8EA00AL, 0x384FBDBDL, + 0x4C11DB70L, 0x48D0C6C7L, 0x4593E01EL, 0x4152FDA9L, + 0x5F15ADACL, 0x5BD4B01BL, 0x569796C2L, 0x52568B75L, + 0x6A1936C8L, 0x6ED82B7FL, 0x639B0DA6L, 0x675A1011L, + 0x791D4014L, 0x7DDC5DA3L, 0x709F7B7AL, 0x745E66CDL, + 0x9823B6E0L, 0x9CE2AB57L, 0x91A18D8EL, 0x95609039L, + 0x8B27C03CL, 0x8FE6DD8BL, 0x82A5FB52L, 0x8664E6E5L, + 0xBE2B5B58L, 0xBAEA46EFL, 0xB7A96036L, 0xB3687D81L, + 0xAD2F2D84L, 0xA9EE3033L, 0xA4AD16EAL, 0xA06C0B5DL, + 0xD4326D90L, 0xD0F37027L, 0xDDB056FEL, 0xD9714B49L, + 0xC7361B4CL, 0xC3F706FBL, 0xCEB42022L, 0xCA753D95L, + 0xF23A8028L, 0xF6FB9D9FL, 0xFBB8BB46L, 0xFF79A6F1L, + 0xE13EF6F4L, 0xE5FFEB43L, 0xE8BCCD9AL, 0xEC7DD02DL, + 0x34867077L, 0x30476DC0L, 0x3D044B19L, 0x39C556AEL, + 0x278206ABL, 0x23431B1CL, 0x2E003DC5L, 0x2AC12072L, + 0x128E9DCFL, 0x164F8078L, 0x1B0CA6A1L, 0x1FCDBB16L, + 0x018AEB13L, 0x054BF6A4L, 0x0808D07DL, 0x0CC9CDCAL, + 0x7897AB07L, 0x7C56B6B0L, 0x71159069L, 0x75D48DDEL, + 0x6B93DDDBL, 0x6F52C06CL, 0x6211E6B5L, 0x66D0FB02L, + 0x5E9F46BFL, 0x5A5E5B08L, 0x571D7DD1L, 0x53DC6066L, + 0x4D9B3063L, 0x495A2DD4L, 0x44190B0DL, 0x40D816BAL, + 0xACA5C697L, 0xA864DB20L, 0xA527FDF9L, 0xA1E6E04EL, + 0xBFA1B04BL, 0xBB60ADFCL, 0xB6238B25L, 0xB2E29692L, + 0x8AAD2B2FL, 0x8E6C3698L, 0x832F1041L, 0x87EE0DF6L, + 0x99A95DF3L, 0x9D684044L, 0x902B669DL, 0x94EA7B2AL, + 0xE0B41DE7L, 0xE4750050L, 0xE9362689L, 0xEDF73B3EL, + 0xF3B06B3BL, 0xF771768CL, 0xFA325055L, 0xFEF34DE2L, + 0xC6BCF05FL, 0xC27DEDE8L, 0xCF3ECB31L, 0xCBFFD686L, + 0xD5B88683L, 0xD1799B34L, 0xDC3ABDEDL, 0xD8FBA05AL, + 0x690CE0EEL, 0x6DCDFD59L, 0x608EDB80L, 0x644FC637L, + 0x7A089632L, 0x7EC98B85L, 0x738AAD5CL, 0x774BB0EBL, + 0x4F040D56L, 0x4BC510E1L, 0x46863638L, 0x42472B8FL, + 0x5C007B8AL, 0x58C1663DL, 0x558240E4L, 0x51435D53L, + 0x251D3B9EL, 0x21DC2629L, 0x2C9F00F0L, 0x285E1D47L, + 0x36194D42L, 0x32D850F5L, 0x3F9B762CL, 0x3B5A6B9BL, + 0x0315D626L, 0x07D4CB91L, 0x0A97ED48L, 0x0E56F0FFL, + 0x1011A0FAL, 0x14D0BD4DL, 0x19939B94L, 0x1D528623L, + 0xF12F560EL, 0xF5EE4BB9L, 0xF8AD6D60L, 0xFC6C70D7L, + 0xE22B20D2L, 0xE6EA3D65L, 0xEBA91BBCL, 0xEF68060BL, + 0xD727BBB6L, 0xD3E6A601L, 0xDEA580D8L, 0xDA649D6FL, + 0xC423CD6AL, 0xC0E2D0DDL, 0xCDA1F604L, 0xC960EBB3L, + 0xBD3E8D7EL, 0xB9FF90C9L, 0xB4BCB610L, 0xB07DABA7L, + 0xAE3AFBA2L, 0xAAFBE615L, 0xA7B8C0CCL, 0xA379DD7BL, + 0x9B3660C6L, 0x9FF77D71L, 0x92B45BA8L, 0x9675461FL, + 0x8832161AL, 0x8CF30BADL, 0x81B02D74L, 0x857130C3L, + 0x5D8A9099L, 0x594B8D2EL, 0x5408ABF7L, 0x50C9B640L, + 0x4E8EE645L, 0x4A4FFBF2L, 0x470CDD2BL, 0x43CDC09CL, + 0x7B827D21L, 0x7F436096L, 0x7200464FL, 0x76C15BF8L, + 0x68860BFDL, 0x6C47164AL, 0x61043093L, 0x65C52D24L, + 0x119B4BE9L, 0x155A565EL, 0x18197087L, 0x1CD86D30L, + 0x029F3D35L, 0x065E2082L, 0x0B1D065BL, 0x0FDC1BECL, + 0x3793A651L, 0x3352BBE6L, 0x3E119D3FL, 0x3AD08088L, + 0x2497D08DL, 0x2056CD3AL, 0x2D15EBE3L, 0x29D4F654L, + 0xC5A92679L, 0xC1683BCEL, 0xCC2B1D17L, 0xC8EA00A0L, + 0xD6AD50A5L, 0xD26C4D12L, 0xDF2F6BCBL, 0xDBEE767CL, + 0xE3A1CBC1L, 0xE760D676L, 0xEA23F0AFL, 0xEEE2ED18L, + 0xF0A5BD1DL, 0xF464A0AAL, 0xF9278673L, 0xFDE69BC4L, + 0x89B8FD09L, 0x8D79E0BEL, 0x803AC667L, 0x84FBDBD0L, + 0x9ABC8BD5L, 0x9E7D9662L, 0x933EB0BBL, 0x97FFAD0CL, + 0xAFB010B1L, 0xAB710D06L, 0xA6322BDFL, 0xA2F33668L, + 0xBCB4666DL, 0xB8757BDAL, 0xB5365D03L, 0xB1F740B4L +}; +#endif + +static DRFLAC_INLINE drflac_uint32 drflac_crc32_byte(drflac_uint32 crc32, drflac_uint8 data) +{ +#ifndef DR_FLAC_NO_CRC + return (crc32 << 8) ^ drflac__crc32_table[(drflac_uint8)((crc32 >> 24) & 0xFF) ^ data]; +#else + (void)data; + return crc32; +#endif +} + +#if 0 +static DRFLAC_INLINE drflac_uint32 drflac_crc32_uint32(drflac_uint32 crc32, drflac_uint32 data) +{ + crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >> 24) & 0xFF)); + crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >> 16) & 0xFF)); + crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >> 8) & 0xFF)); + crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >> 0) & 0xFF)); + return crc32; +} + +static DRFLAC_INLINE drflac_uint32 drflac_crc32_uint64(drflac_uint32 crc32, drflac_uint64 data) +{ + crc32 = drflac_crc32_uint32(crc32, (drflac_uint32)((data >> 32) & 0xFFFFFFFF)); + crc32 = drflac_crc32_uint32(crc32, (drflac_uint32)((data >> 0) & 0xFFFFFFFF)); + return crc32; +} +#endif + +static DRFLAC_INLINE drflac_uint32 drflac_crc32_buffer(drflac_uint32 crc32, drflac_uint8* pData, drflac_uint32 dataSize) +{ + /* This can be optimized. */ + drflac_uint32 i; + for (i = 0; i < dataSize; ++i) { + crc32 = drflac_crc32_byte(crc32, pData[i]); + } + return crc32; +} + + +static DRFLAC_INLINE drflac_bool32 drflac_ogg__is_capture_pattern(drflac_uint8 pattern[4]) +{ + return pattern[0] == 'O' && pattern[1] == 'g' && pattern[2] == 'g' && pattern[3] == 'S'; +} + +static DRFLAC_INLINE drflac_uint32 drflac_ogg__get_page_header_size(drflac_ogg_page_header* pHeader) +{ + return 27 + pHeader->segmentCount; +} + +static DRFLAC_INLINE drflac_uint32 drflac_ogg__get_page_body_size(drflac_ogg_page_header* pHeader) +{ + drflac_uint32 pageBodySize = 0; + int i; + + for (i = 0; i < pHeader->segmentCount; ++i) { + pageBodySize += pHeader->segmentTable[i]; + } + + return pageBodySize; +} + +static drflac_result drflac_ogg__read_page_header_after_capture_pattern(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, drflac_uint32* pBytesRead, drflac_uint32* pCRC32) +{ + drflac_uint8 data[23]; + drflac_uint32 i; + + DRFLAC_ASSERT(*pCRC32 == DRFLAC_OGG_CAPTURE_PATTERN_CRC32); + + if (onRead(pUserData, data, 23) != 23) { + return DRFLAC_AT_END; + } + *pBytesRead += 23; + + /* + It's not actually used, but set the capture pattern to 'OggS' for completeness. Not doing this will cause static analysers to complain about + us trying to access uninitialized data. We could alternatively just comment out this member of the drflac_ogg_page_header structure, but I + like to have it map to the structure of the underlying data. + */ + pHeader->capturePattern[0] = 'O'; + pHeader->capturePattern[1] = 'g'; + pHeader->capturePattern[2] = 'g'; + pHeader->capturePattern[3] = 'S'; + + pHeader->structureVersion = data[0]; + pHeader->headerType = data[1]; + DRFLAC_COPY_MEMORY(&pHeader->granulePosition, &data[ 2], 8); + DRFLAC_COPY_MEMORY(&pHeader->serialNumber, &data[10], 4); + DRFLAC_COPY_MEMORY(&pHeader->sequenceNumber, &data[14], 4); + DRFLAC_COPY_MEMORY(&pHeader->checksum, &data[18], 4); + pHeader->segmentCount = data[22]; + + /* Calculate the CRC. Note that for the calculation the checksum part of the page needs to be set to 0. */ + data[18] = 0; + data[19] = 0; + data[20] = 0; + data[21] = 0; + + for (i = 0; i < 23; ++i) { + *pCRC32 = drflac_crc32_byte(*pCRC32, data[i]); + } + + + if (onRead(pUserData, pHeader->segmentTable, pHeader->segmentCount) != pHeader->segmentCount) { + return DRFLAC_AT_END; + } + *pBytesRead += pHeader->segmentCount; + + for (i = 0; i < pHeader->segmentCount; ++i) { + *pCRC32 = drflac_crc32_byte(*pCRC32, pHeader->segmentTable[i]); + } + + return DRFLAC_SUCCESS; +} + +static drflac_result drflac_ogg__read_page_header(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, drflac_uint32* pBytesRead, drflac_uint32* pCRC32) +{ + drflac_uint8 id[4]; + + *pBytesRead = 0; + + if (onRead(pUserData, id, 4) != 4) { + return DRFLAC_AT_END; + } + *pBytesRead += 4; + + /* We need to read byte-by-byte until we find the OggS capture pattern. */ + for (;;) { + if (drflac_ogg__is_capture_pattern(id)) { + drflac_result result; + + *pCRC32 = DRFLAC_OGG_CAPTURE_PATTERN_CRC32; + + result = drflac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, pHeader, pBytesRead, pCRC32); + if (result == DRFLAC_SUCCESS) { + return DRFLAC_SUCCESS; + } else { + if (result == DRFLAC_CRC_MISMATCH) { + continue; + } else { + return result; + } + } + } else { + /* The first 4 bytes did not equal the capture pattern. Read the next byte and try again. */ + id[0] = id[1]; + id[1] = id[2]; + id[2] = id[3]; + if (onRead(pUserData, &id[3], 1) != 1) { + return DRFLAC_AT_END; + } + *pBytesRead += 1; + } + } +} + + +/* +The main part of the Ogg encapsulation is the conversion from the physical Ogg bitstream to the native FLAC bitstream. It works +in three general stages: Ogg Physical Bitstream -> Ogg/FLAC Logical Bitstream -> FLAC Native Bitstream. dr_flac is designed +in such a way that the core sections assume everything is delivered in native format. Therefore, for each encapsulation type +dr_flac is supporting there needs to be a layer sitting on top of the onRead and onSeek callbacks that ensures the bits read from +the physical Ogg bitstream are converted and delivered in native FLAC format. +*/ +typedef struct +{ + drflac_read_proc onRead; /* The original onRead callback from drflac_open() and family. */ + drflac_seek_proc onSeek; /* The original onSeek callback from drflac_open() and family. */ + void* pUserData; /* The user data passed on onRead and onSeek. This is the user data that was passed on drflac_open() and family. */ + drflac_uint64 currentBytePos; /* The position of the byte we are sitting on in the physical byte stream. Used for efficient seeking. */ + drflac_uint64 firstBytePos; /* The position of the first byte in the physical bitstream. Points to the start of the "OggS" identifier of the FLAC bos page. */ + drflac_uint32 serialNumber; /* The serial number of the FLAC audio pages. This is determined by the initial header page that was read during initialization. */ + drflac_ogg_page_header bosPageHeader; /* Used for seeking. */ + drflac_ogg_page_header currentPageHeader; + drflac_uint32 bytesRemainingInPage; + drflac_uint32 pageDataSize; + drflac_uint8 pageData[DRFLAC_OGG_MAX_PAGE_SIZE]; +} drflac_oggbs; /* oggbs = Ogg Bitstream */ + +static size_t drflac_oggbs__read_physical(drflac_oggbs* oggbs, void* bufferOut, size_t bytesToRead) +{ + size_t bytesActuallyRead = oggbs->onRead(oggbs->pUserData, bufferOut, bytesToRead); + oggbs->currentBytePos += bytesActuallyRead; + + return bytesActuallyRead; +} + +static drflac_bool32 drflac_oggbs__seek_physical(drflac_oggbs* oggbs, drflac_uint64 offset, drflac_seek_origin origin) +{ + if (origin == drflac_seek_origin_start) { + if (offset <= 0x7FFFFFFF) { + if (!oggbs->onSeek(oggbs->pUserData, (int)offset, drflac_seek_origin_start)) { + return DRFLAC_FALSE; + } + oggbs->currentBytePos = offset; + + return DRFLAC_TRUE; + } else { + if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, drflac_seek_origin_start)) { + return DRFLAC_FALSE; + } + oggbs->currentBytePos = offset; + + return drflac_oggbs__seek_physical(oggbs, offset - 0x7FFFFFFF, drflac_seek_origin_current); + } + } else { + while (offset > 0x7FFFFFFF) { + if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, drflac_seek_origin_current)) { + return DRFLAC_FALSE; + } + oggbs->currentBytePos += 0x7FFFFFFF; + offset -= 0x7FFFFFFF; + } + + if (!oggbs->onSeek(oggbs->pUserData, (int)offset, drflac_seek_origin_current)) { /* <-- Safe cast thanks to the loop above. */ + return DRFLAC_FALSE; + } + oggbs->currentBytePos += offset; + + return DRFLAC_TRUE; + } +} + +static drflac_bool32 drflac_oggbs__goto_next_page(drflac_oggbs* oggbs, drflac_ogg_crc_mismatch_recovery recoveryMethod) +{ + drflac_ogg_page_header header; + for (;;) { + drflac_uint32 crc32 = 0; + drflac_uint32 bytesRead; + drflac_uint32 pageBodySize; +#ifndef DR_FLAC_NO_CRC + drflac_uint32 actualCRC32; +#endif + + if (drflac_ogg__read_page_header(oggbs->onRead, oggbs->pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) { + return DRFLAC_FALSE; + } + oggbs->currentBytePos += bytesRead; + + pageBodySize = drflac_ogg__get_page_body_size(&header); + if (pageBodySize > DRFLAC_OGG_MAX_PAGE_SIZE) { + continue; /* Invalid page size. Assume it's corrupted and just move to the next page. */ + } + + if (header.serialNumber != oggbs->serialNumber) { + /* It's not a FLAC page. Skip it. */ + if (pageBodySize > 0 && !drflac_oggbs__seek_physical(oggbs, pageBodySize, drflac_seek_origin_current)) { + return DRFLAC_FALSE; + } + continue; + } + + + /* We need to read the entire page and then do a CRC check on it. If there's a CRC mismatch we need to skip this page. */ + if (drflac_oggbs__read_physical(oggbs, oggbs->pageData, pageBodySize) != pageBodySize) { + return DRFLAC_FALSE; + } + oggbs->pageDataSize = pageBodySize; + +#ifndef DR_FLAC_NO_CRC + actualCRC32 = drflac_crc32_buffer(crc32, oggbs->pageData, oggbs->pageDataSize); + if (actualCRC32 != header.checksum) { + if (recoveryMethod == drflac_ogg_recover_on_crc_mismatch) { + continue; /* CRC mismatch. Skip this page. */ + } else { + /* + Even though we are failing on a CRC mismatch, we still want our stream to be in a good state. Therefore we + go to the next valid page to ensure we're in a good state, but return false to let the caller know that the + seek did not fully complete. + */ + drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch); + return DRFLAC_FALSE; + } + } +#else + (void)recoveryMethod; /* <-- Silence a warning. */ +#endif + + oggbs->currentPageHeader = header; + oggbs->bytesRemainingInPage = pageBodySize; + return DRFLAC_TRUE; + } +} + +/* Function below is unused at the moment, but I might be re-adding it later. */ +#if 0 +static drflac_uint8 drflac_oggbs__get_current_segment_index(drflac_oggbs* oggbs, drflac_uint8* pBytesRemainingInSeg) +{ + drflac_uint32 bytesConsumedInPage = drflac_ogg__get_page_body_size(&oggbs->currentPageHeader) - oggbs->bytesRemainingInPage; + drflac_uint8 iSeg = 0; + drflac_uint32 iByte = 0; + while (iByte < bytesConsumedInPage) { + drflac_uint8 segmentSize = oggbs->currentPageHeader.segmentTable[iSeg]; + if (iByte + segmentSize > bytesConsumedInPage) { + break; + } else { + iSeg += 1; + iByte += segmentSize; + } + } + + *pBytesRemainingInSeg = oggbs->currentPageHeader.segmentTable[iSeg] - (drflac_uint8)(bytesConsumedInPage - iByte); + return iSeg; +} + +static drflac_bool32 drflac_oggbs__seek_to_next_packet(drflac_oggbs* oggbs) +{ + /* The current packet ends when we get to the segment with a lacing value of < 255 which is not at the end of a page. */ + for (;;) { + drflac_bool32 atEndOfPage = DRFLAC_FALSE; + + drflac_uint8 bytesRemainingInSeg; + drflac_uint8 iFirstSeg = drflac_oggbs__get_current_segment_index(oggbs, &bytesRemainingInSeg); + + drflac_uint32 bytesToEndOfPacketOrPage = bytesRemainingInSeg; + for (drflac_uint8 iSeg = iFirstSeg; iSeg < oggbs->currentPageHeader.segmentCount; ++iSeg) { + drflac_uint8 segmentSize = oggbs->currentPageHeader.segmentTable[iSeg]; + if (segmentSize < 255) { + if (iSeg == oggbs->currentPageHeader.segmentCount-1) { + atEndOfPage = DRFLAC_TRUE; + } + + break; + } + + bytesToEndOfPacketOrPage += segmentSize; + } + + /* + At this point we will have found either the packet or the end of the page. If were at the end of the page we'll + want to load the next page and keep searching for the end of the packet. + */ + drflac_oggbs__seek_physical(oggbs, bytesToEndOfPacketOrPage, drflac_seek_origin_current); + oggbs->bytesRemainingInPage -= bytesToEndOfPacketOrPage; + + if (atEndOfPage) { + /* + We're potentially at the next packet, but we need to check the next page first to be sure because the packet may + straddle pages. + */ + if (!drflac_oggbs__goto_next_page(oggbs)) { + return DRFLAC_FALSE; + } + + /* If it's a fresh packet it most likely means we're at the next packet. */ + if ((oggbs->currentPageHeader.headerType & 0x01) == 0) { + return DRFLAC_TRUE; + } + } else { + /* We're at the next packet. */ + return DRFLAC_TRUE; + } + } +} + +static drflac_bool32 drflac_oggbs__seek_to_next_frame(drflac_oggbs* oggbs) +{ + /* The bitstream should be sitting on the first byte just after the header of the frame. */ + + /* What we're actually doing here is seeking to the start of the next packet. */ + return drflac_oggbs__seek_to_next_packet(oggbs); +} +#endif + +static size_t drflac__on_read_ogg(void* pUserData, void* bufferOut, size_t bytesToRead) +{ + drflac_oggbs* oggbs = (drflac_oggbs*)pUserData; + drflac_uint8* pRunningBufferOut = (drflac_uint8*)bufferOut; + size_t bytesRead = 0; + + DRFLAC_ASSERT(oggbs != NULL); + DRFLAC_ASSERT(pRunningBufferOut != NULL); + + /* Reading is done page-by-page. If we've run out of bytes in the page we need to move to the next one. */ + while (bytesRead < bytesToRead) { + size_t bytesRemainingToRead = bytesToRead - bytesRead; + + if (oggbs->bytesRemainingInPage >= bytesRemainingToRead) { + DRFLAC_COPY_MEMORY(pRunningBufferOut, oggbs->pageData + (oggbs->pageDataSize - oggbs->bytesRemainingInPage), bytesRemainingToRead); + bytesRead += bytesRemainingToRead; + oggbs->bytesRemainingInPage -= (drflac_uint32)bytesRemainingToRead; + break; + } + + /* If we get here it means some of the requested data is contained in the next pages. */ + if (oggbs->bytesRemainingInPage > 0) { + DRFLAC_COPY_MEMORY(pRunningBufferOut, oggbs->pageData + (oggbs->pageDataSize - oggbs->bytesRemainingInPage), oggbs->bytesRemainingInPage); + bytesRead += oggbs->bytesRemainingInPage; + pRunningBufferOut += oggbs->bytesRemainingInPage; + oggbs->bytesRemainingInPage = 0; + } + + DRFLAC_ASSERT(bytesRemainingToRead > 0); + if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) { + break; /* Failed to go to the next page. Might have simply hit the end of the stream. */ + } + } + + return bytesRead; +} + +static drflac_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_seek_origin origin) +{ + drflac_oggbs* oggbs = (drflac_oggbs*)pUserData; + int bytesSeeked = 0; + + DRFLAC_ASSERT(oggbs != NULL); + DRFLAC_ASSERT(offset >= 0); /* <-- Never seek backwards. */ + + /* Seeking is always forward which makes things a lot simpler. */ + if (origin == drflac_seek_origin_start) { + if (!drflac_oggbs__seek_physical(oggbs, (int)oggbs->firstBytePos, drflac_seek_origin_start)) { + return DRFLAC_FALSE; + } + + if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_fail_on_crc_mismatch)) { + return DRFLAC_FALSE; + } + + return drflac__on_seek_ogg(pUserData, offset, drflac_seek_origin_current); + } + + DRFLAC_ASSERT(origin == drflac_seek_origin_current); + + while (bytesSeeked < offset) { + int bytesRemainingToSeek = offset - bytesSeeked; + DRFLAC_ASSERT(bytesRemainingToSeek >= 0); + + if (oggbs->bytesRemainingInPage >= (size_t)bytesRemainingToSeek) { + bytesSeeked += bytesRemainingToSeek; + (void)bytesSeeked; /* <-- Silence a dead store warning emitted by Clang Static Analyzer. */ + oggbs->bytesRemainingInPage -= bytesRemainingToSeek; + break; + } + + /* If we get here it means some of the requested data is contained in the next pages. */ + if (oggbs->bytesRemainingInPage > 0) { + bytesSeeked += (int)oggbs->bytesRemainingInPage; + oggbs->bytesRemainingInPage = 0; + } + + DRFLAC_ASSERT(bytesRemainingToSeek > 0); + if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_fail_on_crc_mismatch)) { + /* Failed to go to the next page. We either hit the end of the stream or had a CRC mismatch. */ + return DRFLAC_FALSE; + } + } + + return DRFLAC_TRUE; +} + + +static drflac_bool32 drflac_ogg__seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex) +{ + drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs; + drflac_uint64 originalBytePos; + drflac_uint64 runningGranulePosition; + drflac_uint64 runningFrameBytePos; + drflac_uint64 runningPCMFrameCount; + + DRFLAC_ASSERT(oggbs != NULL); + + originalBytePos = oggbs->currentBytePos; /* For recovery. Points to the OggS identifier. */ + + /* First seek to the first frame. */ + if (!drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes)) { + return DRFLAC_FALSE; + } + oggbs->bytesRemainingInPage = 0; + + runningGranulePosition = 0; + for (;;) { + if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) { + drflac_oggbs__seek_physical(oggbs, originalBytePos, drflac_seek_origin_start); + return DRFLAC_FALSE; /* Never did find that sample... */ + } + + runningFrameBytePos = oggbs->currentBytePos - drflac_ogg__get_page_header_size(&oggbs->currentPageHeader) - oggbs->pageDataSize; + if (oggbs->currentPageHeader.granulePosition >= pcmFrameIndex) { + break; /* The sample is somewhere in the previous page. */ + } + + /* + At this point we know the sample is not in the previous page. It could possibly be in this page. For simplicity we + disregard any pages that do not begin a fresh packet. + */ + if ((oggbs->currentPageHeader.headerType & 0x01) == 0) { /* <-- Is it a fresh page? */ + if (oggbs->currentPageHeader.segmentTable[0] >= 2) { + drflac_uint8 firstBytesInPage[2]; + firstBytesInPage[0] = oggbs->pageData[0]; + firstBytesInPage[1] = oggbs->pageData[1]; + + if ((firstBytesInPage[0] == 0xFF) && (firstBytesInPage[1] & 0xFC) == 0xF8) { /* <-- Does the page begin with a frame's sync code? */ + runningGranulePosition = oggbs->currentPageHeader.granulePosition; + } + + continue; + } + } + } + + /* + We found the page that that is closest to the sample, so now we need to find it. The first thing to do is seek to the + start of that page. In the loop above we checked that it was a fresh page which means this page is also the start of + a new frame. This property means that after we've seeked to the page we can immediately start looping over frames until + we find the one containing the target sample. + */ + if (!drflac_oggbs__seek_physical(oggbs, runningFrameBytePos, drflac_seek_origin_start)) { + return DRFLAC_FALSE; + } + if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) { + return DRFLAC_FALSE; + } + + /* + At this point we'll be sitting on the first byte of the frame header of the first frame in the page. We just keep + looping over these frames until we find the one containing the sample we're after. + */ + runningPCMFrameCount = runningGranulePosition; + for (;;) { + /* + There are two ways to find the sample and seek past irrelevant frames: + 1) Use the native FLAC decoder. + 2) Use Ogg's framing system. + + Both of these options have their own pros and cons. Using the native FLAC decoder is slower because it needs to + do a full decode of the frame. Using Ogg's framing system is faster, but more complicated and involves some code + duplication for the decoding of frame headers. + + Another thing to consider is that using the Ogg framing system will perform direct seeking of the physical Ogg + bitstream. This is important to consider because it means we cannot read data from the drflac_bs object using the + standard drflac__*() APIs because that will read in extra data for its own internal caching which in turn breaks + the positioning of the read pointer of the physical Ogg bitstream. Therefore, anything that would normally be read + using the native FLAC decoding APIs, such as drflac__read_next_flac_frame_header(), need to be re-implemented so as to + avoid the use of the drflac_bs object. + + Considering these issues, I have decided to use the slower native FLAC decoding method for the following reasons: + 1) Seeking is already partially accelerated using Ogg's paging system in the code block above. + 2) Seeking in an Ogg encapsulated FLAC stream is probably quite uncommon. + 3) Simplicity. + */ + drflac_uint64 firstPCMFrameInFLACFrame = 0; + drflac_uint64 lastPCMFrameInFLACFrame = 0; + drflac_uint64 pcmFrameCountInThisFrame; + + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; + } + + drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &firstPCMFrameInFLACFrame, &lastPCMFrameInFLACFrame); + + pcmFrameCountInThisFrame = (lastPCMFrameInFLACFrame - firstPCMFrameInFLACFrame) + 1; + + /* If we are seeking to the end of the file and we've just hit it, we're done. */ + if (pcmFrameIndex == pFlac->totalPCMFrameCount && (runningPCMFrameCount + pcmFrameCountInThisFrame) == pFlac->totalPCMFrameCount) { + drflac_result result = drflac__decode_flac_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + pFlac->currentPCMFrame = pcmFrameIndex; + pFlac->currentFLACFrame.pcmFramesRemaining = 0; + return DRFLAC_TRUE; + } else { + return DRFLAC_FALSE; + } + } + + if (pcmFrameIndex < (runningPCMFrameCount + pcmFrameCountInThisFrame)) { + /* + The sample should be in this FLAC frame. We need to fully decode it, however if it's an invalid frame (a CRC mismatch), we need to pretend + it never existed and keep iterating. + */ + drflac_result result = drflac__decode_flac_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + /* The frame is valid. We just need to skip over some samples to ensure it's sample-exact. */ + drflac_uint64 pcmFramesToDecode = (size_t)(pcmFrameIndex - runningPCMFrameCount); /* <-- Safe cast because the maximum number of samples in a frame is 65535. */ + if (pcmFramesToDecode == 0) { + return DRFLAC_TRUE; + } + + pFlac->currentPCMFrame = runningPCMFrameCount; + + return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; /* <-- If this fails, something bad has happened (it should never fail). */ + } else { + if (result == DRFLAC_CRC_MISMATCH) { + continue; /* CRC mismatch. Pretend this frame never existed. */ + } else { + return DRFLAC_FALSE; + } + } + } else { + /* + It's not in this frame. We need to seek past the frame, but check if there was a CRC mismatch. If so, we pretend this + frame never existed and leave the running sample count untouched. + */ + drflac_result result = drflac__seek_to_next_flac_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + runningPCMFrameCount += pcmFrameCountInThisFrame; + } else { + if (result == DRFLAC_CRC_MISMATCH) { + continue; /* CRC mismatch. Pretend this frame never existed. */ + } else { + return DRFLAC_FALSE; + } + } + } + } +} + + + +static drflac_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_bool32 relaxed) +{ + drflac_ogg_page_header header; + drflac_uint32 crc32 = DRFLAC_OGG_CAPTURE_PATTERN_CRC32; + drflac_uint32 bytesRead = 0; + + /* Pre Condition: The bit stream should be sitting just past the 4-byte OggS capture pattern. */ + (void)relaxed; + + pInit->container = drflac_container_ogg; + pInit->oggFirstBytePos = 0; + + /* + We'll get here if the first 4 bytes of the stream were the OggS capture pattern, however it doesn't necessarily mean the + stream includes FLAC encoded audio. To check for this we need to scan the beginning-of-stream page markers and check if + any match the FLAC specification. Important to keep in mind that the stream may be multiplexed. + */ + if (drflac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) { + return DRFLAC_FALSE; + } + pInit->runningFilePos += bytesRead; + + for (;;) { + int pageBodySize; + + /* Break if we're past the beginning of stream page. */ + if ((header.headerType & 0x02) == 0) { + return DRFLAC_FALSE; + } + + /* Check if it's a FLAC header. */ + pageBodySize = drflac_ogg__get_page_body_size(&header); + if (pageBodySize == 51) { /* 51 = the lacing value of the FLAC header packet. */ + /* It could be a FLAC page... */ + drflac_uint32 bytesRemainingInPage = pageBodySize; + drflac_uint8 packetType; + + if (onRead(pUserData, &packetType, 1) != 1) { + return DRFLAC_FALSE; + } + + bytesRemainingInPage -= 1; + if (packetType == 0x7F) { + /* Increasingly more likely to be a FLAC page... */ + drflac_uint8 sig[4]; + if (onRead(pUserData, sig, 4) != 4) { + return DRFLAC_FALSE; + } + + bytesRemainingInPage -= 4; + if (sig[0] == 'F' && sig[1] == 'L' && sig[2] == 'A' && sig[3] == 'C') { + /* Almost certainly a FLAC page... */ + drflac_uint8 mappingVersion[2]; + if (onRead(pUserData, mappingVersion, 2) != 2) { + return DRFLAC_FALSE; + } + + if (mappingVersion[0] != 1) { + return DRFLAC_FALSE; /* Only supporting version 1.x of the Ogg mapping. */ + } + + /* + The next 2 bytes are the non-audio packets, not including this one. We don't care about this because we're going to + be handling it in a generic way based on the serial number and packet types. + */ + if (!onSeek(pUserData, 2, drflac_seek_origin_current)) { + return DRFLAC_FALSE; + } + + /* Expecting the native FLAC signature "fLaC". */ + if (onRead(pUserData, sig, 4) != 4) { + return DRFLAC_FALSE; + } + + if (sig[0] == 'f' && sig[1] == 'L' && sig[2] == 'a' && sig[3] == 'C') { + /* The remaining data in the page should be the STREAMINFO block. */ + drflac_streaminfo streaminfo; + drflac_uint8 isLastBlock; + drflac_uint8 blockType; + drflac_uint32 blockSize; + if (!drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize)) { + return DRFLAC_FALSE; + } + + if (blockType != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO || blockSize != 34) { + return DRFLAC_FALSE; /* Invalid block type. First block must be the STREAMINFO block. */ + } + + if (drflac__read_streaminfo(onRead, pUserData, &streaminfo)) { + /* Success! */ + pInit->hasStreamInfoBlock = DRFLAC_TRUE; + pInit->sampleRate = streaminfo.sampleRate; + pInit->channels = streaminfo.channels; + pInit->bitsPerSample = streaminfo.bitsPerSample; + pInit->totalPCMFrameCount = streaminfo.totalPCMFrameCount; + pInit->maxBlockSizeInPCMFrames = streaminfo.maxBlockSizeInPCMFrames; + pInit->hasMetadataBlocks = !isLastBlock; + + if (onMeta) { + drflac_metadata metadata; + metadata.type = DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO; + metadata.pRawData = NULL; + metadata.rawDataSize = 0; + metadata.data.streaminfo = streaminfo; + onMeta(pUserDataMD, &metadata); + } + + pInit->runningFilePos += pageBodySize; + pInit->oggFirstBytePos = pInit->runningFilePos - 79; /* Subtracting 79 will place us right on top of the "OggS" identifier of the FLAC bos page. */ + pInit->oggSerial = header.serialNumber; + pInit->oggBosHeader = header; + break; + } else { + /* Failed to read STREAMINFO block. Aww, so close... */ + return DRFLAC_FALSE; + } + } else { + /* Invalid file. */ + return DRFLAC_FALSE; + } + } else { + /* Not a FLAC header. Skip it. */ + if (!onSeek(pUserData, bytesRemainingInPage, drflac_seek_origin_current)) { + return DRFLAC_FALSE; + } + } + } else { + /* Not a FLAC header. Seek past the entire page and move on to the next. */ + if (!onSeek(pUserData, bytesRemainingInPage, drflac_seek_origin_current)) { + return DRFLAC_FALSE; + } + } + } else { + if (!onSeek(pUserData, pageBodySize, drflac_seek_origin_current)) { + return DRFLAC_FALSE; + } + } + + pInit->runningFilePos += pageBodySize; + + + /* Read the header of the next page. */ + if (drflac_ogg__read_page_header(onRead, pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) { + return DRFLAC_FALSE; + } + pInit->runningFilePos += bytesRead; + } + + /* + If we get here it means we found a FLAC audio stream. We should be sitting on the first byte of the header of the next page. The next + packets in the FLAC logical stream contain the metadata. The only thing left to do in the initialization phase for Ogg is to create the + Ogg bistream object. + */ + pInit->hasMetadataBlocks = DRFLAC_TRUE; /* <-- Always have at least VORBIS_COMMENT metadata block. */ + return DRFLAC_TRUE; +} +#endif + +static drflac_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, void* pUserDataMD) +{ + drflac_bool32 relaxed; + drflac_uint8 id[4]; + + if (pInit == NULL || onRead == NULL || onSeek == NULL) { + return DRFLAC_FALSE; + } + + DRFLAC_ZERO_MEMORY(pInit, sizeof(*pInit)); + pInit->onRead = onRead; + pInit->onSeek = onSeek; + pInit->onMeta = onMeta; + pInit->container = container; + pInit->pUserData = pUserData; + pInit->pUserDataMD = pUserDataMD; + + pInit->bs.onRead = onRead; + pInit->bs.onSeek = onSeek; + pInit->bs.pUserData = pUserData; + drflac__reset_cache(&pInit->bs); + + + /* If the container is explicitly defined then we can try opening in relaxed mode. */ + relaxed = container != drflac_container_unknown; + + /* Skip over any ID3 tags. */ + for (;;) { + if (onRead(pUserData, id, 4) != 4) { + return DRFLAC_FALSE; /* Ran out of data. */ + } + pInit->runningFilePos += 4; + + if (id[0] == 'I' && id[1] == 'D' && id[2] == '3') { + drflac_uint8 header[6]; + drflac_uint8 flags; + drflac_uint32 headerSize; + + if (onRead(pUserData, header, 6) != 6) { + return DRFLAC_FALSE; /* Ran out of data. */ + } + pInit->runningFilePos += 6; + + flags = header[1]; + + DRFLAC_COPY_MEMORY(&headerSize, header+2, 4); + headerSize = drflac__unsynchsafe_32(drflac__be2host_32(headerSize)); + if (flags & 0x10) { + headerSize += 10; + } + + if (!onSeek(pUserData, headerSize, drflac_seek_origin_current)) { + return DRFLAC_FALSE; /* Failed to seek past the tag. */ + } + pInit->runningFilePos += headerSize; + } else { + break; + } + } + + if (id[0] == 'f' && id[1] == 'L' && id[2] == 'a' && id[3] == 'C') { + return drflac__init_private__native(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed); + } +#ifndef DR_FLAC_NO_OGG + if (id[0] == 'O' && id[1] == 'g' && id[2] == 'g' && id[3] == 'S') { + return drflac__init_private__ogg(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed); + } +#endif + + /* If we get here it means we likely don't have a header. Try opening in relaxed mode, if applicable. */ + if (relaxed) { + if (container == drflac_container_native) { + return drflac__init_private__native(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed); + } +#ifndef DR_FLAC_NO_OGG + if (container == drflac_container_ogg) { + return drflac__init_private__ogg(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed); + } +#endif + } + + /* Unsupported container. */ + return DRFLAC_FALSE; +} + +static void drflac__init_from_info(drflac* pFlac, const drflac_init_info* pInit) +{ + DRFLAC_ASSERT(pFlac != NULL); + DRFLAC_ASSERT(pInit != NULL); + + DRFLAC_ZERO_MEMORY(pFlac, sizeof(*pFlac)); + pFlac->bs = pInit->bs; + pFlac->onMeta = pInit->onMeta; + pFlac->pUserDataMD = pInit->pUserDataMD; + pFlac->maxBlockSizeInPCMFrames = pInit->maxBlockSizeInPCMFrames; + pFlac->sampleRate = pInit->sampleRate; + pFlac->channels = (drflac_uint8)pInit->channels; + pFlac->bitsPerSample = (drflac_uint8)pInit->bitsPerSample; + pFlac->totalPCMFrameCount = pInit->totalPCMFrameCount; + pFlac->container = pInit->container; +} + + +static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, void* pUserDataMD, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac_init_info init; + drflac_uint32 allocationSize; + drflac_uint32 wholeSIMDVectorCountPerChannel; + drflac_uint32 decodedSamplesAllocationSize; +#ifndef DR_FLAC_NO_OGG + drflac_oggbs* pOggbs = NULL; +#endif + drflac_uint64 firstFramePos; + drflac_uint64 seektablePos; + drflac_uint32 seekpointCount; + drflac_allocation_callbacks allocationCallbacks; + drflac* pFlac; + + /* CPU support first. */ + drflac__init_cpu_caps(); + + if (!drflac__init_private(&init, onRead, onSeek, onMeta, container, pUserData, pUserDataMD)) { + return NULL; + } + + if (pAllocationCallbacks != NULL) { + allocationCallbacks = *pAllocationCallbacks; + if (allocationCallbacks.onFree == NULL || (allocationCallbacks.onMalloc == NULL && allocationCallbacks.onRealloc == NULL)) { + return NULL; /* Invalid allocation callbacks. */ + } + } else { + allocationCallbacks.pUserData = NULL; + allocationCallbacks.onMalloc = drflac__malloc_default; + allocationCallbacks.onRealloc = drflac__realloc_default; + allocationCallbacks.onFree = drflac__free_default; + } + + + /* + The size of the allocation for the drflac object needs to be large enough to fit the following: + 1) The main members of the drflac structure + 2) A block of memory large enough to store the decoded samples of the largest frame in the stream + 3) If the container is Ogg, a drflac_oggbs object + + The complicated part of the allocation is making sure there's enough room the decoded samples, taking into consideration + the different SIMD instruction sets. + */ + allocationSize = sizeof(drflac); + + /* + The allocation size for decoded frames depends on the number of 32-bit integers that fit inside the largest SIMD vector + we are supporting. + */ + if ((init.maxBlockSizeInPCMFrames % (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))) == 0) { + wholeSIMDVectorCountPerChannel = (init.maxBlockSizeInPCMFrames / (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))); + } else { + wholeSIMDVectorCountPerChannel = (init.maxBlockSizeInPCMFrames / (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))) + 1; + } + + decodedSamplesAllocationSize = wholeSIMDVectorCountPerChannel * DRFLAC_MAX_SIMD_VECTOR_SIZE * init.channels; + + allocationSize += decodedSamplesAllocationSize; + allocationSize += DRFLAC_MAX_SIMD_VECTOR_SIZE; /* Allocate extra bytes to ensure we have enough for alignment. */ + +#ifndef DR_FLAC_NO_OGG + /* There's additional data required for Ogg streams. */ + if (init.container == drflac_container_ogg) { + allocationSize += sizeof(drflac_oggbs); + + pOggbs = (drflac_oggbs*)drflac__malloc_from_callbacks(sizeof(*pOggbs), &allocationCallbacks); + if (pOggbs == NULL) { + return NULL; /*DRFLAC_OUT_OF_MEMORY;*/ + } + + DRFLAC_ZERO_MEMORY(pOggbs, sizeof(*pOggbs)); + pOggbs->onRead = onRead; + pOggbs->onSeek = onSeek; + pOggbs->pUserData = pUserData; + pOggbs->currentBytePos = init.oggFirstBytePos; + pOggbs->firstBytePos = init.oggFirstBytePos; + pOggbs->serialNumber = init.oggSerial; + pOggbs->bosPageHeader = init.oggBosHeader; + pOggbs->bytesRemainingInPage = 0; + } +#endif + + /* + This part is a bit awkward. We need to load the seektable so that it can be referenced in-memory, but I want the drflac object to + consist of only a single heap allocation. To this, the size of the seek table needs to be known, which we determine when reading + and decoding the metadata. + */ + firstFramePos = 42; /* <-- We know we are at byte 42 at this point. */ + seektablePos = 0; + seekpointCount = 0; + if (init.hasMetadataBlocks) { + drflac_read_proc onReadOverride = onRead; + drflac_seek_proc onSeekOverride = onSeek; + void* pUserDataOverride = pUserData; + +#ifndef DR_FLAC_NO_OGG + if (init.container == drflac_container_ogg) { + onReadOverride = drflac__on_read_ogg; + onSeekOverride = drflac__on_seek_ogg; + pUserDataOverride = (void*)pOggbs; + } +#endif + + if (!drflac__read_and_decode_metadata(onReadOverride, onSeekOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seekpointCount, &allocationCallbacks)) { + #ifndef DR_FLAC_NO_OGG + drflac__free_from_callbacks(pOggbs, &allocationCallbacks); + #endif + return NULL; + } + + allocationSize += seekpointCount * sizeof(drflac_seekpoint); + } + + + pFlac = (drflac*)drflac__malloc_from_callbacks(allocationSize, &allocationCallbacks); + if (pFlac == NULL) { + #ifndef DR_FLAC_NO_OGG + drflac__free_from_callbacks(pOggbs, &allocationCallbacks); + #endif + return NULL; + } + + drflac__init_from_info(pFlac, &init); + pFlac->allocationCallbacks = allocationCallbacks; + pFlac->pDecodedSamples = (drflac_int32*)drflac_align((size_t)pFlac->pExtraData, DRFLAC_MAX_SIMD_VECTOR_SIZE); + +#ifndef DR_FLAC_NO_OGG + if (init.container == drflac_container_ogg) { + drflac_oggbs* pInternalOggbs = (drflac_oggbs*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize + (seekpointCount * sizeof(drflac_seekpoint))); + DRFLAC_COPY_MEMORY(pInternalOggbs, pOggbs, sizeof(*pOggbs)); + + /* At this point the pOggbs object has been handed over to pInternalOggbs and can be freed. */ + drflac__free_from_callbacks(pOggbs, &allocationCallbacks); + pOggbs = NULL; + + /* The Ogg bistream needs to be layered on top of the original bitstream. */ + pFlac->bs.onRead = drflac__on_read_ogg; + pFlac->bs.onSeek = drflac__on_seek_ogg; + pFlac->bs.pUserData = (void*)pInternalOggbs; + pFlac->_oggbs = (void*)pInternalOggbs; + } +#endif + + pFlac->firstFLACFramePosInBytes = firstFramePos; + + /* NOTE: Seektables are not currently compatible with Ogg encapsulation (Ogg has its own accelerated seeking system). I may change this later, so I'm leaving this here for now. */ +#ifndef DR_FLAC_NO_OGG + if (init.container == drflac_container_ogg) + { + pFlac->pSeekpoints = NULL; + pFlac->seekpointCount = 0; + } + else +#endif + { + /* If we have a seektable we need to load it now, making sure we move back to where we were previously. */ + if (seektablePos != 0) { + pFlac->seekpointCount = seekpointCount; + pFlac->pSeekpoints = (drflac_seekpoint*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize); + + DRFLAC_ASSERT(pFlac->bs.onSeek != NULL); + DRFLAC_ASSERT(pFlac->bs.onRead != NULL); + + /* Seek to the seektable, then just read directly into our seektable buffer. */ + if (pFlac->bs.onSeek(pFlac->bs.pUserData, (int)seektablePos, drflac_seek_origin_start)) { + drflac_uint32 iSeekpoint; + + for (iSeekpoint = 0; iSeekpoint < seekpointCount; iSeekpoint += 1) { + if (pFlac->bs.onRead(pFlac->bs.pUserData, pFlac->pSeekpoints + iSeekpoint, DRFLAC_SEEKPOINT_SIZE_IN_BYTES) == DRFLAC_SEEKPOINT_SIZE_IN_BYTES) { + /* Endian swap. */ + pFlac->pSeekpoints[iSeekpoint].firstPCMFrame = drflac__be2host_64(pFlac->pSeekpoints[iSeekpoint].firstPCMFrame); + pFlac->pSeekpoints[iSeekpoint].flacFrameOffset = drflac__be2host_64(pFlac->pSeekpoints[iSeekpoint].flacFrameOffset); + pFlac->pSeekpoints[iSeekpoint].pcmFrameCount = drflac__be2host_16(pFlac->pSeekpoints[iSeekpoint].pcmFrameCount); + } else { + /* Failed to read the seektable. Pretend we don't have one. */ + pFlac->pSeekpoints = NULL; + pFlac->seekpointCount = 0; + break; + } + } + + /* We need to seek back to where we were. If this fails it's a critical error. */ + if (!pFlac->bs.onSeek(pFlac->bs.pUserData, (int)pFlac->firstFLACFramePosInBytes, drflac_seek_origin_start)) { + drflac__free_from_callbacks(pFlac, &allocationCallbacks); + return NULL; + } + } else { + /* Failed to seek to the seektable. Ominous sign, but for now we can just pretend we don't have one. */ + pFlac->pSeekpoints = NULL; + pFlac->seekpointCount = 0; + } + } + } + + + /* + If we get here, but don't have a STREAMINFO block, it means we've opened the stream in relaxed mode and need to decode + the first frame. + */ + if (!init.hasStreamInfoBlock) { + pFlac->currentFLACFrame.header = init.firstFrameHeader; + for (;;) { + drflac_result result = drflac__decode_flac_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + break; + } else { + if (result == DRFLAC_CRC_MISMATCH) { + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + drflac__free_from_callbacks(pFlac, &allocationCallbacks); + return NULL; + } + continue; + } else { + drflac__free_from_callbacks(pFlac, &allocationCallbacks); + return NULL; + } + } + } + } + + return pFlac; +} + + + +#ifndef DR_FLAC_NO_STDIO +#include +#ifndef DR_FLAC_NO_WCHAR +#include /* For wcslen(), wcsrtombs() */ +#endif + +/* Errno */ +/* drflac_result_from_errno() is only used for fopen() and wfopen() so putting it inside DR_WAV_NO_STDIO for now. If something else needs this later we can move it out. */ +#include +static drflac_result drflac_result_from_errno(int e) +{ + switch (e) + { + case 0: return DRFLAC_SUCCESS; + #ifdef EPERM + case EPERM: return DRFLAC_INVALID_OPERATION; + #endif + #ifdef ENOENT + case ENOENT: return DRFLAC_DOES_NOT_EXIST; + #endif + #ifdef ESRCH + case ESRCH: return DRFLAC_DOES_NOT_EXIST; + #endif + #ifdef EINTR + case EINTR: return DRFLAC_INTERRUPT; + #endif + #ifdef EIO + case EIO: return DRFLAC_IO_ERROR; + #endif + #ifdef ENXIO + case ENXIO: return DRFLAC_DOES_NOT_EXIST; + #endif + #ifdef E2BIG + case E2BIG: return DRFLAC_INVALID_ARGS; + #endif + #ifdef ENOEXEC + case ENOEXEC: return DRFLAC_INVALID_FILE; + #endif + #ifdef EBADF + case EBADF: return DRFLAC_INVALID_FILE; + #endif + #ifdef ECHILD + case ECHILD: return DRFLAC_ERROR; + #endif + #ifdef EAGAIN + case EAGAIN: return DRFLAC_UNAVAILABLE; + #endif + #ifdef ENOMEM + case ENOMEM: return DRFLAC_OUT_OF_MEMORY; + #endif + #ifdef EACCES + case EACCES: return DRFLAC_ACCESS_DENIED; + #endif + #ifdef EFAULT + case EFAULT: return DRFLAC_BAD_ADDRESS; + #endif + #ifdef ENOTBLK + case ENOTBLK: return DRFLAC_ERROR; + #endif + #ifdef EBUSY + case EBUSY: return DRFLAC_BUSY; + #endif + #ifdef EEXIST + case EEXIST: return DRFLAC_ALREADY_EXISTS; + #endif + #ifdef EXDEV + case EXDEV: return DRFLAC_ERROR; + #endif + #ifdef ENODEV + case ENODEV: return DRFLAC_DOES_NOT_EXIST; + #endif + #ifdef ENOTDIR + case ENOTDIR: return DRFLAC_NOT_DIRECTORY; + #endif + #ifdef EISDIR + case EISDIR: return DRFLAC_IS_DIRECTORY; + #endif + #ifdef EINVAL + case EINVAL: return DRFLAC_INVALID_ARGS; + #endif + #ifdef ENFILE + case ENFILE: return DRFLAC_TOO_MANY_OPEN_FILES; + #endif + #ifdef EMFILE + case EMFILE: return DRFLAC_TOO_MANY_OPEN_FILES; + #endif + #ifdef ENOTTY + case ENOTTY: return DRFLAC_INVALID_OPERATION; + #endif + #ifdef ETXTBSY + case ETXTBSY: return DRFLAC_BUSY; + #endif + #ifdef EFBIG + case EFBIG: return DRFLAC_TOO_BIG; + #endif + #ifdef ENOSPC + case ENOSPC: return DRFLAC_NO_SPACE; + #endif + #ifdef ESPIPE + case ESPIPE: return DRFLAC_BAD_SEEK; + #endif + #ifdef EROFS + case EROFS: return DRFLAC_ACCESS_DENIED; + #endif + #ifdef EMLINK + case EMLINK: return DRFLAC_TOO_MANY_LINKS; + #endif + #ifdef EPIPE + case EPIPE: return DRFLAC_BAD_PIPE; + #endif + #ifdef EDOM + case EDOM: return DRFLAC_OUT_OF_RANGE; + #endif + #ifdef ERANGE + case ERANGE: return DRFLAC_OUT_OF_RANGE; + #endif + #ifdef EDEADLK + case EDEADLK: return DRFLAC_DEADLOCK; + #endif + #ifdef ENAMETOOLONG + case ENAMETOOLONG: return DRFLAC_PATH_TOO_LONG; + #endif + #ifdef ENOLCK + case ENOLCK: return DRFLAC_ERROR; + #endif + #ifdef ENOSYS + case ENOSYS: return DRFLAC_NOT_IMPLEMENTED; + #endif + #ifdef ENOTEMPTY + case ENOTEMPTY: return DRFLAC_DIRECTORY_NOT_EMPTY; + #endif + #ifdef ELOOP + case ELOOP: return DRFLAC_TOO_MANY_LINKS; + #endif + #ifdef ENOMSG + case ENOMSG: return DRFLAC_NO_MESSAGE; + #endif + #ifdef EIDRM + case EIDRM: return DRFLAC_ERROR; + #endif + #ifdef ECHRNG + case ECHRNG: return DRFLAC_ERROR; + #endif + #ifdef EL2NSYNC + case EL2NSYNC: return DRFLAC_ERROR; + #endif + #ifdef EL3HLT + case EL3HLT: return DRFLAC_ERROR; + #endif + #ifdef EL3RST + case EL3RST: return DRFLAC_ERROR; + #endif + #ifdef ELNRNG + case ELNRNG: return DRFLAC_OUT_OF_RANGE; + #endif + #ifdef EUNATCH + case EUNATCH: return DRFLAC_ERROR; + #endif + #ifdef ENOCSI + case ENOCSI: return DRFLAC_ERROR; + #endif + #ifdef EL2HLT + case EL2HLT: return DRFLAC_ERROR; + #endif + #ifdef EBADE + case EBADE: return DRFLAC_ERROR; + #endif + #ifdef EBADR + case EBADR: return DRFLAC_ERROR; + #endif + #ifdef EXFULL + case EXFULL: return DRFLAC_ERROR; + #endif + #ifdef ENOANO + case ENOANO: return DRFLAC_ERROR; + #endif + #ifdef EBADRQC + case EBADRQC: return DRFLAC_ERROR; + #endif + #ifdef EBADSLT + case EBADSLT: return DRFLAC_ERROR; + #endif + #ifdef EBFONT + case EBFONT: return DRFLAC_INVALID_FILE; + #endif + #ifdef ENOSTR + case ENOSTR: return DRFLAC_ERROR; + #endif + #ifdef ENODATA + case ENODATA: return DRFLAC_NO_DATA_AVAILABLE; + #endif + #ifdef ETIME + case ETIME: return DRFLAC_TIMEOUT; + #endif + #ifdef ENOSR + case ENOSR: return DRFLAC_NO_DATA_AVAILABLE; + #endif + #ifdef ENONET + case ENONET: return DRFLAC_NO_NETWORK; + #endif + #ifdef ENOPKG + case ENOPKG: return DRFLAC_ERROR; + #endif + #ifdef EREMOTE + case EREMOTE: return DRFLAC_ERROR; + #endif + #ifdef ENOLINK + case ENOLINK: return DRFLAC_ERROR; + #endif + #ifdef EADV + case EADV: return DRFLAC_ERROR; + #endif + #ifdef ESRMNT + case ESRMNT: return DRFLAC_ERROR; + #endif + #ifdef ECOMM + case ECOMM: return DRFLAC_ERROR; + #endif + #ifdef EPROTO + case EPROTO: return DRFLAC_ERROR; + #endif + #ifdef EMULTIHOP + case EMULTIHOP: return DRFLAC_ERROR; + #endif + #ifdef EDOTDOT + case EDOTDOT: return DRFLAC_ERROR; + #endif + #ifdef EBADMSG + case EBADMSG: return DRFLAC_BAD_MESSAGE; + #endif + #ifdef EOVERFLOW + case EOVERFLOW: return DRFLAC_TOO_BIG; + #endif + #ifdef ENOTUNIQ + case ENOTUNIQ: return DRFLAC_NOT_UNIQUE; + #endif + #ifdef EBADFD + case EBADFD: return DRFLAC_ERROR; + #endif + #ifdef EREMCHG + case EREMCHG: return DRFLAC_ERROR; + #endif + #ifdef ELIBACC + case ELIBACC: return DRFLAC_ACCESS_DENIED; + #endif + #ifdef ELIBBAD + case ELIBBAD: return DRFLAC_INVALID_FILE; + #endif + #ifdef ELIBSCN + case ELIBSCN: return DRFLAC_INVALID_FILE; + #endif + #ifdef ELIBMAX + case ELIBMAX: return DRFLAC_ERROR; + #endif + #ifdef ELIBEXEC + case ELIBEXEC: return DRFLAC_ERROR; + #endif + #ifdef EILSEQ + case EILSEQ: return DRFLAC_INVALID_DATA; + #endif + #ifdef ERESTART + case ERESTART: return DRFLAC_ERROR; + #endif + #ifdef ESTRPIPE + case ESTRPIPE: return DRFLAC_ERROR; + #endif + #ifdef EUSERS + case EUSERS: return DRFLAC_ERROR; + #endif + #ifdef ENOTSOCK + case ENOTSOCK: return DRFLAC_NOT_SOCKET; + #endif + #ifdef EDESTADDRREQ + case EDESTADDRREQ: return DRFLAC_NO_ADDRESS; + #endif + #ifdef EMSGSIZE + case EMSGSIZE: return DRFLAC_TOO_BIG; + #endif + #ifdef EPROTOTYPE + case EPROTOTYPE: return DRFLAC_BAD_PROTOCOL; + #endif + #ifdef ENOPROTOOPT + case ENOPROTOOPT: return DRFLAC_PROTOCOL_UNAVAILABLE; + #endif + #ifdef EPROTONOSUPPORT + case EPROTONOSUPPORT: return DRFLAC_PROTOCOL_NOT_SUPPORTED; + #endif + #ifdef ESOCKTNOSUPPORT + case ESOCKTNOSUPPORT: return DRFLAC_SOCKET_NOT_SUPPORTED; + #endif + #ifdef EOPNOTSUPP + case EOPNOTSUPP: return DRFLAC_INVALID_OPERATION; + #endif + #ifdef EPFNOSUPPORT + case EPFNOSUPPORT: return DRFLAC_PROTOCOL_FAMILY_NOT_SUPPORTED; + #endif + #ifdef EAFNOSUPPORT + case EAFNOSUPPORT: return DRFLAC_ADDRESS_FAMILY_NOT_SUPPORTED; + #endif + #ifdef EADDRINUSE + case EADDRINUSE: return DRFLAC_ALREADY_IN_USE; + #endif + #ifdef EADDRNOTAVAIL + case EADDRNOTAVAIL: return DRFLAC_ERROR; + #endif + #ifdef ENETDOWN + case ENETDOWN: return DRFLAC_NO_NETWORK; + #endif + #ifdef ENETUNREACH + case ENETUNREACH: return DRFLAC_NO_NETWORK; + #endif + #ifdef ENETRESET + case ENETRESET: return DRFLAC_NO_NETWORK; + #endif + #ifdef ECONNABORTED + case ECONNABORTED: return DRFLAC_NO_NETWORK; + #endif + #ifdef ECONNRESET + case ECONNRESET: return DRFLAC_CONNECTION_RESET; + #endif + #ifdef ENOBUFS + case ENOBUFS: return DRFLAC_NO_SPACE; + #endif + #ifdef EISCONN + case EISCONN: return DRFLAC_ALREADY_CONNECTED; + #endif + #ifdef ENOTCONN + case ENOTCONN: return DRFLAC_NOT_CONNECTED; + #endif + #ifdef ESHUTDOWN + case ESHUTDOWN: return DRFLAC_ERROR; + #endif + #ifdef ETOOMANYREFS + case ETOOMANYREFS: return DRFLAC_ERROR; + #endif + #ifdef ETIMEDOUT + case ETIMEDOUT: return DRFLAC_TIMEOUT; + #endif + #ifdef ECONNREFUSED + case ECONNREFUSED: return DRFLAC_CONNECTION_REFUSED; + #endif + #ifdef EHOSTDOWN + case EHOSTDOWN: return DRFLAC_NO_HOST; + #endif + #ifdef EHOSTUNREACH + case EHOSTUNREACH: return DRFLAC_NO_HOST; + #endif + #ifdef EALREADY + case EALREADY: return DRFLAC_IN_PROGRESS; + #endif + #ifdef EINPROGRESS + case EINPROGRESS: return DRFLAC_IN_PROGRESS; + #endif + #ifdef ESTALE + case ESTALE: return DRFLAC_INVALID_FILE; + #endif + #ifdef EUCLEAN + case EUCLEAN: return DRFLAC_ERROR; + #endif + #ifdef ENOTNAM + case ENOTNAM: return DRFLAC_ERROR; + #endif + #ifdef ENAVAIL + case ENAVAIL: return DRFLAC_ERROR; + #endif + #ifdef EISNAM + case EISNAM: return DRFLAC_ERROR; + #endif + #ifdef EREMOTEIO + case EREMOTEIO: return DRFLAC_IO_ERROR; + #endif + #ifdef EDQUOT + case EDQUOT: return DRFLAC_NO_SPACE; + #endif + #ifdef ENOMEDIUM + case ENOMEDIUM: return DRFLAC_DOES_NOT_EXIST; + #endif + #ifdef EMEDIUMTYPE + case EMEDIUMTYPE: return DRFLAC_ERROR; + #endif + #ifdef ECANCELED + case ECANCELED: return DRFLAC_CANCELLED; + #endif + #ifdef ENOKEY + case ENOKEY: return DRFLAC_ERROR; + #endif + #ifdef EKEYEXPIRED + case EKEYEXPIRED: return DRFLAC_ERROR; + #endif + #ifdef EKEYREVOKED + case EKEYREVOKED: return DRFLAC_ERROR; + #endif + #ifdef EKEYREJECTED + case EKEYREJECTED: return DRFLAC_ERROR; + #endif + #ifdef EOWNERDEAD + case EOWNERDEAD: return DRFLAC_ERROR; + #endif + #ifdef ENOTRECOVERABLE + case ENOTRECOVERABLE: return DRFLAC_ERROR; + #endif + #ifdef ERFKILL + case ERFKILL: return DRFLAC_ERROR; + #endif + #ifdef EHWPOISON + case EHWPOISON: return DRFLAC_ERROR; + #endif + default: return DRFLAC_ERROR; + } +} +/* End Errno */ + +/* fopen */ +static drflac_result drflac_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode) +{ +#if defined(_MSC_VER) && _MSC_VER >= 1400 + errno_t err; +#endif + + if (ppFile != NULL) { + *ppFile = NULL; /* Safety. */ + } + + if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) { + return DRFLAC_INVALID_ARGS; + } + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + err = fopen_s(ppFile, pFilePath, pOpenMode); + if (err != 0) { + return drflac_result_from_errno(err); + } +#else +#if defined(_WIN32) || defined(__APPLE__) + *ppFile = fopen(pFilePath, pOpenMode); +#else + #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE) + *ppFile = fopen64(pFilePath, pOpenMode); + #else + *ppFile = fopen(pFilePath, pOpenMode); + #endif +#endif + if (*ppFile == NULL) { + drflac_result result = drflac_result_from_errno(errno); + if (result == DRFLAC_SUCCESS) { + result = DRFLAC_ERROR; /* Just a safety check to make sure we never ever return success when pFile == NULL. */ + } + + return result; + } +#endif + + return DRFLAC_SUCCESS; +} + +/* +_wfopen() isn't always available in all compilation environments. + + * Windows only. + * MSVC seems to support it universally as far back as VC6 from what I can tell (haven't checked further back). + * MinGW-64 (both 32- and 64-bit) seems to support it. + * MinGW wraps it in !defined(__STRICT_ANSI__). + * OpenWatcom wraps it in !defined(_NO_EXT_KEYS). + +This can be reviewed as compatibility issues arise. The preference is to use _wfopen_s() and _wfopen() as opposed to the wcsrtombs() +fallback, so if you notice your compiler not detecting this properly I'm happy to look at adding support. +*/ +#if defined(_WIN32) + #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS)) + #define DRFLAC_HAS_WFOPEN + #endif +#endif + +#ifndef DR_FLAC_NO_WCHAR +static drflac_result drflac_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + if (ppFile != NULL) { + *ppFile = NULL; /* Safety. */ + } + + if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) { + return DRFLAC_INVALID_ARGS; + } + +#if defined(DRFLAC_HAS_WFOPEN) + { + /* Use _wfopen() on Windows. */ + #if defined(_MSC_VER) && _MSC_VER >= 1400 + errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode); + if (err != 0) { + return drflac_result_from_errno(err); + } + #else + *ppFile = _wfopen(pFilePath, pOpenMode); + if (*ppFile == NULL) { + return drflac_result_from_errno(errno); + } + #endif + (void)pAllocationCallbacks; + } +#else + /* + Use fopen() on anything other than Windows. Requires a conversion. This is annoying because + fopen() is locale specific. The only real way I can think of to do this is with wcsrtombs(). Note + that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for + maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler + error I'll look into improving compatibility. + */ + + /* + Some compilers don't support wchar_t or wcsrtombs() which we're using below. In this case we just + need to abort with an error. If you encounter a compiler lacking such support, add it to this list + and submit a bug report and it'll be added to the library upstream. + */ + #if defined(__DJGPP__) + { + /* Nothing to do here. This will fall through to the error check below. */ + } + #else + { + mbstate_t mbs; + size_t lenMB; + const wchar_t* pFilePathTemp = pFilePath; + char* pFilePathMB = NULL; + char pOpenModeMB[32] = {0}; + + /* Get the length first. */ + DRFLAC_ZERO_OBJECT(&mbs); + lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs); + if (lenMB == (size_t)-1) { + return drflac_result_from_errno(errno); + } + + pFilePathMB = (char*)drflac__malloc_from_callbacks(lenMB + 1, pAllocationCallbacks); + if (pFilePathMB == NULL) { + return DRFLAC_OUT_OF_MEMORY; + } + + pFilePathTemp = pFilePath; + DRFLAC_ZERO_OBJECT(&mbs); + wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs); + + /* The open mode should always consist of ASCII characters so we should be able to do a trivial conversion. */ + { + size_t i = 0; + for (;;) { + if (pOpenMode[i] == 0) { + pOpenModeMB[i] = '\0'; + break; + } + + pOpenModeMB[i] = (char)pOpenMode[i]; + i += 1; + } + } + + *ppFile = fopen(pFilePathMB, pOpenModeMB); + + drflac__free_from_callbacks(pFilePathMB, pAllocationCallbacks); + } + #endif + + if (*ppFile == NULL) { + return DRFLAC_ERROR; + } +#endif + + return DRFLAC_SUCCESS; +} +#endif +/* End fopen */ + +static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t bytesToRead) +{ + return fread(bufferOut, 1, bytesToRead, (FILE*)pUserData); +} + +static drflac_bool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin) +{ + DRFLAC_ASSERT(offset >= 0); /* <-- Never seek backwards. */ + + return fseek((FILE*)pUserData, offset, (origin == drflac_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; +} + + +DRFLAC_API drflac* drflac_open_file(const char* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac* pFlac; + FILE* pFile; + + if (drflac_fopen(&pFile, pFileName, "rb") != DRFLAC_SUCCESS) { + return NULL; + } + + pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + if (pFlac == NULL) { + fclose(pFile); + return NULL; + } + + return pFlac; +} + +#ifndef DR_FLAC_NO_WCHAR +DRFLAC_API drflac* drflac_open_file_w(const wchar_t* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac* pFlac; + FILE* pFile; + + if (drflac_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != DRFLAC_SUCCESS) { + return NULL; + } + + pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + if (pFlac == NULL) { + fclose(pFile); + return NULL; + } + + return pFlac; +} +#endif + +DRFLAC_API drflac* drflac_open_file_with_metadata(const char* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac* pFlac; + FILE* pFile; + + if (drflac_fopen(&pFile, pFileName, "rb") != DRFLAC_SUCCESS) { + return NULL; + } + + pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, onMeta, drflac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks); + if (pFlac == NULL) { + fclose(pFile); + return pFlac; + } + + return pFlac; +} + +#ifndef DR_FLAC_NO_WCHAR +DRFLAC_API drflac* drflac_open_file_with_metadata_w(const wchar_t* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac* pFlac; + FILE* pFile; + + if (drflac_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != DRFLAC_SUCCESS) { + return NULL; + } + + pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, onMeta, drflac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks); + if (pFlac == NULL) { + fclose(pFile); + return pFlac; + } + + return pFlac; +} +#endif +#endif /* DR_FLAC_NO_STDIO */ + +static size_t drflac__on_read_memory(void* pUserData, void* bufferOut, size_t bytesToRead) +{ + drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData; + size_t bytesRemaining; + + DRFLAC_ASSERT(memoryStream != NULL); + DRFLAC_ASSERT(memoryStream->dataSize >= memoryStream->currentReadPos); + + bytesRemaining = memoryStream->dataSize - memoryStream->currentReadPos; + if (bytesToRead > bytesRemaining) { + bytesToRead = bytesRemaining; + } + + if (bytesToRead > 0) { + DRFLAC_COPY_MEMORY(bufferOut, memoryStream->data + memoryStream->currentReadPos, bytesToRead); + memoryStream->currentReadPos += bytesToRead; + } + + return bytesToRead; +} + +static drflac_bool32 drflac__on_seek_memory(void* pUserData, int offset, drflac_seek_origin origin) +{ + drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData; + + DRFLAC_ASSERT(memoryStream != NULL); + DRFLAC_ASSERT(offset >= 0); /* <-- Never seek backwards. */ + + if (offset > (drflac_int64)memoryStream->dataSize) { + return DRFLAC_FALSE; + } + + if (origin == drflac_seek_origin_current) { + if (memoryStream->currentReadPos + offset <= memoryStream->dataSize) { + memoryStream->currentReadPos += offset; + } else { + return DRFLAC_FALSE; /* Trying to seek too far forward. */ + } + } else { + if ((drflac_uint32)offset <= memoryStream->dataSize) { + memoryStream->currentReadPos = offset; + } else { + return DRFLAC_FALSE; /* Trying to seek too far forward. */ + } + } + + return DRFLAC_TRUE; +} + +DRFLAC_API drflac* drflac_open_memory(const void* pData, size_t dataSize, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac__memory_stream memoryStream; + drflac* pFlac; + + memoryStream.data = (const drflac_uint8*)pData; + memoryStream.dataSize = dataSize; + memoryStream.currentReadPos = 0; + pFlac = drflac_open(drflac__on_read_memory, drflac__on_seek_memory, &memoryStream, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + + pFlac->memoryStream = memoryStream; + + /* This is an awful hack... */ +#ifndef DR_FLAC_NO_OGG + if (pFlac->container == drflac_container_ogg) + { + drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs; + oggbs->pUserData = &pFlac->memoryStream; + } + else +#endif + { + pFlac->bs.pUserData = &pFlac->memoryStream; + } + + return pFlac; +} + +DRFLAC_API drflac* drflac_open_memory_with_metadata(const void* pData, size_t dataSize, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac__memory_stream memoryStream; + drflac* pFlac; + + memoryStream.data = (const drflac_uint8*)pData; + memoryStream.dataSize = dataSize; + memoryStream.currentReadPos = 0; + pFlac = drflac_open_with_metadata_private(drflac__on_read_memory, drflac__on_seek_memory, onMeta, drflac_container_unknown, &memoryStream, pUserData, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + + pFlac->memoryStream = memoryStream; + + /* This is an awful hack... */ +#ifndef DR_FLAC_NO_OGG + if (pFlac->container == drflac_container_ogg) + { + drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs; + oggbs->pUserData = &pFlac->memoryStream; + } + else +#endif + { + pFlac->bs.pUserData = &pFlac->memoryStream; + } + + return pFlac; +} + + + +DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + return drflac_open_with_metadata_private(onRead, onSeek, NULL, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks); +} +DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + return drflac_open_with_metadata_private(onRead, onSeek, NULL, container, pUserData, pUserData, pAllocationCallbacks); +} + +DRFLAC_API drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + return drflac_open_with_metadata_private(onRead, onSeek, onMeta, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks); +} +DRFLAC_API drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + return drflac_open_with_metadata_private(onRead, onSeek, onMeta, container, pUserData, pUserData, pAllocationCallbacks); +} + +DRFLAC_API void drflac_close(drflac* pFlac) +{ + if (pFlac == NULL) { + return; + } + +#ifndef DR_FLAC_NO_STDIO + /* + If we opened the file with drflac_open_file() we will want to close the file handle. We can know whether or not drflac_open_file() + was used by looking at the callbacks. + */ + if (pFlac->bs.onRead == drflac__on_read_stdio) { + fclose((FILE*)pFlac->bs.pUserData); + } + +#ifndef DR_FLAC_NO_OGG + /* Need to clean up Ogg streams a bit differently due to the way the bit streaming is chained. */ + if (pFlac->container == drflac_container_ogg) { + drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs; + DRFLAC_ASSERT(pFlac->bs.onRead == drflac__on_read_ogg); + + if (oggbs->onRead == drflac__on_read_stdio) { + fclose((FILE*)oggbs->pUserData); + } + } +#endif +#endif + + drflac__free_from_callbacks(pFlac, &pFlac->allocationCallbacks); +} + + +#if 0 +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + drflac_uint64 i; + for (i = 0; i < frameCount; ++i) { + drflac_uint32 left = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + drflac_uint32 right = left - side; + + pOutputSamples[i*2+0] = (drflac_int32)left; + pOutputSamples[i*2+1] = (drflac_int32)right; + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 left0 = pInputSamples0U32[i*4+0] << shift0; + drflac_uint32 left1 = pInputSamples0U32[i*4+1] << shift0; + drflac_uint32 left2 = pInputSamples0U32[i*4+2] << shift0; + drflac_uint32 left3 = pInputSamples0U32[i*4+3] << shift0; + + drflac_uint32 side0 = pInputSamples1U32[i*4+0] << shift1; + drflac_uint32 side1 = pInputSamples1U32[i*4+1] << shift1; + drflac_uint32 side2 = pInputSamples1U32[i*4+2] << shift1; + drflac_uint32 side3 = pInputSamples1U32[i*4+3] << shift1; + + drflac_uint32 right0 = left0 - side0; + drflac_uint32 right1 = left1 - side1; + drflac_uint32 right2 = left2 - side2; + drflac_uint32 right3 = left3 - side3; + + pOutputSamples[i*8+0] = (drflac_int32)left0; + pOutputSamples[i*8+1] = (drflac_int32)right0; + pOutputSamples[i*8+2] = (drflac_int32)left1; + pOutputSamples[i*8+3] = (drflac_int32)right1; + pOutputSamples[i*8+4] = (drflac_int32)left2; + pOutputSamples[i*8+5] = (drflac_int32)right2; + pOutputSamples[i*8+6] = (drflac_int32)left3; + pOutputSamples[i*8+7] = (drflac_int32)right3; + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 left = pInputSamples0U32[i] << shift0; + drflac_uint32 side = pInputSamples1U32[i] << shift1; + drflac_uint32 right = left - side; + + pOutputSamples[i*2+0] = (drflac_int32)left; + pOutputSamples[i*2+1] = (drflac_int32)right; + } +} + +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + for (i = 0; i < frameCount4; ++i) { + __m128i left = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0); + __m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); + __m128i right = _mm_sub_epi32(left, side); + + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right)); + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 left = pInputSamples0U32[i] << shift0; + drflac_uint32 side = pInputSamples1U32[i] << shift1; + drflac_uint32 right = left - side; + + pOutputSamples[i*2+0] = (drflac_int32)left; + pOutputSamples[i*2+1] = (drflac_int32)right; + } +} +#endif + +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + int32x4_t shift0_4; + int32x4_t shift1_4; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + shift0_4 = vdupq_n_s32(shift0); + shift1_4 = vdupq_n_s32(shift1); + + for (i = 0; i < frameCount4; ++i) { + uint32x4_t left; + uint32x4_t side; + uint32x4_t right; + + left = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4); + side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4); + right = vsubq_u32(left, side); + + drflac__vst2q_u32((drflac_uint32*)pOutputSamples + i*8, vzipq_u32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 left = pInputSamples0U32[i] << shift0; + drflac_uint32 side = pInputSamples1U32[i] << shift1; + drflac_uint32 right = left - side; + + pOutputSamples[i*2+0] = (drflac_int32)left; + pOutputSamples[i*2+1] = (drflac_int32)right; + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s32__decode_left_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s32__decode_left_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#endif + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_s32__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_s32__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + + +#if 0 +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + drflac_uint64 i; + for (i = 0; i < frameCount; ++i) { + drflac_uint32 side = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + drflac_uint32 right = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + drflac_uint32 left = right + side; + + pOutputSamples[i*2+0] = (drflac_int32)left; + pOutputSamples[i*2+1] = (drflac_int32)right; + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 side0 = pInputSamples0U32[i*4+0] << shift0; + drflac_uint32 side1 = pInputSamples0U32[i*4+1] << shift0; + drflac_uint32 side2 = pInputSamples0U32[i*4+2] << shift0; + drflac_uint32 side3 = pInputSamples0U32[i*4+3] << shift0; + + drflac_uint32 right0 = pInputSamples1U32[i*4+0] << shift1; + drflac_uint32 right1 = pInputSamples1U32[i*4+1] << shift1; + drflac_uint32 right2 = pInputSamples1U32[i*4+2] << shift1; + drflac_uint32 right3 = pInputSamples1U32[i*4+3] << shift1; + + drflac_uint32 left0 = right0 + side0; + drflac_uint32 left1 = right1 + side1; + drflac_uint32 left2 = right2 + side2; + drflac_uint32 left3 = right3 + side3; + + pOutputSamples[i*8+0] = (drflac_int32)left0; + pOutputSamples[i*8+1] = (drflac_int32)right0; + pOutputSamples[i*8+2] = (drflac_int32)left1; + pOutputSamples[i*8+3] = (drflac_int32)right1; + pOutputSamples[i*8+4] = (drflac_int32)left2; + pOutputSamples[i*8+5] = (drflac_int32)right2; + pOutputSamples[i*8+6] = (drflac_int32)left3; + pOutputSamples[i*8+7] = (drflac_int32)right3; + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 side = pInputSamples0U32[i] << shift0; + drflac_uint32 right = pInputSamples1U32[i] << shift1; + drflac_uint32 left = right + side; + + pOutputSamples[i*2+0] = (drflac_int32)left; + pOutputSamples[i*2+1] = (drflac_int32)right; + } +} + +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + for (i = 0; i < frameCount4; ++i) { + __m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0); + __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); + __m128i left = _mm_add_epi32(right, side); + + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right)); + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 side = pInputSamples0U32[i] << shift0; + drflac_uint32 right = pInputSamples1U32[i] << shift1; + drflac_uint32 left = right + side; + + pOutputSamples[i*2+0] = (drflac_int32)left; + pOutputSamples[i*2+1] = (drflac_int32)right; + } +} +#endif + +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + int32x4_t shift0_4; + int32x4_t shift1_4; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + shift0_4 = vdupq_n_s32(shift0); + shift1_4 = vdupq_n_s32(shift1); + + for (i = 0; i < frameCount4; ++i) { + uint32x4_t side; + uint32x4_t right; + uint32x4_t left; + + side = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4); + right = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4); + left = vaddq_u32(right, side); + + drflac__vst2q_u32((drflac_uint32*)pOutputSamples + i*8, vzipq_u32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 side = pInputSamples0U32[i] << shift0; + drflac_uint32 right = pInputSamples1U32[i] << shift1; + drflac_uint32 left = right + side; + + pOutputSamples[i*2+0] = (drflac_int32)left; + pOutputSamples[i*2+1] = (drflac_int32)right; + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s32__decode_right_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s32__decode_right_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#endif + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_s32__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_s32__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + + +#if 0 +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + for (drflac_uint64 i = 0; i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample); + pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample); + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_int32 shift = unusedBitsPerSample; + + if (shift > 0) { + shift -= 1; + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 temp0L; + drflac_uint32 temp1L; + drflac_uint32 temp2L; + drflac_uint32 temp3L; + drflac_uint32 temp0R; + drflac_uint32 temp1R; + drflac_uint32 temp2R; + drflac_uint32 temp3R; + + drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + + drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid0 = (mid0 << 1) | (side0 & 0x01); + mid1 = (mid1 << 1) | (side1 & 0x01); + mid2 = (mid2 << 1) | (side2 & 0x01); + mid3 = (mid3 << 1) | (side3 & 0x01); + + temp0L = (mid0 + side0) << shift; + temp1L = (mid1 + side1) << shift; + temp2L = (mid2 + side2) << shift; + temp3L = (mid3 + side3) << shift; + + temp0R = (mid0 - side0) << shift; + temp1R = (mid1 - side1) << shift; + temp2R = (mid2 - side2) << shift; + temp3R = (mid3 - side3) << shift; + + pOutputSamples[i*8+0] = (drflac_int32)temp0L; + pOutputSamples[i*8+1] = (drflac_int32)temp0R; + pOutputSamples[i*8+2] = (drflac_int32)temp1L; + pOutputSamples[i*8+3] = (drflac_int32)temp1R; + pOutputSamples[i*8+4] = (drflac_int32)temp2L; + pOutputSamples[i*8+5] = (drflac_int32)temp2R; + pOutputSamples[i*8+6] = (drflac_int32)temp3L; + pOutputSamples[i*8+7] = (drflac_int32)temp3R; + } + } else { + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 temp0L; + drflac_uint32 temp1L; + drflac_uint32 temp2L; + drflac_uint32 temp3L; + drflac_uint32 temp0R; + drflac_uint32 temp1R; + drflac_uint32 temp2R; + drflac_uint32 temp3R; + + drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + + drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid0 = (mid0 << 1) | (side0 & 0x01); + mid1 = (mid1 << 1) | (side1 & 0x01); + mid2 = (mid2 << 1) | (side2 & 0x01); + mid3 = (mid3 << 1) | (side3 & 0x01); + + temp0L = (drflac_uint32)((drflac_int32)(mid0 + side0) >> 1); + temp1L = (drflac_uint32)((drflac_int32)(mid1 + side1) >> 1); + temp2L = (drflac_uint32)((drflac_int32)(mid2 + side2) >> 1); + temp3L = (drflac_uint32)((drflac_int32)(mid3 + side3) >> 1); + + temp0R = (drflac_uint32)((drflac_int32)(mid0 - side0) >> 1); + temp1R = (drflac_uint32)((drflac_int32)(mid1 - side1) >> 1); + temp2R = (drflac_uint32)((drflac_int32)(mid2 - side2) >> 1); + temp3R = (drflac_uint32)((drflac_int32)(mid3 - side3) >> 1); + + pOutputSamples[i*8+0] = (drflac_int32)temp0L; + pOutputSamples[i*8+1] = (drflac_int32)temp0R; + pOutputSamples[i*8+2] = (drflac_int32)temp1L; + pOutputSamples[i*8+3] = (drflac_int32)temp1R; + pOutputSamples[i*8+4] = (drflac_int32)temp2L; + pOutputSamples[i*8+5] = (drflac_int32)temp2R; + pOutputSamples[i*8+6] = (drflac_int32)temp3L; + pOutputSamples[i*8+7] = (drflac_int32)temp3R; + } + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample); + pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample); + } +} + +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_int32 shift = unusedBitsPerSample; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + if (shift == 0) { + for (i = 0; i < frameCount4; ++i) { + __m128i mid; + __m128i side; + __m128i left; + __m128i right; + + mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + + mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01))); + + left = _mm_srai_epi32(_mm_add_epi32(mid, side), 1); + right = _mm_srai_epi32(_mm_sub_epi32(mid, side), 1); + + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right)); + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int32)(mid + side) >> 1; + pOutputSamples[i*2+1] = (drflac_int32)(mid - side) >> 1; + } + } else { + shift -= 1; + for (i = 0; i < frameCount4; ++i) { + __m128i mid; + __m128i side; + __m128i left; + __m128i right; + + mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + + mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01))); + + left = _mm_slli_epi32(_mm_add_epi32(mid, side), shift); + right = _mm_slli_epi32(_mm_sub_epi32(mid, side), shift); + + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right)); + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift); + pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift); + } + } +} +#endif + +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_int32 shift = unusedBitsPerSample; + int32x4_t wbpsShift0_4; /* wbps = Wasted Bits Per Sample */ + int32x4_t wbpsShift1_4; /* wbps = Wasted Bits Per Sample */ + uint32x4_t one4; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + wbpsShift0_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + wbpsShift1_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + one4 = vdupq_n_u32(1); + + if (shift == 0) { + for (i = 0; i < frameCount4; ++i) { + uint32x4_t mid; + uint32x4_t side; + int32x4_t left; + int32x4_t right; + + mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4); + side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4); + + mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, one4)); + + left = vshrq_n_s32(vreinterpretq_s32_u32(vaddq_u32(mid, side)), 1); + right = vshrq_n_s32(vreinterpretq_s32_u32(vsubq_u32(mid, side)), 1); + + drflac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int32)(mid + side) >> 1; + pOutputSamples[i*2+1] = (drflac_int32)(mid - side) >> 1; + } + } else { + int32x4_t shift4; + + shift -= 1; + shift4 = vdupq_n_s32(shift); + + for (i = 0; i < frameCount4; ++i) { + uint32x4_t mid; + uint32x4_t side; + int32x4_t left; + int32x4_t right; + + mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4); + side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4); + + mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, one4)); + + left = vreinterpretq_s32_u32(vshlq_u32(vaddq_u32(mid, side), shift4)); + right = vreinterpretq_s32_u32(vshlq_u32(vsubq_u32(mid, side), shift4)); + + drflac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift); + pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift); + } + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s32__decode_mid_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s32__decode_mid_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#endif + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_s32__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_s32__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + + +#if 0 +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + for (drflac_uint64 i = 0; i < frameCount; ++i) { + pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample)); + pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample)); + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 tempL0 = pInputSamples0U32[i*4+0] << shift0; + drflac_uint32 tempL1 = pInputSamples0U32[i*4+1] << shift0; + drflac_uint32 tempL2 = pInputSamples0U32[i*4+2] << shift0; + drflac_uint32 tempL3 = pInputSamples0U32[i*4+3] << shift0; + + drflac_uint32 tempR0 = pInputSamples1U32[i*4+0] << shift1; + drflac_uint32 tempR1 = pInputSamples1U32[i*4+1] << shift1; + drflac_uint32 tempR2 = pInputSamples1U32[i*4+2] << shift1; + drflac_uint32 tempR3 = pInputSamples1U32[i*4+3] << shift1; + + pOutputSamples[i*8+0] = (drflac_int32)tempL0; + pOutputSamples[i*8+1] = (drflac_int32)tempR0; + pOutputSamples[i*8+2] = (drflac_int32)tempL1; + pOutputSamples[i*8+3] = (drflac_int32)tempR1; + pOutputSamples[i*8+4] = (drflac_int32)tempL2; + pOutputSamples[i*8+5] = (drflac_int32)tempR2; + pOutputSamples[i*8+6] = (drflac_int32)tempL3; + pOutputSamples[i*8+7] = (drflac_int32)tempR3; + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0); + pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1); + } +} + +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + for (i = 0; i < frameCount4; ++i) { + __m128i left = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0); + __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); + + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right)); + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0); + pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1); + } +} +#endif + +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + int32x4_t shift4_0 = vdupq_n_s32(shift0); + int32x4_t shift4_1 = vdupq_n_s32(shift1); + + for (i = 0; i < frameCount4; ++i) { + int32x4_t left; + int32x4_t right; + + left = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift4_0)); + right = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift4_1)); + + drflac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0); + pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1); + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s32__decode_independent_stereo__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s32__decode_independent_stereo__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#endif + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_s32__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_s32__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + + +DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s32(drflac* pFlac, drflac_uint64 framesToRead, drflac_int32* pBufferOut) +{ + drflac_uint64 framesRead; + drflac_uint32 unusedBitsPerSample; + + if (pFlac == NULL || framesToRead == 0) { + return 0; + } + + if (pBufferOut == NULL) { + return drflac__seek_forward_by_pcm_frames(pFlac, framesToRead); + } + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 32); + unusedBitsPerSample = 32 - pFlac->bitsPerSample; + + framesRead = 0; + while (framesToRead > 0) { + /* If we've run out of samples in this frame, go to the next. */ + if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) { + if (!drflac__read_and_decode_next_flac_frame(pFlac)) { + break; /* Couldn't read the next frame, so just break from the loop and return. */ + } + } else { + unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment); + drflac_uint64 iFirstPCMFrame = pFlac->currentFLACFrame.header.blockSizeInPCMFrames - pFlac->currentFLACFrame.pcmFramesRemaining; + drflac_uint64 frameCountThisIteration = framesToRead; + + if (frameCountThisIteration > pFlac->currentFLACFrame.pcmFramesRemaining) { + frameCountThisIteration = pFlac->currentFLACFrame.pcmFramesRemaining; + } + + if (channelCount == 2) { + const drflac_int32* pDecodedSamples0 = pFlac->currentFLACFrame.subframes[0].pSamplesS32 + iFirstPCMFrame; + const drflac_int32* pDecodedSamples1 = pFlac->currentFLACFrame.subframes[1].pSamplesS32 + iFirstPCMFrame; + + switch (pFlac->currentFLACFrame.header.channelAssignment) + { + case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE: + { + drflac_read_pcm_frames_s32__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + + case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE: + { + drflac_read_pcm_frames_s32__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + + case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE: + { + drflac_read_pcm_frames_s32__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + + case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT: + default: + { + drflac_read_pcm_frames_s32__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + } + } else { + /* Generic interleaving. */ + drflac_uint64 i; + for (i = 0; i < frameCountThisIteration; ++i) { + unsigned int j; + for (j = 0; j < channelCount; ++j) { + pBufferOut[(i*channelCount)+j] = (drflac_int32)((drflac_uint32)(pFlac->currentFLACFrame.subframes[j].pSamplesS32[iFirstPCMFrame + i]) << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[j].wastedBitsPerSample)); + } + } + } + + framesRead += frameCountThisIteration; + pBufferOut += frameCountThisIteration * channelCount; + framesToRead -= frameCountThisIteration; + pFlac->currentPCMFrame += frameCountThisIteration; + pFlac->currentFLACFrame.pcmFramesRemaining -= (drflac_uint32)frameCountThisIteration; + } + } + + return framesRead; +} + + +#if 0 +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + drflac_uint64 i; + for (i = 0; i < frameCount; ++i) { + drflac_uint32 left = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + drflac_uint32 right = left - side; + + left >>= 16; + right >>= 16; + + pOutputSamples[i*2+0] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 left0 = pInputSamples0U32[i*4+0] << shift0; + drflac_uint32 left1 = pInputSamples0U32[i*4+1] << shift0; + drflac_uint32 left2 = pInputSamples0U32[i*4+2] << shift0; + drflac_uint32 left3 = pInputSamples0U32[i*4+3] << shift0; + + drflac_uint32 side0 = pInputSamples1U32[i*4+0] << shift1; + drflac_uint32 side1 = pInputSamples1U32[i*4+1] << shift1; + drflac_uint32 side2 = pInputSamples1U32[i*4+2] << shift1; + drflac_uint32 side3 = pInputSamples1U32[i*4+3] << shift1; + + drflac_uint32 right0 = left0 - side0; + drflac_uint32 right1 = left1 - side1; + drflac_uint32 right2 = left2 - side2; + drflac_uint32 right3 = left3 - side3; + + left0 >>= 16; + left1 >>= 16; + left2 >>= 16; + left3 >>= 16; + + right0 >>= 16; + right1 >>= 16; + right2 >>= 16; + right3 >>= 16; + + pOutputSamples[i*8+0] = (drflac_int16)left0; + pOutputSamples[i*8+1] = (drflac_int16)right0; + pOutputSamples[i*8+2] = (drflac_int16)left1; + pOutputSamples[i*8+3] = (drflac_int16)right1; + pOutputSamples[i*8+4] = (drflac_int16)left2; + pOutputSamples[i*8+5] = (drflac_int16)right2; + pOutputSamples[i*8+6] = (drflac_int16)left3; + pOutputSamples[i*8+7] = (drflac_int16)right3; + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 left = pInputSamples0U32[i] << shift0; + drflac_uint32 side = pInputSamples1U32[i] << shift1; + drflac_uint32 right = left - side; + + left >>= 16; + right >>= 16; + + pOutputSamples[i*2+0] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; + } +} + +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + for (i = 0; i < frameCount4; ++i) { + __m128i left = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0); + __m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); + __m128i right = _mm_sub_epi32(left, side); + + left = _mm_srai_epi32(left, 16); + right = _mm_srai_epi32(right, 16); + + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 left = pInputSamples0U32[i] << shift0; + drflac_uint32 side = pInputSamples1U32[i] << shift1; + drflac_uint32 right = left - side; + + left >>= 16; + right >>= 16; + + pOutputSamples[i*2+0] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; + } +} +#endif + +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + int32x4_t shift0_4; + int32x4_t shift1_4; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + shift0_4 = vdupq_n_s32(shift0); + shift1_4 = vdupq_n_s32(shift1); + + for (i = 0; i < frameCount4; ++i) { + uint32x4_t left; + uint32x4_t side; + uint32x4_t right; + + left = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4); + side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4); + right = vsubq_u32(left, side); + + left = vshrq_n_u32(left, 16); + right = vshrq_n_u32(right, 16); + + drflac__vst2q_u16((drflac_uint16*)pOutputSamples + i*8, vzip_u16(vmovn_u32(left), vmovn_u32(right))); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 left = pInputSamples0U32[i] << shift0; + drflac_uint32 side = pInputSamples1U32[i] << shift1; + drflac_uint32 right = left - side; + + left >>= 16; + right >>= 16; + + pOutputSamples[i*2+0] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s16__decode_left_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s16__decode_left_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#endif + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_s16__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_s16__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + + +#if 0 +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + drflac_uint64 i; + for (i = 0; i < frameCount; ++i) { + drflac_uint32 side = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + drflac_uint32 right = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + drflac_uint32 left = right + side; + + left >>= 16; + right >>= 16; + + pOutputSamples[i*2+0] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 side0 = pInputSamples0U32[i*4+0] << shift0; + drflac_uint32 side1 = pInputSamples0U32[i*4+1] << shift0; + drflac_uint32 side2 = pInputSamples0U32[i*4+2] << shift0; + drflac_uint32 side3 = pInputSamples0U32[i*4+3] << shift0; + + drflac_uint32 right0 = pInputSamples1U32[i*4+0] << shift1; + drflac_uint32 right1 = pInputSamples1U32[i*4+1] << shift1; + drflac_uint32 right2 = pInputSamples1U32[i*4+2] << shift1; + drflac_uint32 right3 = pInputSamples1U32[i*4+3] << shift1; + + drflac_uint32 left0 = right0 + side0; + drflac_uint32 left1 = right1 + side1; + drflac_uint32 left2 = right2 + side2; + drflac_uint32 left3 = right3 + side3; + + left0 >>= 16; + left1 >>= 16; + left2 >>= 16; + left3 >>= 16; + + right0 >>= 16; + right1 >>= 16; + right2 >>= 16; + right3 >>= 16; + + pOutputSamples[i*8+0] = (drflac_int16)left0; + pOutputSamples[i*8+1] = (drflac_int16)right0; + pOutputSamples[i*8+2] = (drflac_int16)left1; + pOutputSamples[i*8+3] = (drflac_int16)right1; + pOutputSamples[i*8+4] = (drflac_int16)left2; + pOutputSamples[i*8+5] = (drflac_int16)right2; + pOutputSamples[i*8+6] = (drflac_int16)left3; + pOutputSamples[i*8+7] = (drflac_int16)right3; + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 side = pInputSamples0U32[i] << shift0; + drflac_uint32 right = pInputSamples1U32[i] << shift1; + drflac_uint32 left = right + side; + + left >>= 16; + right >>= 16; + + pOutputSamples[i*2+0] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; + } +} + +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + for (i = 0; i < frameCount4; ++i) { + __m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0); + __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); + __m128i left = _mm_add_epi32(right, side); + + left = _mm_srai_epi32(left, 16); + right = _mm_srai_epi32(right, 16); + + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 side = pInputSamples0U32[i] << shift0; + drflac_uint32 right = pInputSamples1U32[i] << shift1; + drflac_uint32 left = right + side; + + left >>= 16; + right >>= 16; + + pOutputSamples[i*2+0] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; + } +} +#endif + +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + int32x4_t shift0_4; + int32x4_t shift1_4; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + shift0_4 = vdupq_n_s32(shift0); + shift1_4 = vdupq_n_s32(shift1); + + for (i = 0; i < frameCount4; ++i) { + uint32x4_t side; + uint32x4_t right; + uint32x4_t left; + + side = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4); + right = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4); + left = vaddq_u32(right, side); + + left = vshrq_n_u32(left, 16); + right = vshrq_n_u32(right, 16); + + drflac__vst2q_u16((drflac_uint16*)pOutputSamples + i*8, vzip_u16(vmovn_u32(left), vmovn_u32(right))); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 side = pInputSamples0U32[i] << shift0; + drflac_uint32 right = pInputSamples1U32[i] << shift1; + drflac_uint32 left = right + side; + + left >>= 16; + right >>= 16; + + pOutputSamples[i*2+0] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s16__decode_right_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s16__decode_right_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#endif + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_s16__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_s16__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + + +#if 0 +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + for (drflac_uint64 i = 0; i < frameCount; ++i) { + drflac_uint32 mid = (drflac_uint32)pInputSamples0[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample) >> 16); + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift = unusedBitsPerSample; + + if (shift > 0) { + shift -= 1; + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 temp0L; + drflac_uint32 temp1L; + drflac_uint32 temp2L; + drflac_uint32 temp3L; + drflac_uint32 temp0R; + drflac_uint32 temp1R; + drflac_uint32 temp2R; + drflac_uint32 temp3R; + + drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + + drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid0 = (mid0 << 1) | (side0 & 0x01); + mid1 = (mid1 << 1) | (side1 & 0x01); + mid2 = (mid2 << 1) | (side2 & 0x01); + mid3 = (mid3 << 1) | (side3 & 0x01); + + temp0L = (mid0 + side0) << shift; + temp1L = (mid1 + side1) << shift; + temp2L = (mid2 + side2) << shift; + temp3L = (mid3 + side3) << shift; + + temp0R = (mid0 - side0) << shift; + temp1R = (mid1 - side1) << shift; + temp2R = (mid2 - side2) << shift; + temp3R = (mid3 - side3) << shift; + + temp0L >>= 16; + temp1L >>= 16; + temp2L >>= 16; + temp3L >>= 16; + + temp0R >>= 16; + temp1R >>= 16; + temp2R >>= 16; + temp3R >>= 16; + + pOutputSamples[i*8+0] = (drflac_int16)temp0L; + pOutputSamples[i*8+1] = (drflac_int16)temp0R; + pOutputSamples[i*8+2] = (drflac_int16)temp1L; + pOutputSamples[i*8+3] = (drflac_int16)temp1R; + pOutputSamples[i*8+4] = (drflac_int16)temp2L; + pOutputSamples[i*8+5] = (drflac_int16)temp2R; + pOutputSamples[i*8+6] = (drflac_int16)temp3L; + pOutputSamples[i*8+7] = (drflac_int16)temp3R; + } + } else { + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 temp0L; + drflac_uint32 temp1L; + drflac_uint32 temp2L; + drflac_uint32 temp3L; + drflac_uint32 temp0R; + drflac_uint32 temp1R; + drflac_uint32 temp2R; + drflac_uint32 temp3R; + + drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + + drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid0 = (mid0 << 1) | (side0 & 0x01); + mid1 = (mid1 << 1) | (side1 & 0x01); + mid2 = (mid2 << 1) | (side2 & 0x01); + mid3 = (mid3 << 1) | (side3 & 0x01); + + temp0L = ((drflac_int32)(mid0 + side0) >> 1); + temp1L = ((drflac_int32)(mid1 + side1) >> 1); + temp2L = ((drflac_int32)(mid2 + side2) >> 1); + temp3L = ((drflac_int32)(mid3 + side3) >> 1); + + temp0R = ((drflac_int32)(mid0 - side0) >> 1); + temp1R = ((drflac_int32)(mid1 - side1) >> 1); + temp2R = ((drflac_int32)(mid2 - side2) >> 1); + temp3R = ((drflac_int32)(mid3 - side3) >> 1); + + temp0L >>= 16; + temp1L >>= 16; + temp2L >>= 16; + temp3L >>= 16; + + temp0R >>= 16; + temp1R >>= 16; + temp2R >>= 16; + temp3R >>= 16; + + pOutputSamples[i*8+0] = (drflac_int16)temp0L; + pOutputSamples[i*8+1] = (drflac_int16)temp0R; + pOutputSamples[i*8+2] = (drflac_int16)temp1L; + pOutputSamples[i*8+3] = (drflac_int16)temp1R; + pOutputSamples[i*8+4] = (drflac_int16)temp2L; + pOutputSamples[i*8+5] = (drflac_int16)temp2R; + pOutputSamples[i*8+6] = (drflac_int16)temp3L; + pOutputSamples[i*8+7] = (drflac_int16)temp3R; + } + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample) >> 16); + } +} + +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift = unusedBitsPerSample; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + if (shift == 0) { + for (i = 0; i < frameCount4; ++i) { + __m128i mid; + __m128i side; + __m128i left; + __m128i right; + + mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + + mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01))); + + left = _mm_srai_epi32(_mm_add_epi32(mid, side), 1); + right = _mm_srai_epi32(_mm_sub_epi32(mid, side), 1); + + left = _mm_srai_epi32(left, 16); + right = _mm_srai_epi32(right, 16); + + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int16)(((drflac_int32)(mid + side) >> 1) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)(((drflac_int32)(mid - side) >> 1) >> 16); + } + } else { + shift -= 1; + for (i = 0; i < frameCount4; ++i) { + __m128i mid; + __m128i side; + __m128i left; + __m128i right; + + mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + + mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01))); + + left = _mm_slli_epi32(_mm_add_epi32(mid, side), shift); + right = _mm_slli_epi32(_mm_sub_epi32(mid, side), shift); + + left = _mm_srai_epi32(left, 16); + right = _mm_srai_epi32(right, 16); + + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int16)(((mid + side) << shift) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)(((mid - side) << shift) >> 16); + } + } +} +#endif + +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift = unusedBitsPerSample; + int32x4_t wbpsShift0_4; /* wbps = Wasted Bits Per Sample */ + int32x4_t wbpsShift1_4; /* wbps = Wasted Bits Per Sample */ + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + wbpsShift0_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + wbpsShift1_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + + if (shift == 0) { + for (i = 0; i < frameCount4; ++i) { + uint32x4_t mid; + uint32x4_t side; + int32x4_t left; + int32x4_t right; + + mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4); + side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4); + + mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1))); + + left = vshrq_n_s32(vreinterpretq_s32_u32(vaddq_u32(mid, side)), 1); + right = vshrq_n_s32(vreinterpretq_s32_u32(vsubq_u32(mid, side)), 1); + + left = vshrq_n_s32(left, 16); + right = vshrq_n_s32(right, 16); + + drflac__vst2q_s16(pOutputSamples + i*8, vzip_s16(vmovn_s32(left), vmovn_s32(right))); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int16)(((drflac_int32)(mid + side) >> 1) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)(((drflac_int32)(mid - side) >> 1) >> 16); + } + } else { + int32x4_t shift4; + + shift -= 1; + shift4 = vdupq_n_s32(shift); + + for (i = 0; i < frameCount4; ++i) { + uint32x4_t mid; + uint32x4_t side; + int32x4_t left; + int32x4_t right; + + mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4); + side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4); + + mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1))); + + left = vreinterpretq_s32_u32(vshlq_u32(vaddq_u32(mid, side), shift4)); + right = vreinterpretq_s32_u32(vshlq_u32(vsubq_u32(mid, side), shift4)); + + left = vshrq_n_s32(left, 16); + right = vshrq_n_s32(right, 16); + + drflac__vst2q_s16(pOutputSamples + i*8, vzip_s16(vmovn_s32(left), vmovn_s32(right))); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int16)(((mid + side) << shift) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)(((mid - side) << shift) >> 16); + } + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s16__decode_mid_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s16__decode_mid_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#endif + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_s16__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_s16__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + + +#if 0 +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + for (drflac_uint64 i = 0; i < frameCount; ++i) { + pOutputSamples[i*2+0] = (drflac_int16)((drflac_int32)((drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample)) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)((drflac_int32)((drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample)) >> 16); + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 tempL0 = pInputSamples0U32[i*4+0] << shift0; + drflac_uint32 tempL1 = pInputSamples0U32[i*4+1] << shift0; + drflac_uint32 tempL2 = pInputSamples0U32[i*4+2] << shift0; + drflac_uint32 tempL3 = pInputSamples0U32[i*4+3] << shift0; + + drflac_uint32 tempR0 = pInputSamples1U32[i*4+0] << shift1; + drflac_uint32 tempR1 = pInputSamples1U32[i*4+1] << shift1; + drflac_uint32 tempR2 = pInputSamples1U32[i*4+2] << shift1; + drflac_uint32 tempR3 = pInputSamples1U32[i*4+3] << shift1; + + tempL0 >>= 16; + tempL1 >>= 16; + tempL2 >>= 16; + tempL3 >>= 16; + + tempR0 >>= 16; + tempR1 >>= 16; + tempR2 >>= 16; + tempR3 >>= 16; + + pOutputSamples[i*8+0] = (drflac_int16)tempL0; + pOutputSamples[i*8+1] = (drflac_int16)tempR0; + pOutputSamples[i*8+2] = (drflac_int16)tempL1; + pOutputSamples[i*8+3] = (drflac_int16)tempR1; + pOutputSamples[i*8+4] = (drflac_int16)tempL2; + pOutputSamples[i*8+5] = (drflac_int16)tempR2; + pOutputSamples[i*8+6] = (drflac_int16)tempL3; + pOutputSamples[i*8+7] = (drflac_int16)tempR3; + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + pOutputSamples[i*2+0] = (drflac_int16)((pInputSamples0U32[i] << shift0) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)((pInputSamples1U32[i] << shift1) >> 16); + } +} + +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + for (i = 0; i < frameCount4; ++i) { + __m128i left = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0); + __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); + + left = _mm_srai_epi32(left, 16); + right = _mm_srai_epi32(right, 16); + + /* At this point we have results. We can now pack and interleave these into a single __m128i object and then store the in the output buffer. */ + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + pOutputSamples[i*2+0] = (drflac_int16)((pInputSamples0U32[i] << shift0) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)((pInputSamples1U32[i] << shift1) >> 16); + } +} +#endif + +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + int32x4_t shift0_4 = vdupq_n_s32(shift0); + int32x4_t shift1_4 = vdupq_n_s32(shift1); + + for (i = 0; i < frameCount4; ++i) { + int32x4_t left; + int32x4_t right; + + left = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4)); + right = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4)); + + left = vshrq_n_s32(left, 16); + right = vshrq_n_s32(right, 16); + + drflac__vst2q_s16(pOutputSamples + i*8, vzip_s16(vmovn_s32(left), vmovn_s32(right))); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + pOutputSamples[i*2+0] = (drflac_int16)((pInputSamples0U32[i] << shift0) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)((pInputSamples1U32[i] << shift1) >> 16); + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s16__decode_independent_stereo__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s16__decode_independent_stereo__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#endif + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_s16__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_s16__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + +DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s16(drflac* pFlac, drflac_uint64 framesToRead, drflac_int16* pBufferOut) +{ + drflac_uint64 framesRead; + drflac_uint32 unusedBitsPerSample; + + if (pFlac == NULL || framesToRead == 0) { + return 0; + } + + if (pBufferOut == NULL) { + return drflac__seek_forward_by_pcm_frames(pFlac, framesToRead); + } + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 32); + unusedBitsPerSample = 32 - pFlac->bitsPerSample; + + framesRead = 0; + while (framesToRead > 0) { + /* If we've run out of samples in this frame, go to the next. */ + if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) { + if (!drflac__read_and_decode_next_flac_frame(pFlac)) { + break; /* Couldn't read the next frame, so just break from the loop and return. */ + } + } else { + unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment); + drflac_uint64 iFirstPCMFrame = pFlac->currentFLACFrame.header.blockSizeInPCMFrames - pFlac->currentFLACFrame.pcmFramesRemaining; + drflac_uint64 frameCountThisIteration = framesToRead; + + if (frameCountThisIteration > pFlac->currentFLACFrame.pcmFramesRemaining) { + frameCountThisIteration = pFlac->currentFLACFrame.pcmFramesRemaining; + } + + if (channelCount == 2) { + const drflac_int32* pDecodedSamples0 = pFlac->currentFLACFrame.subframes[0].pSamplesS32 + iFirstPCMFrame; + const drflac_int32* pDecodedSamples1 = pFlac->currentFLACFrame.subframes[1].pSamplesS32 + iFirstPCMFrame; + + switch (pFlac->currentFLACFrame.header.channelAssignment) + { + case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE: + { + drflac_read_pcm_frames_s16__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + + case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE: + { + drflac_read_pcm_frames_s16__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + + case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE: + { + drflac_read_pcm_frames_s16__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + + case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT: + default: + { + drflac_read_pcm_frames_s16__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + } + } else { + /* Generic interleaving. */ + drflac_uint64 i; + for (i = 0; i < frameCountThisIteration; ++i) { + unsigned int j; + for (j = 0; j < channelCount; ++j) { + drflac_int32 sampleS32 = (drflac_int32)((drflac_uint32)(pFlac->currentFLACFrame.subframes[j].pSamplesS32[iFirstPCMFrame + i]) << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[j].wastedBitsPerSample)); + pBufferOut[(i*channelCount)+j] = (drflac_int16)(sampleS32 >> 16); + } + } + } + + framesRead += frameCountThisIteration; + pBufferOut += frameCountThisIteration * channelCount; + framesToRead -= frameCountThisIteration; + pFlac->currentPCMFrame += frameCountThisIteration; + pFlac->currentFLACFrame.pcmFramesRemaining -= (drflac_uint32)frameCountThisIteration; + } + } + + return framesRead; +} + + +#if 0 +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + drflac_uint64 i; + for (i = 0; i < frameCount; ++i) { + drflac_uint32 left = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + drflac_uint32 right = left - side; + + pOutputSamples[i*2+0] = (float)((drflac_int32)left / 2147483648.0); + pOutputSamples[i*2+1] = (float)((drflac_int32)right / 2147483648.0); + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + float factor = 1 / 2147483648.0; + + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 left0 = pInputSamples0U32[i*4+0] << shift0; + drflac_uint32 left1 = pInputSamples0U32[i*4+1] << shift0; + drflac_uint32 left2 = pInputSamples0U32[i*4+2] << shift0; + drflac_uint32 left3 = pInputSamples0U32[i*4+3] << shift0; + + drflac_uint32 side0 = pInputSamples1U32[i*4+0] << shift1; + drflac_uint32 side1 = pInputSamples1U32[i*4+1] << shift1; + drflac_uint32 side2 = pInputSamples1U32[i*4+2] << shift1; + drflac_uint32 side3 = pInputSamples1U32[i*4+3] << shift1; + + drflac_uint32 right0 = left0 - side0; + drflac_uint32 right1 = left1 - side1; + drflac_uint32 right2 = left2 - side2; + drflac_uint32 right3 = left3 - side3; + + pOutputSamples[i*8+0] = (drflac_int32)left0 * factor; + pOutputSamples[i*8+1] = (drflac_int32)right0 * factor; + pOutputSamples[i*8+2] = (drflac_int32)left1 * factor; + pOutputSamples[i*8+3] = (drflac_int32)right1 * factor; + pOutputSamples[i*8+4] = (drflac_int32)left2 * factor; + pOutputSamples[i*8+5] = (drflac_int32)right2 * factor; + pOutputSamples[i*8+6] = (drflac_int32)left3 * factor; + pOutputSamples[i*8+7] = (drflac_int32)right3 * factor; + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 left = pInputSamples0U32[i] << shift0; + drflac_uint32 side = pInputSamples1U32[i] << shift1; + drflac_uint32 right = left - side; + + pOutputSamples[i*2+0] = (drflac_int32)left * factor; + pOutputSamples[i*2+1] = (drflac_int32)right * factor; + } +} + +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8; + drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8; + __m128 factor; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + factor = _mm_set1_ps(1.0f / 8388608.0f); + + for (i = 0; i < frameCount4; ++i) { + __m128i left = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0); + __m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); + __m128i right = _mm_sub_epi32(left, side); + __m128 leftf = _mm_mul_ps(_mm_cvtepi32_ps(left), factor); + __m128 rightf = _mm_mul_ps(_mm_cvtepi32_ps(right), factor); + + _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf)); + _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 left = pInputSamples0U32[i] << shift0; + drflac_uint32 side = pInputSamples1U32[i] << shift1; + drflac_uint32 right = left - side; + + pOutputSamples[i*2+0] = (drflac_int32)left / 8388608.0f; + pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f; + } +} +#endif + +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8; + drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8; + float32x4_t factor4; + int32x4_t shift0_4; + int32x4_t shift1_4; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + factor4 = vdupq_n_f32(1.0f / 8388608.0f); + shift0_4 = vdupq_n_s32(shift0); + shift1_4 = vdupq_n_s32(shift1); + + for (i = 0; i < frameCount4; ++i) { + uint32x4_t left; + uint32x4_t side; + uint32x4_t right; + float32x4_t leftf; + float32x4_t rightf; + + left = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4); + side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4); + right = vsubq_u32(left, side); + leftf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(left)), factor4); + rightf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(right)), factor4); + + drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 left = pInputSamples0U32[i] << shift0; + drflac_uint32 side = pInputSamples1U32[i] << shift1; + drflac_uint32 right = left - side; + + pOutputSamples[i*2+0] = (drflac_int32)left / 8388608.0f; + pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f; + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_f32__decode_left_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_f32__decode_left_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#endif + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_f32__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_f32__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + + +#if 0 +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + drflac_uint64 i; + for (i = 0; i < frameCount; ++i) { + drflac_uint32 side = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + drflac_uint32 right = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + drflac_uint32 left = right + side; + + pOutputSamples[i*2+0] = (float)((drflac_int32)left / 2147483648.0); + pOutputSamples[i*2+1] = (float)((drflac_int32)right / 2147483648.0); + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + float factor = 1 / 2147483648.0; + + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 side0 = pInputSamples0U32[i*4+0] << shift0; + drflac_uint32 side1 = pInputSamples0U32[i*4+1] << shift0; + drflac_uint32 side2 = pInputSamples0U32[i*4+2] << shift0; + drflac_uint32 side3 = pInputSamples0U32[i*4+3] << shift0; + + drflac_uint32 right0 = pInputSamples1U32[i*4+0] << shift1; + drflac_uint32 right1 = pInputSamples1U32[i*4+1] << shift1; + drflac_uint32 right2 = pInputSamples1U32[i*4+2] << shift1; + drflac_uint32 right3 = pInputSamples1U32[i*4+3] << shift1; + + drflac_uint32 left0 = right0 + side0; + drflac_uint32 left1 = right1 + side1; + drflac_uint32 left2 = right2 + side2; + drflac_uint32 left3 = right3 + side3; + + pOutputSamples[i*8+0] = (drflac_int32)left0 * factor; + pOutputSamples[i*8+1] = (drflac_int32)right0 * factor; + pOutputSamples[i*8+2] = (drflac_int32)left1 * factor; + pOutputSamples[i*8+3] = (drflac_int32)right1 * factor; + pOutputSamples[i*8+4] = (drflac_int32)left2 * factor; + pOutputSamples[i*8+5] = (drflac_int32)right2 * factor; + pOutputSamples[i*8+6] = (drflac_int32)left3 * factor; + pOutputSamples[i*8+7] = (drflac_int32)right3 * factor; + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 side = pInputSamples0U32[i] << shift0; + drflac_uint32 right = pInputSamples1U32[i] << shift1; + drflac_uint32 left = right + side; + + pOutputSamples[i*2+0] = (drflac_int32)left * factor; + pOutputSamples[i*2+1] = (drflac_int32)right * factor; + } +} + +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8; + drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8; + __m128 factor; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + factor = _mm_set1_ps(1.0f / 8388608.0f); + + for (i = 0; i < frameCount4; ++i) { + __m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0); + __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); + __m128i left = _mm_add_epi32(right, side); + __m128 leftf = _mm_mul_ps(_mm_cvtepi32_ps(left), factor); + __m128 rightf = _mm_mul_ps(_mm_cvtepi32_ps(right), factor); + + _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf)); + _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 side = pInputSamples0U32[i] << shift0; + drflac_uint32 right = pInputSamples1U32[i] << shift1; + drflac_uint32 left = right + side; + + pOutputSamples[i*2+0] = (drflac_int32)left / 8388608.0f; + pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f; + } +} +#endif + +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8; + drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8; + float32x4_t factor4; + int32x4_t shift0_4; + int32x4_t shift1_4; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + factor4 = vdupq_n_f32(1.0f / 8388608.0f); + shift0_4 = vdupq_n_s32(shift0); + shift1_4 = vdupq_n_s32(shift1); + + for (i = 0; i < frameCount4; ++i) { + uint32x4_t side; + uint32x4_t right; + uint32x4_t left; + float32x4_t leftf; + float32x4_t rightf; + + side = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4); + right = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4); + left = vaddq_u32(right, side); + leftf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(left)), factor4); + rightf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(right)), factor4); + + drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 side = pInputSamples0U32[i] << shift0; + drflac_uint32 right = pInputSamples1U32[i] << shift1; + drflac_uint32 left = right + side; + + pOutputSamples[i*2+0] = (drflac_int32)left / 8388608.0f; + pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f; + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_f32__decode_right_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_f32__decode_right_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#endif + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_f32__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_f32__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + + +#if 0 +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + for (drflac_uint64 i = 0; i < frameCount; ++i) { + drflac_uint32 mid = (drflac_uint32)pInputSamples0[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (float)((((drflac_int32)(mid + side) >> 1) << (unusedBitsPerSample)) / 2147483648.0); + pOutputSamples[i*2+1] = (float)((((drflac_int32)(mid - side) >> 1) << (unusedBitsPerSample)) / 2147483648.0); + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift = unusedBitsPerSample; + float factor = 1 / 2147483648.0; + + if (shift > 0) { + shift -= 1; + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 temp0L; + drflac_uint32 temp1L; + drflac_uint32 temp2L; + drflac_uint32 temp3L; + drflac_uint32 temp0R; + drflac_uint32 temp1R; + drflac_uint32 temp2R; + drflac_uint32 temp3R; + + drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + + drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid0 = (mid0 << 1) | (side0 & 0x01); + mid1 = (mid1 << 1) | (side1 & 0x01); + mid2 = (mid2 << 1) | (side2 & 0x01); + mid3 = (mid3 << 1) | (side3 & 0x01); + + temp0L = (mid0 + side0) << shift; + temp1L = (mid1 + side1) << shift; + temp2L = (mid2 + side2) << shift; + temp3L = (mid3 + side3) << shift; + + temp0R = (mid0 - side0) << shift; + temp1R = (mid1 - side1) << shift; + temp2R = (mid2 - side2) << shift; + temp3R = (mid3 - side3) << shift; + + pOutputSamples[i*8+0] = (drflac_int32)temp0L * factor; + pOutputSamples[i*8+1] = (drflac_int32)temp0R * factor; + pOutputSamples[i*8+2] = (drflac_int32)temp1L * factor; + pOutputSamples[i*8+3] = (drflac_int32)temp1R * factor; + pOutputSamples[i*8+4] = (drflac_int32)temp2L * factor; + pOutputSamples[i*8+5] = (drflac_int32)temp2R * factor; + pOutputSamples[i*8+6] = (drflac_int32)temp3L * factor; + pOutputSamples[i*8+7] = (drflac_int32)temp3R * factor; + } + } else { + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 temp0L; + drflac_uint32 temp1L; + drflac_uint32 temp2L; + drflac_uint32 temp3L; + drflac_uint32 temp0R; + drflac_uint32 temp1R; + drflac_uint32 temp2R; + drflac_uint32 temp3R; + + drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + + drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid0 = (mid0 << 1) | (side0 & 0x01); + mid1 = (mid1 << 1) | (side1 & 0x01); + mid2 = (mid2 << 1) | (side2 & 0x01); + mid3 = (mid3 << 1) | (side3 & 0x01); + + temp0L = (drflac_uint32)((drflac_int32)(mid0 + side0) >> 1); + temp1L = (drflac_uint32)((drflac_int32)(mid1 + side1) >> 1); + temp2L = (drflac_uint32)((drflac_int32)(mid2 + side2) >> 1); + temp3L = (drflac_uint32)((drflac_int32)(mid3 + side3) >> 1); + + temp0R = (drflac_uint32)((drflac_int32)(mid0 - side0) >> 1); + temp1R = (drflac_uint32)((drflac_int32)(mid1 - side1) >> 1); + temp2R = (drflac_uint32)((drflac_int32)(mid2 - side2) >> 1); + temp3R = (drflac_uint32)((drflac_int32)(mid3 - side3) >> 1); + + pOutputSamples[i*8+0] = (drflac_int32)temp0L * factor; + pOutputSamples[i*8+1] = (drflac_int32)temp0R * factor; + pOutputSamples[i*8+2] = (drflac_int32)temp1L * factor; + pOutputSamples[i*8+3] = (drflac_int32)temp1R * factor; + pOutputSamples[i*8+4] = (drflac_int32)temp2L * factor; + pOutputSamples[i*8+5] = (drflac_int32)temp2R * factor; + pOutputSamples[i*8+6] = (drflac_int32)temp3L * factor; + pOutputSamples[i*8+7] = (drflac_int32)temp3R * factor; + } + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample) * factor; + pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample) * factor; + } +} + +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift = unusedBitsPerSample - 8; + float factor; + __m128 factor128; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + factor = 1.0f / 8388608.0f; + factor128 = _mm_set1_ps(factor); + + if (shift == 0) { + for (i = 0; i < frameCount4; ++i) { + __m128i mid; + __m128i side; + __m128i tempL; + __m128i tempR; + __m128 leftf; + __m128 rightf; + + mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + + mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01))); + + tempL = _mm_srai_epi32(_mm_add_epi32(mid, side), 1); + tempR = _mm_srai_epi32(_mm_sub_epi32(mid, side), 1); + + leftf = _mm_mul_ps(_mm_cvtepi32_ps(tempL), factor128); + rightf = _mm_mul_ps(_mm_cvtepi32_ps(tempR), factor128); + + _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf)); + _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = ((drflac_int32)(mid + side) >> 1) * factor; + pOutputSamples[i*2+1] = ((drflac_int32)(mid - side) >> 1) * factor; + } + } else { + shift -= 1; + for (i = 0; i < frameCount4; ++i) { + __m128i mid; + __m128i side; + __m128i tempL; + __m128i tempR; + __m128 leftf; + __m128 rightf; + + mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + + mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01))); + + tempL = _mm_slli_epi32(_mm_add_epi32(mid, side), shift); + tempR = _mm_slli_epi32(_mm_sub_epi32(mid, side), shift); + + leftf = _mm_mul_ps(_mm_cvtepi32_ps(tempL), factor128); + rightf = _mm_mul_ps(_mm_cvtepi32_ps(tempR), factor128); + + _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf)); + _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift) * factor; + pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift) * factor; + } + } +} +#endif + +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift = unusedBitsPerSample - 8; + float factor; + float32x4_t factor4; + int32x4_t shift4; + int32x4_t wbps0_4; /* Wasted Bits Per Sample */ + int32x4_t wbps1_4; /* Wasted Bits Per Sample */ + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + factor = 1.0f / 8388608.0f; + factor4 = vdupq_n_f32(factor); + wbps0_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + wbps1_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + + if (shift == 0) { + for (i = 0; i < frameCount4; ++i) { + int32x4_t lefti; + int32x4_t righti; + float32x4_t leftf; + float32x4_t rightf; + + uint32x4_t mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbps0_4); + uint32x4_t side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbps1_4); + + mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1))); + + lefti = vshrq_n_s32(vreinterpretq_s32_u32(vaddq_u32(mid, side)), 1); + righti = vshrq_n_s32(vreinterpretq_s32_u32(vsubq_u32(mid, side)), 1); + + leftf = vmulq_f32(vcvtq_f32_s32(lefti), factor4); + rightf = vmulq_f32(vcvtq_f32_s32(righti), factor4); + + drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = ((drflac_int32)(mid + side) >> 1) * factor; + pOutputSamples[i*2+1] = ((drflac_int32)(mid - side) >> 1) * factor; + } + } else { + shift -= 1; + shift4 = vdupq_n_s32(shift); + for (i = 0; i < frameCount4; ++i) { + uint32x4_t mid; + uint32x4_t side; + int32x4_t lefti; + int32x4_t righti; + float32x4_t leftf; + float32x4_t rightf; + + mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbps0_4); + side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbps1_4); + + mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1))); + + lefti = vreinterpretq_s32_u32(vshlq_u32(vaddq_u32(mid, side), shift4)); + righti = vreinterpretq_s32_u32(vshlq_u32(vsubq_u32(mid, side), shift4)); + + leftf = vmulq_f32(vcvtq_f32_s32(lefti), factor4); + rightf = vmulq_f32(vcvtq_f32_s32(righti), factor4); + + drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift) * factor; + pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift) * factor; + } + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_f32__decode_mid_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_f32__decode_mid_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#endif + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_f32__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_f32__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + +#if 0 +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + for (drflac_uint64 i = 0; i < frameCount; ++i) { + pOutputSamples[i*2+0] = (float)((drflac_int32)((drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample)) / 2147483648.0); + pOutputSamples[i*2+1] = (float)((drflac_int32)((drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample)) / 2147483648.0); + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + float factor = 1 / 2147483648.0; + + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 tempL0 = pInputSamples0U32[i*4+0] << shift0; + drflac_uint32 tempL1 = pInputSamples0U32[i*4+1] << shift0; + drflac_uint32 tempL2 = pInputSamples0U32[i*4+2] << shift0; + drflac_uint32 tempL3 = pInputSamples0U32[i*4+3] << shift0; + + drflac_uint32 tempR0 = pInputSamples1U32[i*4+0] << shift1; + drflac_uint32 tempR1 = pInputSamples1U32[i*4+1] << shift1; + drflac_uint32 tempR2 = pInputSamples1U32[i*4+2] << shift1; + drflac_uint32 tempR3 = pInputSamples1U32[i*4+3] << shift1; + + pOutputSamples[i*8+0] = (drflac_int32)tempL0 * factor; + pOutputSamples[i*8+1] = (drflac_int32)tempR0 * factor; + pOutputSamples[i*8+2] = (drflac_int32)tempL1 * factor; + pOutputSamples[i*8+3] = (drflac_int32)tempR1 * factor; + pOutputSamples[i*8+4] = (drflac_int32)tempL2 * factor; + pOutputSamples[i*8+5] = (drflac_int32)tempR2 * factor; + pOutputSamples[i*8+6] = (drflac_int32)tempL3 * factor; + pOutputSamples[i*8+7] = (drflac_int32)tempR3 * factor; + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0) * factor; + pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1) * factor; + } +} + +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8; + drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8; + + float factor = 1.0f / 8388608.0f; + __m128 factor128 = _mm_set1_ps(factor); + + for (i = 0; i < frameCount4; ++i) { + __m128i lefti; + __m128i righti; + __m128 leftf; + __m128 rightf; + + lefti = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0); + righti = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); + + leftf = _mm_mul_ps(_mm_cvtepi32_ps(lefti), factor128); + rightf = _mm_mul_ps(_mm_cvtepi32_ps(righti), factor128); + + _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf)); + _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0) * factor; + pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1) * factor; + } +} +#endif + +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8; + drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8; + + float factor = 1.0f / 8388608.0f; + float32x4_t factor4 = vdupq_n_f32(factor); + int32x4_t shift0_4 = vdupq_n_s32(shift0); + int32x4_t shift1_4 = vdupq_n_s32(shift1); + + for (i = 0; i < frameCount4; ++i) { + int32x4_t lefti; + int32x4_t righti; + float32x4_t leftf; + float32x4_t rightf; + + lefti = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4)); + righti = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4)); + + leftf = vmulq_f32(vcvtq_f32_s32(lefti), factor4); + rightf = vmulq_f32(vcvtq_f32_s32(righti), factor4); + + drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0) * factor; + pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1) * factor; + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_f32__decode_independent_stereo__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_f32__decode_independent_stereo__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#endif + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_f32__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_f32__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + +DRFLAC_API drflac_uint64 drflac_read_pcm_frames_f32(drflac* pFlac, drflac_uint64 framesToRead, float* pBufferOut) +{ + drflac_uint64 framesRead; + drflac_uint32 unusedBitsPerSample; + + if (pFlac == NULL || framesToRead == 0) { + return 0; + } + + if (pBufferOut == NULL) { + return drflac__seek_forward_by_pcm_frames(pFlac, framesToRead); + } + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 32); + unusedBitsPerSample = 32 - pFlac->bitsPerSample; + + framesRead = 0; + while (framesToRead > 0) { + /* If we've run out of samples in this frame, go to the next. */ + if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) { + if (!drflac__read_and_decode_next_flac_frame(pFlac)) { + break; /* Couldn't read the next frame, so just break from the loop and return. */ + } + } else { + unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment); + drflac_uint64 iFirstPCMFrame = pFlac->currentFLACFrame.header.blockSizeInPCMFrames - pFlac->currentFLACFrame.pcmFramesRemaining; + drflac_uint64 frameCountThisIteration = framesToRead; + + if (frameCountThisIteration > pFlac->currentFLACFrame.pcmFramesRemaining) { + frameCountThisIteration = pFlac->currentFLACFrame.pcmFramesRemaining; + } + + if (channelCount == 2) { + const drflac_int32* pDecodedSamples0 = pFlac->currentFLACFrame.subframes[0].pSamplesS32 + iFirstPCMFrame; + const drflac_int32* pDecodedSamples1 = pFlac->currentFLACFrame.subframes[1].pSamplesS32 + iFirstPCMFrame; + + switch (pFlac->currentFLACFrame.header.channelAssignment) + { + case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE: + { + drflac_read_pcm_frames_f32__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + + case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE: + { + drflac_read_pcm_frames_f32__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + + case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE: + { + drflac_read_pcm_frames_f32__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + + case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT: + default: + { + drflac_read_pcm_frames_f32__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + } + } else { + /* Generic interleaving. */ + drflac_uint64 i; + for (i = 0; i < frameCountThisIteration; ++i) { + unsigned int j; + for (j = 0; j < channelCount; ++j) { + drflac_int32 sampleS32 = (drflac_int32)((drflac_uint32)(pFlac->currentFLACFrame.subframes[j].pSamplesS32[iFirstPCMFrame + i]) << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[j].wastedBitsPerSample)); + pBufferOut[(i*channelCount)+j] = (float)(sampleS32 / 2147483648.0); + } + } + } + + framesRead += frameCountThisIteration; + pBufferOut += frameCountThisIteration * channelCount; + framesToRead -= frameCountThisIteration; + pFlac->currentPCMFrame += frameCountThisIteration; + pFlac->currentFLACFrame.pcmFramesRemaining -= (unsigned int)frameCountThisIteration; + } + } + + return framesRead; +} + + +DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex) +{ + if (pFlac == NULL) { + return DRFLAC_FALSE; + } + + /* Don't do anything if we're already on the seek point. */ + if (pFlac->currentPCMFrame == pcmFrameIndex) { + return DRFLAC_TRUE; + } + + /* + If we don't know where the first frame begins then we can't seek. This will happen when the STREAMINFO block was not present + when the decoder was opened. + */ + if (pFlac->firstFLACFramePosInBytes == 0) { + return DRFLAC_FALSE; + } + + if (pcmFrameIndex == 0) { + pFlac->currentPCMFrame = 0; + return drflac__seek_to_first_frame(pFlac); + } else { + drflac_bool32 wasSuccessful = DRFLAC_FALSE; + drflac_uint64 originalPCMFrame = pFlac->currentPCMFrame; + + /* Clamp the sample to the end. */ + if (pcmFrameIndex > pFlac->totalPCMFrameCount) { + pcmFrameIndex = pFlac->totalPCMFrameCount; + } + + /* If the target sample and the current sample are in the same frame we just move the position forward. */ + if (pcmFrameIndex > pFlac->currentPCMFrame) { + /* Forward. */ + drflac_uint32 offset = (drflac_uint32)(pcmFrameIndex - pFlac->currentPCMFrame); + if (pFlac->currentFLACFrame.pcmFramesRemaining > offset) { + pFlac->currentFLACFrame.pcmFramesRemaining -= offset; + pFlac->currentPCMFrame = pcmFrameIndex; + return DRFLAC_TRUE; + } + } else { + /* Backward. */ + drflac_uint32 offsetAbs = (drflac_uint32)(pFlac->currentPCMFrame - pcmFrameIndex); + drflac_uint32 currentFLACFramePCMFrameCount = pFlac->currentFLACFrame.header.blockSizeInPCMFrames; + drflac_uint32 currentFLACFramePCMFramesConsumed = currentFLACFramePCMFrameCount - pFlac->currentFLACFrame.pcmFramesRemaining; + if (currentFLACFramePCMFramesConsumed > offsetAbs) { + pFlac->currentFLACFrame.pcmFramesRemaining += offsetAbs; + pFlac->currentPCMFrame = pcmFrameIndex; + return DRFLAC_TRUE; + } + } + + /* + Different techniques depending on encapsulation. Using the native FLAC seektable with Ogg encapsulation is a bit awkward so + we'll instead use Ogg's natural seeking facility. + */ +#ifndef DR_FLAC_NO_OGG + if (pFlac->container == drflac_container_ogg) + { + wasSuccessful = drflac_ogg__seek_to_pcm_frame(pFlac, pcmFrameIndex); + } + else +#endif + { + /* First try seeking via the seek table. If this fails, fall back to a brute force seek which is much slower. */ + if (/*!wasSuccessful && */!pFlac->_noSeekTableSeek) { + wasSuccessful = drflac__seek_to_pcm_frame__seek_table(pFlac, pcmFrameIndex); + } + +#if !defined(DR_FLAC_NO_CRC) + /* Fall back to binary search if seek table seeking fails. This requires the length of the stream to be known. */ + if (!wasSuccessful && !pFlac->_noBinarySearchSeek && pFlac->totalPCMFrameCount > 0) { + wasSuccessful = drflac__seek_to_pcm_frame__binary_search(pFlac, pcmFrameIndex); + } +#endif + + /* Fall back to brute force if all else fails. */ + if (!wasSuccessful && !pFlac->_noBruteForceSeek) { + wasSuccessful = drflac__seek_to_pcm_frame__brute_force(pFlac, pcmFrameIndex); + } + } + + if (wasSuccessful) { + pFlac->currentPCMFrame = pcmFrameIndex; + } else { + /* Seek failed. Try putting the decoder back to it's original state. */ + if (drflac_seek_to_pcm_frame(pFlac, originalPCMFrame) == DRFLAC_FALSE) { + /* Failed to seek back to the original PCM frame. Fall back to 0. */ + drflac_seek_to_pcm_frame(pFlac, 0); + } + } + + return wasSuccessful; + } +} + + + +/* High Level APIs */ + +/* SIZE_MAX */ +#if defined(SIZE_MAX) + #define DRFLAC_SIZE_MAX SIZE_MAX +#else + #if defined(DRFLAC_64BIT) + #define DRFLAC_SIZE_MAX ((drflac_uint64)0xFFFFFFFFFFFFFFFF) + #else + #define DRFLAC_SIZE_MAX 0xFFFFFFFF + #endif +#endif +/* End SIZE_MAX */ + + +/* Using a macro as the definition of the drflac__full_decode_and_close_*() API family. Sue me. */ +#define DRFLAC_DEFINE_FULL_READ_AND_CLOSE(extension, type) \ +static type* drflac__full_read_and_close_ ## extension (drflac* pFlac, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut)\ +{ \ + type* pSampleData = NULL; \ + drflac_uint64 totalPCMFrameCount; \ + \ + DRFLAC_ASSERT(pFlac != NULL); \ + \ + totalPCMFrameCount = pFlac->totalPCMFrameCount; \ + \ + if (totalPCMFrameCount == 0) { \ + type buffer[4096]; \ + drflac_uint64 pcmFramesRead; \ + size_t sampleDataBufferSize = sizeof(buffer); \ + \ + pSampleData = (type*)drflac__malloc_from_callbacks(sampleDataBufferSize, &pFlac->allocationCallbacks); \ + if (pSampleData == NULL) { \ + goto on_error; \ + } \ + \ + while ((pcmFramesRead = (drflac_uint64)drflac_read_pcm_frames_##extension(pFlac, sizeof(buffer)/sizeof(buffer[0])/pFlac->channels, buffer)) > 0) { \ + if (((totalPCMFrameCount + pcmFramesRead) * pFlac->channels * sizeof(type)) > sampleDataBufferSize) { \ + type* pNewSampleData; \ + size_t newSampleDataBufferSize; \ + \ + newSampleDataBufferSize = sampleDataBufferSize * 2; \ + pNewSampleData = (type*)drflac__realloc_from_callbacks(pSampleData, newSampleDataBufferSize, sampleDataBufferSize, &pFlac->allocationCallbacks); \ + if (pNewSampleData == NULL) { \ + drflac__free_from_callbacks(pSampleData, &pFlac->allocationCallbacks); \ + goto on_error; \ + } \ + \ + sampleDataBufferSize = newSampleDataBufferSize; \ + pSampleData = pNewSampleData; \ + } \ + \ + DRFLAC_COPY_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), buffer, (size_t)(pcmFramesRead*pFlac->channels*sizeof(type))); \ + totalPCMFrameCount += pcmFramesRead; \ + } \ + \ + /* At this point everything should be decoded, but we just want to fill the unused part buffer with silence - need to \ + protect those ears from random noise! */ \ + DRFLAC_ZERO_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), (size_t)(sampleDataBufferSize - totalPCMFrameCount*pFlac->channels*sizeof(type))); \ + } else { \ + drflac_uint64 dataSize = totalPCMFrameCount*pFlac->channels*sizeof(type); \ + if (dataSize > (drflac_uint64)DRFLAC_SIZE_MAX) { \ + goto on_error; /* The decoded data is too big. */ \ + } \ + \ + pSampleData = (type*)drflac__malloc_from_callbacks((size_t)dataSize, &pFlac->allocationCallbacks); /* <-- Safe cast as per the check above. */ \ + if (pSampleData == NULL) { \ + goto on_error; \ + } \ + \ + totalPCMFrameCount = drflac_read_pcm_frames_##extension(pFlac, pFlac->totalPCMFrameCount, pSampleData); \ + } \ + \ + if (sampleRateOut) *sampleRateOut = pFlac->sampleRate; \ + if (channelsOut) *channelsOut = pFlac->channels; \ + if (totalPCMFrameCountOut) *totalPCMFrameCountOut = totalPCMFrameCount; \ + \ + drflac_close(pFlac); \ + return pSampleData; \ + \ +on_error: \ + drflac_close(pFlac); \ + return NULL; \ +} + +DRFLAC_DEFINE_FULL_READ_AND_CLOSE(s32, drflac_int32) +DRFLAC_DEFINE_FULL_READ_AND_CLOSE(s16, drflac_int16) +DRFLAC_DEFINE_FULL_READ_AND_CLOSE(f32, float) + +DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac* pFlac; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalPCMFrameCountOut) { + *totalPCMFrameCountOut = 0; + } + + pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + + return drflac__full_read_and_close_s32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut); +} + +DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac* pFlac; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalPCMFrameCountOut) { + *totalPCMFrameCountOut = 0; + } + + pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + + return drflac__full_read_and_close_s16(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut); +} + +DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac* pFlac; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalPCMFrameCountOut) { + *totalPCMFrameCountOut = 0; + } + + pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + + return drflac__full_read_and_close_f32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut); +} + +#ifndef DR_FLAC_NO_STDIO +DRFLAC_API drflac_int32* drflac_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac* pFlac; + + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + + pFlac = drflac_open_file(filename, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + + return drflac__full_read_and_close_s32(pFlac, channels, sampleRate, totalPCMFrameCount); +} + +DRFLAC_API drflac_int16* drflac_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac* pFlac; + + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + + pFlac = drflac_open_file(filename, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + + return drflac__full_read_and_close_s16(pFlac, channels, sampleRate, totalPCMFrameCount); +} + +DRFLAC_API float* drflac_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac* pFlac; + + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + + pFlac = drflac_open_file(filename, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + + return drflac__full_read_and_close_f32(pFlac, channels, sampleRate, totalPCMFrameCount); +} +#endif + +DRFLAC_API drflac_int32* drflac_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac* pFlac; + + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + + pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + + return drflac__full_read_and_close_s32(pFlac, channels, sampleRate, totalPCMFrameCount); +} + +DRFLAC_API drflac_int16* drflac_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac* pFlac; + + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + + pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + + return drflac__full_read_and_close_s16(pFlac, channels, sampleRate, totalPCMFrameCount); +} + +DRFLAC_API float* drflac_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac* pFlac; + + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + + pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + + return drflac__full_read_and_close_f32(pFlac, channels, sampleRate, totalPCMFrameCount); +} + + +DRFLAC_API void drflac_free(void* p, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + if (pAllocationCallbacks != NULL) { + drflac__free_from_callbacks(p, pAllocationCallbacks); + } else { + drflac__free_default(p, NULL); + } +} + + + + +DRFLAC_API void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, drflac_uint32 commentCount, const void* pComments) +{ + if (pIter == NULL) { + return; + } + + pIter->countRemaining = commentCount; + pIter->pRunningData = (const char*)pComments; +} + +DRFLAC_API const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, drflac_uint32* pCommentLengthOut) +{ + drflac_int32 length; + const char* pComment; + + /* Safety. */ + if (pCommentLengthOut) { + *pCommentLengthOut = 0; + } + + if (pIter == NULL || pIter->countRemaining == 0 || pIter->pRunningData == NULL) { + return NULL; + } + + length = drflac__le2host_32_ptr_unaligned(pIter->pRunningData); + pIter->pRunningData += 4; + + pComment = pIter->pRunningData; + pIter->pRunningData += length; + pIter->countRemaining -= 1; + + if (pCommentLengthOut) { + *pCommentLengthOut = length; + } + + return pComment; +} + + + + +DRFLAC_API void drflac_init_cuesheet_track_iterator(drflac_cuesheet_track_iterator* pIter, drflac_uint32 trackCount, const void* pTrackData) +{ + if (pIter == NULL) { + return; + } + + pIter->countRemaining = trackCount; + pIter->pRunningData = (const char*)pTrackData; +} + +DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterator* pIter, drflac_cuesheet_track* pCuesheetTrack) +{ + drflac_cuesheet_track cuesheetTrack; + const char* pRunningData; + drflac_uint64 offsetHi; + drflac_uint64 offsetLo; + + if (pIter == NULL || pIter->countRemaining == 0 || pIter->pRunningData == NULL) { + return DRFLAC_FALSE; + } + + pRunningData = pIter->pRunningData; + + offsetHi = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + offsetLo = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + cuesheetTrack.offset = offsetLo | (offsetHi << 32); + cuesheetTrack.trackNumber = pRunningData[0]; pRunningData += 1; + DRFLAC_COPY_MEMORY(cuesheetTrack.ISRC, pRunningData, sizeof(cuesheetTrack.ISRC)); pRunningData += 12; + cuesheetTrack.isAudio = (pRunningData[0] & 0x80) != 0; + cuesheetTrack.preEmphasis = (pRunningData[0] & 0x40) != 0; pRunningData += 14; + cuesheetTrack.indexCount = pRunningData[0]; pRunningData += 1; + cuesheetTrack.pIndexPoints = (const drflac_cuesheet_track_index*)pRunningData; pRunningData += cuesheetTrack.indexCount * sizeof(drflac_cuesheet_track_index); + + pIter->pRunningData = pRunningData; + pIter->countRemaining -= 1; + + if (pCuesheetTrack) { + *pCuesheetTrack = cuesheetTrack; + } + + return DRFLAC_TRUE; +} + +#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #pragma GCC diagnostic pop +#endif +#endif /* dr_flac_c */ +#endif /* DR_FLAC_IMPLEMENTATION */ + + +/* +REVISION HISTORY +================ +v0.12.42 - 2023-11-02 + - Fix build for ARMv6-M. + - Fix a compilation warning with GCC. + +v0.12.41 - 2023-06-17 + - Fix an incorrect date in revision history. No functional change. + +v0.12.40 - 2023-05-22 + - Minor code restructure. No functional change. + +v0.12.39 - 2022-09-17 + - Fix compilation with DJGPP. + - Fix compilation error with Visual Studio 2019 and the ARM build. + - Fix an error with SSE 4.1 detection. + - Add support for disabling wchar_t with DR_WAV_NO_WCHAR. + - Improve compatibility with compilers which lack support for explicit struct packing. + - Improve compatibility with low-end and embedded hardware by reducing the amount of stack + allocation when loading an Ogg encapsulated file. + +v0.12.38 - 2022-04-10 + - Fix compilation error on older versions of GCC. + +v0.12.37 - 2022-02-12 + - Improve ARM detection. + +v0.12.36 - 2022-02-07 + - Fix a compilation error with the ARM build. + +v0.12.35 - 2022-02-06 + - Fix a bug due to underestimating the amount of precision required for the prediction stage. + - Fix some bugs found from fuzz testing. + +v0.12.34 - 2022-01-07 + - Fix some misalignment bugs when reading metadata. + +v0.12.33 - 2021-12-22 + - Fix a bug with seeking when the seek table does not start at PCM frame 0. + +v0.12.32 - 2021-12-11 + - Fix a warning with Clang. + +v0.12.31 - 2021-08-16 + - Silence some warnings. + +v0.12.30 - 2021-07-31 + - Fix platform detection for ARM64. + +v0.12.29 - 2021-04-02 + - Fix a bug where the running PCM frame index is set to an invalid value when over-seeking. + - Fix a decoding error due to an incorrect validation check. + +v0.12.28 - 2021-02-21 + - Fix a warning due to referencing _MSC_VER when it is undefined. + +v0.12.27 - 2021-01-31 + - Fix a static analysis warning. + +v0.12.26 - 2021-01-17 + - Fix a compilation warning due to _BSD_SOURCE being deprecated. + +v0.12.25 - 2020-12-26 + - Update documentation. + +v0.12.24 - 2020-11-29 + - Fix ARM64/NEON detection when compiling with MSVC. + +v0.12.23 - 2020-11-21 + - Fix compilation with OpenWatcom. + +v0.12.22 - 2020-11-01 + - Fix an error with the previous release. + +v0.12.21 - 2020-11-01 + - Fix a possible deadlock when seeking. + - Improve compiler support for older versions of GCC. + +v0.12.20 - 2020-09-08 + - Fix a compilation error on older compilers. + +v0.12.19 - 2020-08-30 + - Fix a bug due to an undefined 32-bit shift. + +v0.12.18 - 2020-08-14 + - Fix a crash when compiling with clang-cl. + +v0.12.17 - 2020-08-02 + - Simplify sized types. + +v0.12.16 - 2020-07-25 + - Fix a compilation warning. + +v0.12.15 - 2020-07-06 + - Check for negative LPC shifts and return an error. + +v0.12.14 - 2020-06-23 + - Add include guard for the implementation section. + +v0.12.13 - 2020-05-16 + - Add compile-time and run-time version querying. + - DRFLAC_VERSION_MINOR + - DRFLAC_VERSION_MAJOR + - DRFLAC_VERSION_REVISION + - DRFLAC_VERSION_STRING + - drflac_version() + - drflac_version_string() + +v0.12.12 - 2020-04-30 + - Fix compilation errors with VC6. + +v0.12.11 - 2020-04-19 + - Fix some pedantic warnings. + - Fix some undefined behaviour warnings. + +v0.12.10 - 2020-04-10 + - Fix some bugs when trying to seek with an invalid seek table. + +v0.12.9 - 2020-04-05 + - Fix warnings. + +v0.12.8 - 2020-04-04 + - Add drflac_open_file_w() and drflac_open_file_with_metadata_w(). + - Fix some static analysis warnings. + - Minor documentation updates. + +v0.12.7 - 2020-03-14 + - Fix compilation errors with VC6. + +v0.12.6 - 2020-03-07 + - Fix compilation error with Visual Studio .NET 2003. + +v0.12.5 - 2020-01-30 + - Silence some static analysis warnings. + +v0.12.4 - 2020-01-29 + - Silence some static analysis warnings. + +v0.12.3 - 2019-12-02 + - Fix some warnings when compiling with GCC and the -Og flag. + - Fix a crash in out-of-memory situations. + - Fix potential integer overflow bug. + - Fix some static analysis warnings. + - Fix a possible crash when using custom memory allocators without a custom realloc() implementation. + - Fix a bug with binary search seeking where the bits per sample is not a multiple of 8. + +v0.12.2 - 2019-10-07 + - Internal code clean up. + +v0.12.1 - 2019-09-29 + - Fix some Clang Static Analyzer warnings. + - Fix an unused variable warning. + +v0.12.0 - 2019-09-23 + - API CHANGE: Add support for user defined memory allocation routines. This system allows the program to specify their own memory allocation + routines with a user data pointer for client-specific contextual data. This adds an extra parameter to the end of the following APIs: + - drflac_open() + - drflac_open_relaxed() + - drflac_open_with_metadata() + - drflac_open_with_metadata_relaxed() + - drflac_open_file() + - drflac_open_file_with_metadata() + - drflac_open_memory() + - drflac_open_memory_with_metadata() + - drflac_open_and_read_pcm_frames_s32() + - drflac_open_and_read_pcm_frames_s16() + - drflac_open_and_read_pcm_frames_f32() + - drflac_open_file_and_read_pcm_frames_s32() + - drflac_open_file_and_read_pcm_frames_s16() + - drflac_open_file_and_read_pcm_frames_f32() + - drflac_open_memory_and_read_pcm_frames_s32() + - drflac_open_memory_and_read_pcm_frames_s16() + - drflac_open_memory_and_read_pcm_frames_f32() + Set this extra parameter to NULL to use defaults which is the same as the previous behaviour. Setting this NULL will use + DRFLAC_MALLOC, DRFLAC_REALLOC and DRFLAC_FREE. + - Remove deprecated APIs: + - drflac_read_s32() + - drflac_read_s16() + - drflac_read_f32() + - drflac_seek_to_sample() + - drflac_open_and_decode_s32() + - drflac_open_and_decode_s16() + - drflac_open_and_decode_f32() + - drflac_open_and_decode_file_s32() + - drflac_open_and_decode_file_s16() + - drflac_open_and_decode_file_f32() + - drflac_open_and_decode_memory_s32() + - drflac_open_and_decode_memory_s16() + - drflac_open_and_decode_memory_f32() + - Remove drflac.totalSampleCount which is now replaced with drflac.totalPCMFrameCount. You can emulate drflac.totalSampleCount + by doing pFlac->totalPCMFrameCount*pFlac->channels. + - Rename drflac.currentFrame to drflac.currentFLACFrame to remove ambiguity with PCM frames. + - Fix errors when seeking to the end of a stream. + - Optimizations to seeking. + - SSE improvements and optimizations. + - ARM NEON optimizations. + - Optimizations to drflac_read_pcm_frames_s16(). + - Optimizations to drflac_read_pcm_frames_s32(). + +v0.11.10 - 2019-06-26 + - Fix a compiler error. + +v0.11.9 - 2019-06-16 + - Silence some ThreadSanitizer warnings. + +v0.11.8 - 2019-05-21 + - Fix warnings. + +v0.11.7 - 2019-05-06 + - C89 fixes. + +v0.11.6 - 2019-05-05 + - Add support for C89. + - Fix a compiler warning when CRC is disabled. + - Change license to choice of public domain or MIT-0. + +v0.11.5 - 2019-04-19 + - Fix a compiler error with GCC. + +v0.11.4 - 2019-04-17 + - Fix some warnings with GCC when compiling with -std=c99. + +v0.11.3 - 2019-04-07 + - Silence warnings with GCC. + +v0.11.2 - 2019-03-10 + - Fix a warning. + +v0.11.1 - 2019-02-17 + - Fix a potential bug with seeking. + +v0.11.0 - 2018-12-16 + - API CHANGE: Deprecated drflac_read_s32(), drflac_read_s16() and drflac_read_f32() and replaced them with + drflac_read_pcm_frames_s32(), drflac_read_pcm_frames_s16() and drflac_read_pcm_frames_f32(). The new APIs take + and return PCM frame counts instead of sample counts. To upgrade you will need to change the input count by + dividing it by the channel count, and then do the same with the return value. + - API_CHANGE: Deprecated drflac_seek_to_sample() and replaced with drflac_seek_to_pcm_frame(). Same rules as + the changes to drflac_read_*() apply. + - API CHANGE: Deprecated drflac_open_and_decode_*() and replaced with drflac_open_*_and_read_*(). Same rules as + the changes to drflac_read_*() apply. + - Optimizations. + +v0.10.0 - 2018-09-11 + - Remove the DR_FLAC_NO_WIN32_IO option and the Win32 file IO functionality. If you need to use Win32 file IO you + need to do it yourself via the callback API. + - Fix the clang build. + - Fix undefined behavior. + - Fix errors with CUESHEET metdata blocks. + - Add an API for iterating over each cuesheet track in the CUESHEET metadata block. This works the same way as the + Vorbis comment API. + - Other miscellaneous bug fixes, mostly relating to invalid FLAC streams. + - Minor optimizations. + +v0.9.11 - 2018-08-29 + - Fix a bug with sample reconstruction. + +v0.9.10 - 2018-08-07 + - Improve 64-bit detection. + +v0.9.9 - 2018-08-05 + - Fix C++ build on older versions of GCC. + +v0.9.8 - 2018-07-24 + - Fix compilation errors. + +v0.9.7 - 2018-07-05 + - Fix a warning. + +v0.9.6 - 2018-06-29 + - Fix some typos. + +v0.9.5 - 2018-06-23 + - Fix some warnings. + +v0.9.4 - 2018-06-14 + - Optimizations to seeking. + - Clean up. + +v0.9.3 - 2018-05-22 + - Bug fix. + +v0.9.2 - 2018-05-12 + - Fix a compilation error due to a missing break statement. + +v0.9.1 - 2018-04-29 + - Fix compilation error with Clang. + +v0.9 - 2018-04-24 + - Fix Clang build. + - Start using major.minor.revision versioning. + +v0.8g - 2018-04-19 + - Fix build on non-x86/x64 architectures. + +v0.8f - 2018-02-02 + - Stop pretending to support changing rate/channels mid stream. + +v0.8e - 2018-02-01 + - Fix a crash when the block size of a frame is larger than the maximum block size defined by the FLAC stream. + - Fix a crash the the Rice partition order is invalid. + +v0.8d - 2017-09-22 + - Add support for decoding streams with ID3 tags. ID3 tags are just skipped. + +v0.8c - 2017-09-07 + - Fix warning on non-x86/x64 architectures. + +v0.8b - 2017-08-19 + - Fix build on non-x86/x64 architectures. + +v0.8a - 2017-08-13 + - A small optimization for the Clang build. + +v0.8 - 2017-08-12 + - API CHANGE: Rename dr_* types to drflac_*. + - Optimizations. This brings dr_flac back to about the same class of efficiency as the reference implementation. + - Add support for custom implementations of malloc(), realloc(), etc. + - Add CRC checking to Ogg encapsulated streams. + - Fix VC++ 6 build. This is only for the C++ compiler. The C compiler is not currently supported. + - Bug fixes. + +v0.7 - 2017-07-23 + - Add support for opening a stream without a header block. To do this, use drflac_open_relaxed() / drflac_open_with_metadata_relaxed(). + +v0.6 - 2017-07-22 + - Add support for recovering from invalid frames. With this change, dr_flac will simply skip over invalid frames as if they + never existed. Frames are checked against their sync code, the CRC-8 of the frame header and the CRC-16 of the whole frame. + +v0.5 - 2017-07-16 + - Fix typos. + - Change drflac_bool* types to unsigned. + - Add CRC checking. This makes dr_flac slower, but can be disabled with #define DR_FLAC_NO_CRC. + +v0.4f - 2017-03-10 + - Fix a couple of bugs with the bitstreaming code. + +v0.4e - 2017-02-17 + - Fix some warnings. + +v0.4d - 2016-12-26 + - Add support for 32-bit floating-point PCM decoding. + - Use drflac_int* and drflac_uint* sized types to improve compiler support. + - Minor improvements to documentation. + +v0.4c - 2016-12-26 + - Add support for signed 16-bit integer PCM decoding. + +v0.4b - 2016-10-23 + - A minor change to drflac_bool8 and drflac_bool32 types. + +v0.4a - 2016-10-11 + - Rename drBool32 to drflac_bool32 for styling consistency. + +v0.4 - 2016-09-29 + - API/ABI CHANGE: Use fixed size 32-bit booleans instead of the built-in bool type. + - API CHANGE: Rename drflac_open_and_decode*() to drflac_open_and_decode*_s32(). + - API CHANGE: Swap the order of "channels" and "sampleRate" parameters in drflac_open_and_decode*(). Rationale for this is to + keep it consistent with drflac_audio. + +v0.3f - 2016-09-21 + - Fix a warning with GCC. + +v0.3e - 2016-09-18 + - Fixed a bug where GCC 4.3+ was not getting properly identified. + - Fixed a few typos. + - Changed date formats to ISO 8601 (YYYY-MM-DD). + +v0.3d - 2016-06-11 + - Minor clean up. + +v0.3c - 2016-05-28 + - Fixed compilation error. + +v0.3b - 2016-05-16 + - Fixed Linux/GCC build. + - Updated documentation. + +v0.3a - 2016-05-15 + - Minor fixes to documentation. + +v0.3 - 2016-05-11 + - Optimizations. Now at about parity with the reference implementation on 32-bit builds. + - Lots of clean up. + +v0.2b - 2016-05-10 + - Bug fixes. + +v0.2a - 2016-05-10 + - Made drflac_open_and_decode() more robust. + - Removed an unused debugging variable + +v0.2 - 2016-05-09 + - Added support for Ogg encapsulation. + - API CHANGE. Have the onSeek callback take a third argument which specifies whether or not the seek + should be relative to the start or the current position. Also changes the seeking rules such that + seeking offsets will never be negative. + - Have drflac_open_and_decode() fail gracefully if the stream has an unknown total sample count. + +v0.1b - 2016-05-07 + - Properly close the file handle in drflac_open_file() and family when the decoder fails to initialize. + - Removed a stale comment. + +v0.1a - 2016-05-05 + - Minor formatting changes. + - Fixed a warning on the GCC build. + +v0.1 - 2016-05-03 + - Initial versioned release. +*/ + +/* +This software is available as a choice of the following licenses. Choose +whichever you prefer. + +=============================================================================== +ALTERNATIVE 1 - Public Domain (www.unlicense.org) +=============================================================================== +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. + +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to + +=============================================================================== +ALTERNATIVE 2 - MIT No Attribution +=============================================================================== +Copyright 2023 David Reid + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ diff --git a/lib/libchdr/include/libchdr/chd.h b/lib/libchdr/include/libchdr/chd.h index 6d86a90..36fe2a3 100644 --- a/lib/libchdr/include/libchdr/chd.h +++ b/lib/libchdr/include/libchdr/chd.h @@ -204,10 +204,15 @@ extern "C" { #define CHD_CODEC_NONE 0 #define CHD_CODEC_ZLIB CHD_MAKE_TAG('z','l','i','b') +#define CHD_CODEC_LZMA CHD_MAKE_TAG('l','z','m','a') +#define CHD_CODEC_HUFFMAN CHD_MAKE_TAG('h','u','f','f') +#define CHD_CODEC_FLAC CHD_MAKE_TAG('f','l','a','c') +#define CHD_CODEC_ZSTD CHD_MAKE_TAG('z', 's', 't', 'd') /* general codecs with CD frontend */ #define CHD_CODEC_CD_ZLIB CHD_MAKE_TAG('c','d','z','l') #define CHD_CODEC_CD_LZMA CHD_MAKE_TAG('c','d','l','z') #define CHD_CODEC_CD_FLAC CHD_MAKE_TAG('c','d','f','l') +#define CHD_CODEC_CD_ZSTD CHD_MAKE_TAG('c','d','z','s') /* A/V codec configuration parameters */ #define AV_CODEC_COMPRESS_CONFIG 1 @@ -370,7 +375,8 @@ struct _chd_verify_result /* chd_error chd_create_file(core_file *file, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 compression, chd_file *parent); */ /* open an existing CHD file */ -CHD_EXPORT chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file **chd); +CHD_EXPORT chd_error chd_open_core_file(core_file *file, int mode, chd_file *parent, chd_file **chd); +CHD_EXPORT chd_error chd_open_file(FILE *file, int mode, chd_file *parent, chd_file **chd); CHD_EXPORT chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd); /* precache underlying file */ @@ -392,6 +398,8 @@ CHD_EXPORT const char *chd_error_string(chd_error err); /* return a pointer to the extracted CHD header data */ CHD_EXPORT const chd_header *chd_get_header(chd_file *chd); +/* read CHD header data from file into the pointed struct */ +CHD_EXPORT chd_error chd_read_header(const char *filename, chd_header *header); @@ -418,7 +426,6 @@ CHD_EXPORT chd_error chd_codec_config(chd_file *chd, int param, void *config); /* return a string description of a codec */ CHD_EXPORT const char *chd_get_codec_name(UINT32 codec); - #ifdef __cplusplus } #endif diff --git a/lib/libchdr/include/libchdr/chdconfig.h b/lib/libchdr/include/libchdr/chdconfig.h index c2fd579..752038b 100644 --- a/lib/libchdr/include/libchdr/chdconfig.h +++ b/lib/libchdr/include/libchdr/chdconfig.h @@ -3,7 +3,7 @@ /* Configure CHDR features here */ #define WANT_RAW_DATA_SECTOR 1 -#define WANT_SUBCODE 1 +#define WANT_SUBCODE 1 #define NEED_CACHE_HUNK 1 #define VERIFY_BLOCK_CRC 1 diff --git a/lib/libchdr/include/libchdr/coretypes.h b/lib/libchdr/include/libchdr/coretypes.h index 2ff73df..805359b 100644 --- a/lib/libchdr/include/libchdr/coretypes.h +++ b/lib/libchdr/include/libchdr/coretypes.h @@ -4,12 +4,21 @@ #include #include -#ifdef __LIBRETRO__ +#ifdef USE_LIBRETRO_VFS #include #endif #define ARRAY_LENGTH(x) (sizeof(x)/sizeof(x[0])) +#if defined(__PS3__) || defined(__PSL1GHT__) +#undef UINT32 +#undef UINT16 +#undef UINT8 +#undef INT32 +#undef INT16 +#undef INT8 +#endif + typedef uint64_t UINT64; typedef uint32_t UINT32; typedef uint16_t UINT16; @@ -20,20 +29,50 @@ typedef int32_t INT32; typedef int16_t INT16; typedef int8_t INT8; -#define core_file FILE -#define core_fopen(file) fopen(file, "rb") -#define core_fseek fseek -#define core_fread(fc, buff, len) fread(buff, 1, len, fc) -#define core_fclose fclose -#define core_ftell ftell -inline size_t core_fsize(core_file *f) +typedef struct chd_core_file { + /* + * arbitrary pointer to data the implementation uses to implement the below functions + */ + void *argp; + + /* + * return the size of a given file as a 64-bit unsigned integer. + * the position of the file pointer after calling this function is + * undefined because many implementations will seek to the end of the + * file and call ftell. + * + * on error, (UINT64)-1 is returned. + */ + UINT64(*fsize)(struct chd_core_file*); + + /* + * should match the behavior of fread, except the FILE* argument at the end + * will be replaced with a struct chd_core_file*. + */ + size_t(*fread)(void*,size_t,size_t,struct chd_core_file*); + + // closes the given file. + int (*fclose)(struct chd_core_file*); + + // fseek clone + int (*fseek)(struct chd_core_file*, INT64, int); +} core_file; + +static inline int core_fclose(core_file *fp) { + return fp->fclose(fp); +} + +static inline size_t core_fread(core_file *fp, void *ptr, size_t len) { + return fp->fread(ptr, 1, len, fp); +} + +static inline int core_fseek(core_file* fp, INT64 offset, int whence) { + return fp->fseek(fp, offset, whence); +} + +static inline UINT64 core_fsize(core_file *fp) { - long rv; - long p = ftell(f); - fseek(f, 0, SEEK_END); - rv = ftell(f); - fseek(f, p, SEEK_SET); - return rv; + return fp->fsize(fp); } #endif diff --git a/lib/libchdr/include/libchdr/flac.h b/lib/libchdr/include/libchdr/flac.h index 6cf011f..bff255b 100644 --- a/lib/libchdr/include/libchdr/flac.h +++ b/lib/libchdr/include/libchdr/flac.h @@ -14,7 +14,6 @@ #define __FLAC_H__ #include -#include /*************************************************************************** * TYPE DEFINITIONS @@ -24,14 +23,14 @@ typedef struct _flac_decoder flac_decoder; struct _flac_decoder { /* output state */ - FLAC__StreamDecoder* decoder; /* actual encoder */ + void * decoder; /* actual encoder */ uint32_t sample_rate; /* decoded sample rate */ uint8_t channels; /* decoded number of channels */ uint8_t bits_per_sample; /* decoded bits per sample */ uint32_t compressed_offset; /* current offset in compressed data */ - const FLAC__byte * compressed_start; /* start of compressed data */ + const uint8_t * compressed_start; /* start of compressed data */ uint32_t compressed_length; /* length of compressed data */ - const FLAC__byte * compressed2_start; /* start of compressed data */ + const uint8_t * compressed2_start; /* start of compressed data */ uint32_t compressed2_length; /* length of compressed data */ int16_t * uncompressed_start[8]; /* pointer to start of uncompressed data (up to 8 streams) */ uint32_t uncompressed_offset; /* current position in uncompressed data */ @@ -42,7 +41,7 @@ struct _flac_decoder { /* ======================> flac_decoder */ -void flac_decoder_init(flac_decoder* decoder); +int flac_decoder_init(flac_decoder* decoder); void flac_decoder_free(flac_decoder* decoder); int flac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_channels, uint32_t block_size, const void *buffer, uint32_t length); int flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uint32_t num_samples, int swap_endian); diff --git a/lib/libchdr/libchdr_cdrom.c b/lib/libchdr/libchdr_cdrom.c index 58be015..112ea2e 100644 --- a/lib/libchdr/libchdr_cdrom.c +++ b/lib/libchdr/libchdr_cdrom.c @@ -15,7 +15,7 @@ schemes will differ after track 1! ***************************************************************************/ -#include + #include #include diff --git a/lib/libchdr/libchdr_chd.c b/lib/libchdr/libchdr_chd.c index 416769b..3f747cc 100644 --- a/lib/libchdr/libchdr_chd.c +++ b/lib/libchdr/libchdr_chd.c @@ -47,10 +47,14 @@ #include #include #include +#include #include "LzmaEnc.h" #include "LzmaDec.h" -#include "miniz.h" +#if defined(__PS3__) || defined(__PSL1GHT__) +#define __MACTYPES__ +#endif +#include #undef TRUE #undef FALSE @@ -224,6 +228,18 @@ struct _lzma_codec_data lzma_allocator allocator; }; +typedef struct _huff_codec_data huff_codec_data; +struct _huff_codec_data +{ + struct huffman_decoder* decoder; +}; + +typedef struct _zstd_codec_data zstd_codec_data; +struct _zstd_codec_data +{ + ZSTD_DStream *dstream; +}; + /* codec-private data for the CDZL codec */ typedef struct _cdzl_codec_data cdzl_codec_data; struct _cdzl_codec_data { @@ -246,6 +262,14 @@ struct _cdlz_codec_data { uint8_t* buffer; }; +/* codec-private data for the FLAC codec */ +typedef struct _flac_codec_data flac_codec_data; +struct _flac_codec_data { + /* internal state */ + int native_endian; + flac_decoder decoder; +}; + /* codec-private data for the CDFL codec */ typedef struct _cdfl_codec_data cdfl_codec_data; struct _cdfl_codec_data { @@ -258,13 +282,22 @@ struct _cdfl_codec_data { uint8_t* buffer; }; +typedef struct _cdzs_codec_data cdzs_codec_data; +struct _cdzs_codec_data +{ + zstd_codec_data base_decompressor; +#ifdef WANT_SUBCODE + zstd_codec_data subcode_decompressor; +#endif + uint8_t* buffer; +}; + /* internal representation of an open CHD file */ struct _chd_file { UINT32 cookie; /* cookie, should equal COOKIE_VALUE */ core_file * file; /* handle to the open core file */ - UINT8 owns_file; /* flag indicating if this file should be closed on chd_close() */ chd_header header; /* header, extracted from file */ chd_file * parent; /* pointer to parent file, or NULL */ @@ -283,9 +316,14 @@ struct _chd_file const codec_interface * codecintf[4]; /* interface to the codec */ zlib_codec_data zlib_codec_data; /* zlib codec data */ + lzma_codec_data lzma_codec_data; /* lzma codec data */ + huff_codec_data huff_codec_data; /* huff codec data */ + flac_codec_data flac_codec_data; /* flac codec data */ + zstd_codec_data zstd_codec_data; /* zstd codec data */ cdzl_codec_data cdzl_codec_data; /* cdzl codec data */ cdlz_codec_data cdlz_codec_data; /* cdlz codec data */ cdfl_codec_data cdfl_codec_data; /* cdfl codec data */ + cdzs_codec_data cdzs_codec_data; /* cdzs codec data */ #ifdef NEED_CACHE_HUNK UINT32 maxhunk; /* maximum hunk accessed */ @@ -306,11 +344,22 @@ static const UINT8 nullsha1[CHD_SHA1_BYTES] = { 0 }; PROTOTYPES ***************************************************************************/ +/* core_file wrappers over stdio */ +static core_file *core_stdio_fopen(char const *path); +static UINT64 core_stdio_fsize(core_file *file); +static size_t core_stdio_fread(void *ptr, size_t size, size_t nmemb, core_file *file); +static int core_stdio_fclose(core_file *file); +static int core_stdio_fclose_nonowner(core_file *file); // alternate fclose used by chd_open_file +static int core_stdio_fseek(core_file* file, INT64 offset, int whence); + /* internal header operations */ static chd_error header_validate(const chd_header *header); static chd_error header_read(chd_file *chd, chd_header *header); /* internal hunk read/write */ +#ifdef NEED_CACHE_HUNK +static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum); +#endif static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *dest); /* internal map access */ @@ -332,6 +381,22 @@ static chd_error lzma_codec_init(void *codec, uint32_t hunkbytes); static void lzma_codec_free(void *codec); static chd_error lzma_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); +/* huff compression codec */ +static chd_error huff_codec_init(void *codec, uint32_t hunkbytes); +static void huff_codec_free(void *codec); +static chd_error huff_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); + +/* flac compression codec */ +static chd_error flac_codec_init(void *codec, uint32_t hunkbytes); +static void flac_codec_free(void *codec); +static chd_error flac_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); + +/* zstd compression codec */ +static chd_error zstd_codec_init(void *codec, uint32_t hunkbytes); +static void zstd_codec_free(void *codec); +static chd_error zstd_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); + + /* cdzl compression codec */ static chd_error cdzl_codec_init(void* codec, uint32_t hunkbytes); static void cdzl_codec_free(void* codec); @@ -347,6 +412,11 @@ static chd_error cdfl_codec_init(void* codec, uint32_t hunkbytes); static void cdfl_codec_free(void* codec); static chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); +/* cdzs compression codec */ +static chd_error cdzs_codec_init(void *codec, uint32_t hunkbytes); +static void cdzs_codec_free(void *codec); +static chd_error cdzs_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); + /*************************************************************************** * LZMA ALLOCATOR HELPER *************************************************************************** @@ -427,7 +497,7 @@ static void *lzma_fast_alloc(void *p, size_t size) addr = (uint32_t *)malloc(size + sizeof(uint32_t) + LZMA_MIN_ALIGNMENT_BYTES); if (addr==NULL) return NULL; - for (int scan = 0; scan < MAX_LZMA_ALLOCS; scan++) + for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++) { if (codec->allocptr[scan] == NULL) { @@ -743,24 +813,122 @@ static chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t return CHDERR_NONE; } +/*************************************************************************** + * HUFFMAN DECOMPRESSOR + *************************************************************************** + */ + +static chd_error huff_codec_init(void* codec, uint32_t hunkbytes) +{ + huff_codec_data* huff_codec = (huff_codec_data*) codec; + huff_codec->decoder = create_huffman_decoder(256, 16); + return CHDERR_NONE; +} + +static void huff_codec_free(void *codec) +{ + huff_codec_data* huff_codec = (huff_codec_data*) codec; + delete_huffman_decoder(huff_codec->decoder); +} + +static chd_error huff_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) +{ + huff_codec_data* huff_codec = (huff_codec_data*) codec; + struct bitstream* bitbuf = create_bitstream(src, complen); + + // first import the tree + enum huffman_error err = huffman_import_tree_huffman(huff_codec->decoder, bitbuf); + if (err != HUFFERR_NONE) + { + free(bitbuf); + return CHDERR_DECOMPRESSION_ERROR; + } + + // then decode the data + uint32_t cur; + for (cur = 0; cur < destlen; cur++) + dest[cur] = huffman_decode_one(huff_codec->decoder, bitbuf); + bitstream_flush(bitbuf); + chd_error result = bitstream_overflow(bitbuf) ? CHDERR_DECOMPRESSION_ERROR : CHDERR_NONE; + + free(bitbuf); + return result; +} + /*************************************************************************** * CD FLAC DECOMPRESSOR *************************************************************************** */ /*------------------------------------------------------ - * cdfl_codec_blocksize - return the optimal block size + * flac_codec_blocksize - return the optimal block size *------------------------------------------------------ */ -static uint32_t cdfl_codec_blocksize(uint32_t bytes) +static uint32_t flac_codec_blocksize(uint32_t bytes) { /* determine FLAC block size, which must be 16-65535 * clamp to 2k since that's supposed to be the sweet spot */ - uint32_t hunkbytes = bytes / 4; - while (hunkbytes > 2048) - hunkbytes /= 2; - return hunkbytes; + uint32_t blocksize = bytes / 4; + while (blocksize > 2048) + blocksize /= 2; + return blocksize; +} + +static chd_error flac_codec_init(void *codec, uint32_t hunkbytes) +{ + uint16_t native_endian = 0; + flac_codec_data *flac = (flac_codec_data*)codec; + + /* make sure the CHD's hunk size is an even multiple of the sample size */ + if (hunkbytes % 4 != 0) + return CHDERR_CODEC_ERROR; + + /* determine whether we want native or swapped samples */ + *(uint8_t *)(&native_endian) = 1; + flac->native_endian = (native_endian & 1); + + /* flac decoder init */ + if (flac_decoder_init(&flac->decoder)) + return CHDERR_OUT_OF_MEMORY; + + return CHDERR_NONE; +} + +static void flac_codec_free(void *codec) +{ + flac_codec_data *flac = (flac_codec_data*)codec; + flac_decoder_free(&flac->decoder); +} + +static chd_error flac_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) +{ + flac_codec_data *flac = (flac_codec_data*)codec; + int swap_endian; + + if (src[0] == 'L') + swap_endian = !flac->native_endian; + else if (src[0] == 'B') + swap_endian = flac->native_endian; + else + return CHDERR_DECOMPRESSION_ERROR; + + if (!flac_decoder_reset(&flac->decoder, 44100, 2, flac_codec_blocksize(destlen), src + 1, complen - 1)) + return CHDERR_DECOMPRESSION_ERROR; + if (!flac_decoder_decode_interleaved(&flac->decoder, (int16_t *)(dest), destlen/4, swap_endian)) + return CHDERR_DECOMPRESSION_ERROR; + flac_decoder_finish(&flac->decoder); + + return CHDERR_NONE; +} + +static uint32_t cdfl_codec_blocksize(uint32_t bytes) +{ + // for CDs it seems that CD_MAX_SECTOR_DATA is the right target + uint32_t blocksize = bytes / 4; + while (blocksize > CD_MAX_SECTOR_DATA) + blocksize /= 2; + return blocksize; } static chd_error cdfl_codec_init(void *codec, uint32_t hunkbytes) @@ -791,8 +959,7 @@ static chd_error cdfl_codec_init(void *codec, uint32_t hunkbytes) #endif /* flac decoder init */ - flac_decoder_init(&cdfl->decoder); - if (cdfl->decoder.decoder == NULL) + if (flac_decoder_init(&cdfl->decoder)) return CHDERR_OUT_OF_MEMORY; return CHDERR_NONE; @@ -849,6 +1016,163 @@ static chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t return CHDERR_NONE; } + + +/*************************************************************************** + * ZSTD DECOMPRESSOR + *************************************************************************** + */ + +/*------------------------------------------------- + * zstd_codec_init - constructor + *------------------------------------------------- + */ + +static chd_error zstd_codec_init(void* codec, uint32_t hunkbytes) +{ + zstd_codec_data* zstd_codec = (zstd_codec_data*) codec; + + zstd_codec->dstream = ZSTD_createDStream(); + if (!zstd_codec->dstream) { + printf("NO DSTREAM CREATED!\n"); + return CHDERR_DECOMPRESSION_ERROR; + } + return CHDERR_NONE; +} + +/*------------------------------------------------- + * zstd_codec_free + *------------------------------------------------- + */ + +static void zstd_codec_free(void* codec) +{ + zstd_codec_data* zstd_codec = (zstd_codec_data*) codec; + + ZSTD_freeDStream(zstd_codec->dstream); +} + +/*------------------------------------------------- + * decompress - decompress data using the ZSTD + * codec + *------------------------------------------------- + */ +static chd_error zstd_codec_decompress(void* codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) +{ + /* initialize */ + zstd_codec_data* zstd_codec = (zstd_codec_data*) codec; + //reset decompressor + size_t zstd_res = ZSTD_initDStream(zstd_codec->dstream); + if (ZSTD_isError(zstd_res)) + { + printf("INITI DSTREAM FAILED!\n"); + return CHDERR_DECOMPRESSION_ERROR; + } + + ZSTD_inBuffer input = {src, complen, 0}; + ZSTD_outBuffer output = {dest, destlen, 0 }; + + while ((input.pos < input.size) && (output.pos < output.size)) + { + zstd_res = ZSTD_decompressStream(zstd_codec->dstream, &output, &input); + if (ZSTD_isError(zstd_res)) + { + printf("DECOMPRESSION ERROR IN LOOP\n"); + return CHDERR_DECOMPRESSION_ERROR; + } + } + if (output.pos != output.size) + { + printf("OUTPUT DOESN'T MATCH!\n"); + return CHDERR_DECOMPRESSION_ERROR; + } + return CHDERR_NONE; + +} + +/* cdzs */ +static chd_error cdzs_codec_init(void* codec, uint32_t hunkbytes) +{ + chd_error ret; + cdzs_codec_data* cdzs = (cdzs_codec_data*) codec; + + /* allocate buffer */ + cdzs->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes); + if (cdzs->buffer == NULL) + return CHDERR_OUT_OF_MEMORY; + + /* make sure the CHD's hunk size is an even multiple of the frame size */ + ret = zstd_codec_init(&cdzs->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA); + if (ret != CHDERR_NONE) + return ret; + +#ifdef WANT_SUBCODE + ret = zstd_codec_init(&cdzs->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SUBCODE_DATA); + if (ret != CHDERR_NONE) + return ret; +#endif + + if (hunkbytes % CD_FRAME_SIZE != 0) + return CHDERR_CODEC_ERROR; + + return CHDERR_NONE; +} + +static void cdzs_codec_free(void* codec) +{ + cdzs_codec_data* cdzs = (cdzs_codec_data*) codec; + free(cdzs->buffer); + zstd_codec_free(&cdzs->base_decompressor); +#ifdef WANT_SUBCODE + zstd_codec_free(&cdzs->subcode_decompressor); +#endif +} + +static chd_error cdzs_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) +{ + uint32_t framenum; + cdzs_codec_data* cdzs = (cdzs_codec_data*)codec; + + /* determine header bytes */ + uint32_t frames = destlen / CD_FRAME_SIZE; + uint32_t complen_bytes = (destlen < 65536) ? 2 : 3; + uint32_t ecc_bytes = (frames + 7) / 8; + uint32_t header_bytes = ecc_bytes + complen_bytes; + + /* extract compressed length of base */ + uint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1]; + if (complen_bytes > 2) + complen_base = (complen_base << 8) | src[ecc_bytes + 2]; + + /* reset and decode */ + zstd_codec_decompress(&cdzs->base_decompressor, &src[header_bytes], complen_base, &cdzs->buffer[0], frames * CD_MAX_SECTOR_DATA); +#ifdef WANT_SUBCODE + zstd_codec_decompress(&cdzs->subcode_decompressor, &src[header_bytes + complen_base], complen - complen_base - header_bytes, &cdzs->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA); +#endif + + /* reassemble the data */ + for (framenum = 0; framenum < frames; framenum++) + { + uint8_t *sector; + + memcpy(&dest[framenum * CD_FRAME_SIZE], &cdzs->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA); +#ifdef WANT_SUBCODE + memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdzs->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA); +#endif + +#ifdef WANT_RAW_DATA_SECTOR + /* reconstitute the ECC data and sync header */ + sector = (uint8_t *)&dest[framenum * CD_FRAME_SIZE]; + if ((src[framenum / 8] & (1 << (framenum % 8))) != 0) + { + memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header)); + ecc_generate(sector); + } +#endif + } + return CHDERR_NONE; +} + /*************************************************************************** CODEC INTERFACES ***************************************************************************/ @@ -899,6 +1223,49 @@ static const codec_interface codec_interfaces[] = NULL }, + /* V5 lzma compression */ + { + CHD_CODEC_LZMA, + "lzma (LZMA)", + FALSE, + lzma_codec_init, + lzma_codec_free, + lzma_codec_decompress, + NULL + }, + + /* V5 huffman compression */ + { + CHD_CODEC_HUFFMAN, + "Huffman", + FALSE, + huff_codec_init, + huff_codec_free, + huff_codec_decompress, + NULL + }, + + /* V5 flac compression */ + { + CHD_CODEC_FLAC, + "flac (FLAC)", + FALSE, + flac_codec_init, + flac_codec_free, + flac_codec_decompress, + NULL + }, + /* V5 zstd compression */ + { + CHD_CODEC_ZSTD, + "ZStandard", + FALSE, + zstd_codec_init, + zstd_codec_free, + zstd_codec_decompress, + NULL + }, + /* V5 CD zlib compression */ { CHD_CODEC_CD_ZLIB, @@ -931,6 +1298,17 @@ static const codec_interface codec_interfaces[] = cdfl_codec_decompress, NULL }, + /* V5 CD zstd compression */ + { + CHD_CODEC_CD_ZSTD, + "cdzs (CD ZStandard)", + FALSE, + cdzs_codec_init, + cdzs_codec_free, + cdzs_codec_decompress, + NULL + } + }; /*************************************************************************** @@ -1157,6 +1535,7 @@ static inline int chd_compressed(chd_header* header) { static chd_error decompress_v5_map(chd_file* chd, chd_header* header) { + int result = 0; uint32_t hunknum; int repcount = 0; uint8_t lastcomp = 0; @@ -1173,20 +1552,22 @@ static chd_error decompress_v5_map(chd_file* chd, chd_header* header) uint8_t rawbuf[16]; struct huffman_decoder* decoder; enum huffman_error err; - uint64_t curoffset; + uint64_t curoffset; int rawmapsize = map_size_v5(header); if (!chd_compressed(header)) { header->rawmap = (uint8_t*)malloc(rawmapsize); + if (header->rawmap == NULL) + return CHDERR_OUT_OF_MEMORY; core_fseek(chd->file, header->mapoffset, SEEK_SET); - core_fread(chd->file, header->rawmap, rawmapsize); + result = core_fread(chd->file, header->rawmap, rawmapsize); return CHDERR_NONE; } /* read the reader */ core_fseek(chd->file, header->mapoffset, SEEK_SET); - core_fread(chd->file, rawbuf, sizeof(rawbuf)); + result = core_fread(chd->file, rawbuf, sizeof(rawbuf)); mapbytes = get_bigendian_uint32(&rawbuf[0]); firstoffs = get_bigendian_uint48(&rawbuf[4]); mapcrc = get_bigendian_uint16(&rawbuf[10]); @@ -1196,10 +1577,18 @@ static chd_error decompress_v5_map(chd_file* chd, chd_header* header) /* now read the map */ compressed_ptr = (uint8_t*)malloc(sizeof(uint8_t) * mapbytes); + if (compressed_ptr == NULL) + return CHDERR_OUT_OF_MEMORY; core_fseek(chd->file, header->mapoffset + 16, SEEK_SET); - core_fread(chd->file, compressed_ptr, mapbytes); + result = core_fread(chd->file, compressed_ptr, mapbytes); bitbuf = create_bitstream(compressed_ptr, sizeof(uint8_t) * mapbytes); header->rawmap = (uint8_t*)malloc(rawmapsize); + if (header->rawmap == NULL) + { + free(compressed_ptr); + free(bitbuf); + return CHDERR_OUT_OF_MEMORY; + } /* first decode the compression types */ decoder = create_huffman_decoder(16, 8); @@ -1272,8 +1661,6 @@ static chd_error decompress_v5_map(chd_file* chd, chd_header* header) /* pseudo-types; convert into base types */ case COMPRESSION_SELF_1: last_self++; - // fall through - case COMPRESSION_SELF_0: rawmap[0] = COMPRESSION_SELF; offset = last_self; @@ -1286,8 +1673,6 @@ static chd_error decompress_v5_map(chd_file* chd, chd_header* header) case COMPRESSION_PARENT_1: last_parent += header->hunkbytes / header->unitbytes; - // fall through - case COMPRESSION_PARENT_0: rawmap[0] = COMPRESSION_PARENT; offset = last_parent; @@ -1341,11 +1726,28 @@ static inline void map_extract_old(const UINT8 *base, map_entry *entry, UINT32 h chd_open_file - open a CHD file for access -------------------------------------------------*/ -CHD_EXPORT chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file **chd) +CHD_EXPORT chd_error chd_open_file(FILE *file, int mode, chd_file *parent, chd_file **chd) { + core_file *stream = malloc(sizeof(core_file)); + if (!stream) + return CHDERR_OUT_OF_MEMORY; + stream->argp = file; + stream->fsize = core_stdio_fsize; + stream->fread = core_stdio_fread; + stream->fclose = core_stdio_fclose_nonowner; + stream->fseek = core_stdio_fseek; + + return chd_open_core_file(stream, mode, parent, chd); +} + +/*------------------------------------------------- + chd_open_core_file - open a CHD file for access +-------------------------------------------------*/ + +CHD_EXPORT chd_error chd_open_core_file(core_file *file, int mode, chd_file *parent, chd_file **chd) { chd_file *newchd = NULL; chd_error err; - uint32_t intfnum; + int intfnum; /* verify parameters */ if (file == NULL) @@ -1383,8 +1785,15 @@ CHD_EXPORT chd_error chd_open_file(core_file *file, int mode, chd_file *parent, EARLY_EXIT(err = CHDERR_UNSUPPORTED_VERSION); /* if we need a parent, make sure we have one */ - if (parent == NULL && (newchd->header.flags & CHDFLAGS_HAS_PARENT)) - EARLY_EXIT(err = CHDERR_REQUIRES_PARENT); + if (parent == NULL) + { + /* Detect parent requirement for versions below 5 */ + if (newchd->header.version < 5 && newchd->header.flags & CHDFLAGS_HAS_PARENT) + EARLY_EXIT(err = CHDERR_REQUIRES_PARENT); + /* Detection for version 5 and above - if parentsha1 != 0, we have a parent */ + else if (newchd->header.version >= 5 && memcmp(nullsha1, newchd->header.parentsha1, sizeof(newchd->header.parentsha1)) != 0) + EARLY_EXIT(err = CHDERR_REQUIRES_PARENT); + } /* make sure we have a valid parent */ if (parent != NULL) @@ -1456,11 +1865,11 @@ CHD_EXPORT chd_error chd_open_file(core_file *file, int mode, chd_file *parent, } else { - uint32_t decompnum; + int decompnum; /* verify the compression types and initialize the codecs */ for (decompnum = 0; decompnum < ARRAY_LENGTH(newchd->header.compression); decompnum++) { - uint32_t i; + int i; for (i = 0 ; i < ARRAY_LENGTH(codec_interfaces) ; i++) { if (codec_interfaces[i].compression == newchd->header.compression[decompnum]) @@ -1483,6 +1892,22 @@ CHD_EXPORT chd_error chd_open_file(core_file *file, int mode, chd_file *parent, codec = &newchd->zlib_codec_data; break; + case CHD_CODEC_LZMA: + codec = &newchd->lzma_codec_data; + break; + + case CHD_CODEC_HUFFMAN: + codec = &newchd->huff_codec_data; + break; + + case CHD_CODEC_FLAC: + codec = &newchd->flac_codec_data; + break; + + case CHD_CODEC_ZSTD: + codec = &newchd->zstd_codec_data; + break; + case CHD_CODEC_CD_ZLIB: codec = &newchd->cdzl_codec_data; break; @@ -1494,6 +1919,10 @@ CHD_EXPORT chd_error chd_open_file(core_file *file, int mode, chd_file *parent, case CHD_CODEC_CD_FLAC: codec = &newchd->cdfl_codec_data; break; + + case CHD_CODEC_CD_ZSTD: + codec = &newchd->cdzs_codec_data; + break; } if (codec == NULL) @@ -1523,17 +1952,13 @@ cleanup: CHD_EXPORT chd_error chd_precache(chd_file *chd) { -#ifdef _MSC_VER - size_t size, count; -#else - ssize_t size, count; -#endif + INT64 count; + UINT64 size; if (chd->file_cache == NULL) { - core_fseek(chd->file, 0, SEEK_END); - size = core_ftell(chd->file); - if (size <= 0) + size = core_fsize(chd->file); + if ((INT64)size <= 0) return CHDERR_INVALID_DATA; chd->file_cache = malloc(size); if (chd->file_cache == NULL) @@ -1561,6 +1986,12 @@ CHD_EXPORT chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_error err; core_file *file = NULL; + if (filename == NULL) + { + err = CHDERR_INVALID_PARAMETER; + goto cleanup; + } + /* choose the proper mode */ switch(mode) { @@ -1573,7 +2004,7 @@ CHD_EXPORT chd_error chd_open(const char *filename, int mode, chd_file *parent, } /* open the file */ - file = core_fopen(filename); + file = core_stdio_fopen(filename); if (file == 0) { err = CHDERR_FILE_NOT_FOUND; @@ -1581,12 +2012,7 @@ CHD_EXPORT chd_error chd_open(const char *filename, int mode, chd_file *parent, } /* now open the CHD */ - err = chd_open_file(file, mode, parent, chd); - if (err != CHDERR_NONE) - goto cleanup; - - /* we now own this file */ - (*chd)->owns_file = TRUE; + return chd_open_core_file(file, mode, parent, chd); cleanup: if ((err != CHDERR_NONE) && (file != NULL)) @@ -1612,7 +2038,7 @@ CHD_EXPORT void chd_close(chd_file *chd) } else { - uint32_t i; + int i; /* Free the codecs */ for (i = 0 ; i < ARRAY_LENGTH(chd->codecintf); i++) { @@ -1623,21 +2049,41 @@ CHD_EXPORT void chd_close(chd_file *chd) switch (chd->codecintf[i]->compression) { - case CHD_CODEC_CD_LZMA: - codec = &chd->cdlz_codec_data; - break; - case CHD_CODEC_ZLIB: codec = &chd->zlib_codec_data; break; + case CHD_CODEC_LZMA: + codec = &chd->lzma_codec_data; + break; + + case CHD_CODEC_HUFFMAN: + codec = &chd->huff_codec_data; + break; + + case CHD_CODEC_FLAC: + codec = &chd->flac_codec_data; + break; + + case CHD_CODEC_ZSTD: + codec = &chd->zstd_codec_data; + break; + case CHD_CODEC_CD_ZLIB: codec = &chd->cdzl_codec_data; break; + case CHD_CODEC_CD_LZMA: + codec = &chd->cdlz_codec_data; + break; + case CHD_CODEC_CD_FLAC: codec = &chd->cdfl_codec_data; break; + + case CHD_CODEC_CD_ZSTD: + codec = &chd->cdzs_codec_data; + break; } if (codec) @@ -1668,7 +2114,7 @@ CHD_EXPORT void chd_close(chd_file *chd) free(chd->map); /* close the file */ - if (chd->owns_file && chd->file != NULL) + if (chd->file != NULL) core_fclose(chd->file); #ifdef NEED_CACHE_HUNK @@ -1677,6 +2123,9 @@ CHD_EXPORT void chd_close(chd_file *chd) if (chd->file_cache) free(chd->file_cache); + if (chd->parent) + chd_close(chd->parent); + /* free our memory */ free(chd); } @@ -1750,6 +2199,41 @@ CHD_EXPORT const chd_header *chd_get_header(chd_file *chd) return &chd->header; } +/*------------------------------------------------- + chd_read_header - read CHD header data + from file into the pointed struct +-------------------------------------------------*/ +CHD_EXPORT chd_error chd_read_header(const char *filename, chd_header *header) +{ + chd_error err = CHDERR_NONE; + chd_file chd; + + /* punt if NULL */ + if (filename == NULL || header == NULL) + EARLY_EXIT(err = CHDERR_INVALID_PARAMETER); + + /* open the file */ + chd.file = core_stdio_fopen(filename); + if (chd.file == NULL) + EARLY_EXIT(err = CHDERR_FILE_NOT_FOUND); + + /* attempt to read the header */ + err = header_read(&chd, header); + if (err != CHDERR_NONE) + EARLY_EXIT(err); + + /* validate the header */ + err = header_validate(header); + if (err != CHDERR_NONE) + EARLY_EXIT(err); + +cleanup: + if (chd.file != NULL) + core_fclose(chd.file); + + return err; +} + /*************************************************************************** CORE DATA READ/WRITE ***************************************************************************/ @@ -1843,10 +2327,6 @@ CHD_EXPORT chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 se CHD_EXPORT chd_error chd_codec_config(chd_file *chd, int param, void *config) { - (void)chd; - (void)param; - (void)config; - return CHDERR_INVALID_PARAMETER; } @@ -1857,8 +2337,6 @@ CHD_EXPORT chd_error chd_codec_config(chd_file *chd, int param, void *config) CHD_EXPORT const char *chd_get_codec_name(UINT32 codec) { - (void)codec; - return "Unknown"; } @@ -1873,7 +2351,7 @@ CHD_EXPORT const char *chd_get_codec_name(UINT32 codec) static chd_error header_validate(const chd_header *header) { - uint32_t intfnum; + int intfnum; /* require a valid version */ if (header->version == 0 || header->version > CHD_HEADER_VERSION) @@ -2023,6 +2501,8 @@ static chd_error header_read(chd_file *chd, chd_header *header) header->logicalbytes = (UINT64)header->obsolete_cylinders * (UINT64)header->obsolete_heads * (UINT64)header->obsolete_sectors * (UINT64)seclen; header->hunkbytes = seclen * header->obsolete_hunksize; header->unitbytes = header_guess_unitbytes(chd); + if (header->unitbytes == 0) + return CHDERR_INVALID_DATA; header->unitcount = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes; header->metaoffset = 0; } @@ -2037,6 +2517,8 @@ static chd_error header_read(chd_file *chd, chd_header *header) memcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES); header->hunkbytes = get_bigendian_uint32(&rawheader[76]); header->unitbytes = header_guess_unitbytes(chd); + if (header->unitbytes == 0) + return CHDERR_INVALID_DATA; header->unitcount = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes; memcpy(header->sha1, &rawheader[80], CHD_SHA1_BYTES); memcpy(header->parentsha1, &rawheader[100], CHD_SHA1_BYTES); @@ -2050,6 +2532,8 @@ static chd_error header_read(chd_file *chd, chd_header *header) header->metaoffset = get_bigendian_uint64(&rawheader[36]); header->hunkbytes = get_bigendian_uint32(&rawheader[44]); header->unitbytes = header_guess_unitbytes(chd); + if (header->unitbytes == 0) + return CHDERR_INVALID_DATA; header->unitcount = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes; memcpy(header->sha1, &rawheader[48], CHD_SHA1_BYTES); memcpy(header->parentsha1, &rawheader[68], CHD_SHA1_BYTES); @@ -2068,8 +2552,12 @@ static chd_error header_read(chd_file *chd, chd_header *header) header->mapoffset = get_bigendian_uint64(&rawheader[40]); header->metaoffset = get_bigendian_uint64(&rawheader[48]); header->hunkbytes = get_bigendian_uint32(&rawheader[56]); + if (header->hunkbytes == 0) + return CHDERR_INVALID_DATA; header->hunkcount = (header->logicalbytes + header->hunkbytes - 1) / header->hunkbytes; header->unitbytes = get_bigendian_uint32(&rawheader[60]); + if (header->unitbytes == 0) + return CHDERR_INVALID_DATA; header->unitcount = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes; memcpy(header->sha1, &rawheader[84], CHD_SHA1_BYTES); memcpy(header->parentsha1, &rawheader[104], CHD_SHA1_BYTES); @@ -2103,8 +2591,11 @@ static chd_error header_read(chd_file *chd, chd_header *header) static UINT8* hunk_read_compressed(chd_file *chd, UINT64 offset, size_t size) { +#ifdef _MSC_VER size_t bytes; - +#else + ssize_t bytes; +#endif if (chd->file_cache != NULL) { return chd->file_cache + offset; @@ -2126,8 +2617,11 @@ static UINT8* hunk_read_compressed(chd_file *chd, UINT64 offset, size_t size) static chd_error hunk_read_uncompressed(chd_file *chd, UINT64 offset, size_t size, UINT8 *dest) { +#ifdef _MSC_VER size_t bytes; - +#else + ssize_t bytes; +#endif if (chd->file_cache != NULL) { memcpy(dest, chd->file_cache + offset, size); @@ -2142,6 +2636,36 @@ static chd_error hunk_read_uncompressed(chd_file *chd, UINT64 offset, size_t siz return CHDERR_NONE; } +#ifdef NEED_CACHE_HUNK +/*------------------------------------------------- + hunk_read_into_cache - read a hunk into + the CHD's hunk cache +-------------------------------------------------*/ + +static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum) +{ + chd_error err; + + /* track the max */ + if (hunknum > chd->maxhunk) + chd->maxhunk = hunknum; + + /* if we're already in the cache, we're done */ + if (chd->cachehunk == hunknum) + return CHDERR_NONE; + chd->cachehunk = ~0; + + /* otherwise, read the data */ + err = hunk_read_into_memory(chd, hunknum, chd->cache); + if (err != CHDERR_NONE) + return err; + + /* mark the hunk successfully cached in */ + chd->cachehunk = hunknum; + return CHDERR_NONE; +} +#endif + /*------------------------------------------------- hunk_read_into_memory - read a hunk into memory at the given location @@ -2179,7 +2703,9 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des /* read it into the decompression buffer */ compressed_bytes = hunk_read_compressed(chd, entry->offset, entry->length); if (compressed_bytes == NULL) + { return CHDERR_READ_ERROR; + } /* now decompress using the codec */ err = CHDERR_NONE; @@ -2240,7 +2766,7 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des blockoffs = (uint64_t)get_bigendian_uint32(rawmap) * (uint64_t)chd->header.hunkbytes; if (blockoffs != 0) { core_fseek(chd->file, blockoffs, SEEK_SET); - core_fread(chd->file, dest, chd->header.hunkbytes); + int result = core_fread(chd->file, dest, chd->header.hunkbytes); /* TODO else if (m_parent_missing) throw CHDERR_REQUIRES_PARENT; */ @@ -2273,21 +2799,41 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des return CHDERR_READ_ERROR; switch (chd->codecintf[rawmap[0]]->compression) { - case CHD_CODEC_CD_LZMA: - codec = &chd->cdlz_codec_data; - break; - case CHD_CODEC_ZLIB: codec = &chd->zlib_codec_data; break; + case CHD_CODEC_LZMA: + codec = &chd->lzma_codec_data; + break; + + case CHD_CODEC_HUFFMAN: + codec = &chd->huff_codec_data; + break; + + case CHD_CODEC_FLAC: + codec = &chd->flac_codec_data; + break; + + case CHD_CODEC_ZSTD: + codec = &chd->zstd_codec_data; + break; + case CHD_CODEC_CD_ZLIB: codec = &chd->cdzl_codec_data; break; + case CHD_CODEC_CD_LZMA: + codec = &chd->cdlz_codec_data; + break; + case CHD_CODEC_CD_FLAC: codec = &chd->cdfl_codec_data; break; + + case CHD_CODEC_CD_ZSTD: + codec = &chd->cdzs_codec_data; + break; } if (codec==NULL) return CHDERR_CODEC_ERROR; @@ -2314,13 +2860,33 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des return hunk_read_into_memory(chd, blockoffs, dest); case COMPRESSION_PARENT: -#if 0 - /* TODO */ - if (m_parent_missing) + if (chd->parent == NULL) return CHDERR_REQUIRES_PARENT; - return m_parent->read_bytes(uint64_t(blockoffs) * uint64_t(m_parent->unit_bytes()), dest, m_hunkbytes); -#endif - return CHDERR_DECOMPRESSION_ERROR; + UINT8 units_in_hunk = chd->header.hunkbytes / chd->header.unitbytes; + + /* blockoffs is aligned to units_in_hunk */ + if (blockoffs % units_in_hunk == 0) { + return hunk_read_into_memory(chd->parent, blockoffs / units_in_hunk, dest); + /* blockoffs is not aligned to units_in_hunk */ + } else { + UINT32 unit_in_hunk = blockoffs % units_in_hunk; + UINT8 *buf = malloc(chd->header.hunkbytes); + /* Read first half of hunk which contains blockoffs */ + err = hunk_read_into_memory(chd->parent, blockoffs / units_in_hunk, buf); + if (err != CHDERR_NONE) { + free(buf); + return err; + } + memcpy(dest, buf + unit_in_hunk * chd->header.unitbytes, (units_in_hunk - unit_in_hunk) * chd->header.unitbytes); + /* Read second half of hunk which contains blockoffs */ + err = hunk_read_into_memory(chd->parent, (blockoffs / units_in_hunk) + 1, buf); + if (err != CHDERR_NONE) { + free(buf); + return err; + } + memcpy(dest + (units_in_hunk - unit_in_hunk) * chd->header.unitbytes, buf, unit_in_hunk * chd->header.unitbytes); + free(buf); + } } return CHDERR_NONE; } @@ -2345,7 +2911,7 @@ static chd_error map_read(chd_file *chd) UINT8 cookie[MAP_ENTRY_SIZE]; UINT32 count; chd_error err; - uint32_t i; + UINT32 i; /* first allocate memory */ chd->map = (map_entry *)malloc(sizeof(chd->map[0]) * chd->header.totalhunks); @@ -2473,7 +3039,6 @@ static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metai static chd_error zlib_codec_init(void *codec, uint32_t hunkbytes) { - (void)hunkbytes; int zerr; chd_error err; zlib_codec_data *data = (zlib_codec_data*)codec; @@ -2497,10 +3062,6 @@ static chd_error zlib_codec_init(void *codec, uint32_t hunkbytes) else err = CHDERR_NONE; - /* handle an error */ - if (err != CHDERR_NONE) - free(data); - return err; } @@ -2640,3 +3201,87 @@ static void zlib_allocator_free(voidpf opaque) if (alloc->allocptr[i]) free(alloc->allocptr[i]); } + +/*------------------------------------------------- + core_stdio_fopen - core_file wrapper over fopen +-------------------------------------------------*/ +static core_file *core_stdio_fopen(char const *path) { + core_file *file = malloc(sizeof(core_file)); + if (!file) + return NULL; + if (!(file->argp = fopen(path, "rb"))) { + free(file); + return NULL; + } + file->fsize = core_stdio_fsize; + file->fread = core_stdio_fread; + file->fclose = core_stdio_fclose; + file->fseek = core_stdio_fseek; + return file; +} + +/*------------------------------------------------- + core_stdio_fsize - core_file function for + getting file size with stdio +-------------------------------------------------*/ +static UINT64 core_stdio_fsize(core_file *file) { +#if defined USE_LIBRETRO_VFS + #define core_stdio_fseek_impl fseek + #define core_stdio_ftell_impl ftell +#elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__WIN64__) + #define core_stdio_fseek_impl _fseeki64 + #define core_stdio_ftell_impl _ftelli64 +#elif defined(_LARGEFILE_SOURCE) && defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 + #define core_stdio_fseek_impl fseeko64 + #define core_stdio_ftell_impl ftello64 +#elif defined(__PS3__) && !defined(__PSL1GHT__) || defined(__SWITCH__) || defined(__vita__) + #define core_stdio_fseek_impl(x,y,z) fseek(x,(off_t)y,z) + #define core_stdio_ftell_impl(x) (off_t)ftell(x) +#else + #define core_stdio_fseek_impl fseeko + #define core_stdio_ftell_impl ftello +#endif + FILE *fp; + UINT64 p, rv; + fp = (FILE*)file->argp; + + p = core_stdio_ftell_impl(fp); + core_stdio_fseek_impl(fp, 0, SEEK_END); + rv = core_stdio_ftell_impl(fp); + core_stdio_fseek_impl(fp, p, SEEK_SET); + return rv; +} + +/*------------------------------------------------- + core_stdio_fread - core_file wrapper over fread +-------------------------------------------------*/ +static size_t core_stdio_fread(void *ptr, size_t size, size_t nmemb, core_file *file) { + return fread(ptr, size, nmemb, (FILE*)file->argp); +} + +/*------------------------------------------------- + core_stdio_fclose - core_file wrapper over fclose +-------------------------------------------------*/ +static int core_stdio_fclose(core_file *file) { + int err = fclose((FILE*)file->argp); + if (err == 0) + free(file); + return err; +} + +/*------------------------------------------------- + core_stdio_fclose_nonowner - don't call fclose because + we don't own the underlying file, but do free the + core_file because libchdr did allocate that itself. +-------------------------------------------------*/ +static int core_stdio_fclose_nonowner(core_file *file) { + free(file); + return 0; +} + +/*------------------------------------------------- + core_stdio_fseek - core_file wrapper over fclose +-------------------------------------------------*/ +static int core_stdio_fseek(core_file* file, INT64 offset, int whence) { + return core_stdio_fseek_impl((FILE*)file->argp, offset, whence); +} diff --git a/lib/libchdr/libchdr_flac.c b/lib/libchdr/libchdr_flac.c index baf1b94..dce22c7 100644 --- a/lib/libchdr/libchdr_flac.c +++ b/lib/libchdr/libchdr_flac.c @@ -8,40 +8,37 @@ ***************************************************************************/ -#include #include #include +#define DR_FLAC_IMPLEMENTATION +#define DR_FLAC_NO_STDIO +#include /*************************************************************************** * FLAC DECODER *************************************************************************** */ -static FLAC__StreamDecoderReadStatus flac_decoder_read_callback_static(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data); -FLAC__StreamDecoderReadStatus flac_decoder_read_callback(void* client_data, FLAC__byte buffer[], size_t *bytes); -static void flac_decoder_metadata_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); -static FLAC__StreamDecoderTellStatus flac_decoder_tell_callback_static(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data); -static FLAC__StreamDecoderWriteStatus flac_decoder_write_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); -FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(void* client_data, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]); -static void flac_decoder_error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); +static size_t flac_decoder_read_callback(void *userdata, void *buffer, size_t bytes); +static drflac_bool32 flac_decoder_seek_callback(void *userdata, int offset, drflac_seek_origin origin); +static void flac_decoder_metadata_callback(void *userdata, drflac_metadata *metadata); +static void flac_decoder_write_callback(void *userdata, void *buffer, size_t bytes); + /* getters (valid after reset) */ -//static uint32_t sample_rate(flac_decoder *decoder) { return decoder->sample_rate; } +static uint32_t sample_rate(flac_decoder *decoder) { return decoder->sample_rate; } static uint8_t channels(flac_decoder *decoder) { return decoder->channels; } -//static uint8_t bits_per_sample(flac_decoder *decoder) { return decoder->bits_per_sample; } -//static uint32_t total_samples(flac_decoder *decoder) { return FLAC__stream_decoder_get_total_samples(decoder->decoder); } -//static FLAC__StreamDecoderState state(flac_decoder *decoder) { return FLAC__stream_decoder_get_state(decoder->decoder); } -//static const char *state_string(flac_decoder *decoder) { return FLAC__stream_decoder_get_resolved_state_string(decoder->decoder); } +static uint8_t bits_per_sample(flac_decoder *decoder) { return decoder->bits_per_sample; } /*------------------------------------------------- * flac_decoder - constructor *------------------------------------------------- */ -void flac_decoder_init(flac_decoder *decoder) +int flac_decoder_init(flac_decoder *decoder) { - decoder->decoder = FLAC__stream_decoder_new(); + decoder->decoder = NULL; decoder->sample_rate = 0; decoder->channels = 0; decoder->bits_per_sample = 0; @@ -53,6 +50,7 @@ void flac_decoder_init(flac_decoder *decoder) decoder->uncompressed_offset = 0; decoder->uncompressed_length = 0; decoder->uncompressed_swap = 0; + return 0; } /*------------------------------------------------- @@ -62,8 +60,10 @@ void flac_decoder_init(flac_decoder *decoder) void flac_decoder_free(flac_decoder* decoder) { - if ((decoder != NULL) && (decoder->decoder != NULL)) - FLAC__stream_decoder_delete(decoder->decoder); + if ((decoder != NULL) && (decoder->decoder != NULL)) { + drflac_close(decoder->decoder); + decoder->decoder = NULL; + } } /*------------------------------------------------- @@ -75,17 +75,11 @@ void flac_decoder_free(flac_decoder* decoder) static int flac_decoder_internal_reset(flac_decoder* decoder) { decoder->compressed_offset = 0; - if (FLAC__stream_decoder_init_stream(decoder->decoder, - &flac_decoder_read_callback_static, - NULL, - &flac_decoder_tell_callback_static, - NULL, - NULL, - &flac_decoder_write_callback_static, - &flac_decoder_metadata_callback_static, - &flac_decoder_error_callback_static, decoder) != FLAC__STREAM_DECODER_INIT_STATUS_OK) - return 0; - return FLAC__stream_decoder_process_until_end_of_metadata(decoder->decoder); + flac_decoder_free(decoder); + decoder->decoder = drflac_open_with_metadata( + flac_decoder_read_callback, flac_decoder_seek_callback, + flac_decoder_metadata_callback, decoder, NULL); + return (decoder->decoder != NULL); } /*------------------------------------------------- @@ -114,16 +108,16 @@ int flac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* +2A: start of stream data */ }; memcpy(decoder->custom_header, s_header_template, sizeof(s_header_template)); - decoder->custom_header[0x08] = decoder->custom_header[0x0a] = block_size >> 8; - decoder->custom_header[0x09] = decoder->custom_header[0x0b] = block_size & 0xff; + decoder->custom_header[0x08] = decoder->custom_header[0x0a] = (block_size*num_channels) >> 8; + decoder->custom_header[0x09] = decoder->custom_header[0x0b] = (block_size*num_channels) & 0xff; decoder->custom_header[0x12] = sample_rate >> 12; decoder->custom_header[0x13] = sample_rate >> 4; decoder->custom_header[0x14] = (sample_rate << 4) | ((num_channels - 1) << 1); /* configure the header ahead of the provided buffer */ - decoder->compressed_start = (const FLAC__byte *)(decoder->custom_header); + decoder->compressed_start = (const uint8_t *)(decoder->custom_header); decoder->compressed_length = sizeof(decoder->custom_header); - decoder->compressed2_start = (const FLAC__byte *)(buffer); + decoder->compressed2_start = (const uint8_t *)(buffer); decoder->compressed2_length = length; return flac_decoder_internal_reset(decoder); } @@ -143,43 +137,20 @@ int flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uin decoder->uncompressed_length = num_samples; decoder->uncompressed_swap = swap_endian; +#define BUFFER 2352 /* bytes per CD audio sector */ + int16_t buffer[BUFFER]; + uint32_t buf_samples = BUFFER / channels(decoder); /* loop until we get everything we want */ - while (decoder->uncompressed_offset < decoder->uncompressed_length) - if (!FLAC__stream_decoder_process_single(decoder->decoder)) + while (decoder->uncompressed_offset < decoder->uncompressed_length) { + uint32_t frames = (num_samples < buf_samples ? num_samples : buf_samples); + if (!drflac_read_pcm_frames_s16(decoder->decoder, frames, buffer)) return 0; + flac_decoder_write_callback(decoder, buffer, frames*sizeof(*buffer)*channels(decoder)); + num_samples -= frames; + } return 1; } -#if 0 -/*------------------------------------------------- - * decode - decode to an multiple independent - * data streams - *------------------------------------------------- - */ - -bool flac_decoder::decode(int16_t **samples, uint32_t num_samples, bool swap_endian) -{ - /* make sure we don't have too many channels */ - int chans = channels(); - if (chans > ARRAY_LENGTH(m_uncompressed_start)) - return false; - - /* configure the uncompressed buffer */ - memset(m_uncompressed_start, 0, sizeof(m_uncompressed_start)); - for (int curchan = 0; curchan < chans; curchan++) - m_uncompressed_start[curchan] = samples[curchan]; - m_uncompressed_offset = 0; - m_uncompressed_length = num_samples; - m_uncompressed_swap = swap_endian; - - /* loop until we get everything we want */ - while (m_uncompressed_offset < m_uncompressed_length) - if (!FLAC__stream_decoder_process_single(m_decoder)) - return false; - return true; -} -#endif - /*------------------------------------------------- * finish - finish up the decode *------------------------------------------------- @@ -188,15 +159,21 @@ bool flac_decoder::decode(int16_t **samples, uint32_t num_samples, bool swap_end uint32_t flac_decoder_finish(flac_decoder* decoder) { /* get the final decoding position and move forward */ - FLAC__uint64 position = 0; - FLAC__stream_decoder_get_decode_position(decoder->decoder, &position); - FLAC__stream_decoder_finish(decoder->decoder); + drflac *flac = decoder->decoder; + uint64_t position = decoder->compressed_offset; + + /* ugh... there's no function to obtain bytes used in drflac :-/ */ + position -= DRFLAC_CACHE_L2_LINES_REMAINING(&flac->bs) * sizeof(drflac_cache_t); + position -= DRFLAC_CACHE_L1_BITS_REMAINING(&flac->bs) / 8; + position -= flac->bs.unalignedByteCount; /* adjust position if we provided the header */ if (position == 0) return 0; - if (decoder->compressed_start == (const FLAC__byte *)(decoder->custom_header)) + if (decoder->compressed_start == (const uint8_t *)(decoder->custom_header)) position -= decoder->compressed_length; + + flac_decoder_free(decoder); return position; } @@ -208,40 +185,31 @@ uint32_t flac_decoder_finish(flac_decoder* decoder) #define MIN(x, y) ((x) < (y) ? (x) : (y)) -FLAC__StreamDecoderReadStatus flac_decoder_read_callback_static(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) +static size_t flac_decoder_read_callback(void *userdata, void *buffer, size_t bytes) { - (void)decoder; - return flac_decoder_read_callback(client_data, buffer, bytes); -} - -FLAC__StreamDecoderReadStatus flac_decoder_read_callback(void* client_data, FLAC__byte buffer[], size_t *bytes) -{ - flac_decoder* decoder = (flac_decoder*)client_data; - - uint32_t expected = *bytes; + flac_decoder* decoder = (flac_decoder*)userdata; + uint8_t *dst = buffer; /* copy from primary buffer first */ uint32_t outputpos = 0; - if (outputpos < *bytes && decoder->compressed_offset < decoder->compressed_length) + if (outputpos < bytes && decoder->compressed_offset < decoder->compressed_length) { - uint32_t bytes_to_copy = MIN(*bytes - outputpos, decoder->compressed_length - decoder->compressed_offset); - memcpy(&buffer[outputpos], decoder->compressed_start + decoder->compressed_offset, bytes_to_copy); + uint32_t bytes_to_copy = MIN(bytes - outputpos, decoder->compressed_length - decoder->compressed_offset); + memcpy(&dst[outputpos], decoder->compressed_start + decoder->compressed_offset, bytes_to_copy); outputpos += bytes_to_copy; decoder->compressed_offset += bytes_to_copy; } /* once we're out of that, copy from the secondary buffer */ - if (outputpos < *bytes && decoder->compressed_offset < decoder->compressed_length + decoder->compressed2_length) + if (outputpos < bytes && decoder->compressed_offset < decoder->compressed_length + decoder->compressed2_length) { - uint32_t bytes_to_copy = MIN(*bytes - outputpos, decoder->compressed2_length - (decoder->compressed_offset - decoder->compressed_length)); - memcpy(&buffer[outputpos], decoder->compressed2_start + decoder->compressed_offset - decoder->compressed_length, bytes_to_copy); + uint32_t bytes_to_copy = MIN(bytes - outputpos, decoder->compressed2_length - (decoder->compressed_offset - decoder->compressed_length)); + memcpy(&dst[outputpos], decoder->compressed2_start + decoder->compressed_offset - decoder->compressed_length, bytes_to_copy); outputpos += bytes_to_copy; decoder->compressed_offset += bytes_to_copy; } - *bytes = outputpos; - /* return based on whether we ran out of data */ - return (*bytes < expected) ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM : FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + return outputpos; } /*------------------------------------------------- @@ -249,34 +217,18 @@ FLAC__StreamDecoderReadStatus flac_decoder_read_callback(void* client_data, FLAC *------------------------------------------------- */ -void flac_decoder_metadata_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) +static void flac_decoder_metadata_callback(void *userdata, drflac_metadata *metadata) { - (void)decoder; + flac_decoder *decoder = userdata; - flac_decoder *fldecoder; /* ignore all but STREAMINFO metadata */ - if (metadata->type != FLAC__METADATA_TYPE_STREAMINFO) + if (metadata->type != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO) return; /* parse out the data we care about */ - fldecoder = (flac_decoder *)(client_data); - fldecoder->sample_rate = metadata->data.stream_info.sample_rate; - fldecoder->bits_per_sample = metadata->data.stream_info.bits_per_sample; - fldecoder->channels = metadata->data.stream_info.channels; -} - -/*------------------------------------------------- - * tell_callback - handle requests to find out - * where in the input stream we are - *------------------------------------------------- - */ - -FLAC__StreamDecoderTellStatus flac_decoder_tell_callback_static(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) -{ - (void)decoder; - - *absolute_byte_offset = ((flac_decoder *)client_data)->compressed_offset; - return FLAC__STREAM_DECODER_TELL_STATUS_OK; + decoder->sample_rate = metadata->data.streaminfo.sampleRate; + decoder->bits_per_sample = metadata->data.streaminfo.bitsPerSample; + decoder->channels = metadata->data.streaminfo.channels; } /*------------------------------------------------- @@ -285,59 +237,67 @@ FLAC__StreamDecoderTellStatus flac_decoder_tell_callback_static(const FLAC__Stre *------------------------------------------------- */ -FLAC__StreamDecoderWriteStatus flac_decoder_write_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) +static void flac_decoder_write_callback(void *userdata, void *buffer, size_t bytes) { - (void)decoder; - - return flac_decoder_write_callback(client_data, frame, buffer); -} - -FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(void *client_data, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]) -{ - int sampnum; - uint32_t chan; + int sampnum, chan; int shift, blocksize; - flac_decoder * decoder = (flac_decoder *)client_data; - - assert(frame->header.channels == channels(decoder)); + flac_decoder * decoder = (flac_decoder *)userdata; + int16_t *sampbuf = (int16_t *)buffer; + int sampch = channels(decoder); + uint32_t offset = decoder->uncompressed_offset; + uint16_t usample; /* interleaved case */ shift = decoder->uncompressed_swap ? 8 : 0; - blocksize = frame->header.blocksize; + blocksize = bytes / (sampch * sizeof(sampbuf[0])); if (decoder->uncompressed_start[1] == NULL) { - int16_t *dest = decoder->uncompressed_start[0] + decoder->uncompressed_offset * frame->header.channels; - for (sampnum = 0; sampnum < blocksize && decoder->uncompressed_offset < decoder->uncompressed_length; sampnum++, decoder->uncompressed_offset++) - for (chan = 0; chan < frame->header.channels; chan++) - *dest++ = (int16_t)((((uint16_t)buffer[chan][sampnum]) << shift) | (((uint16_t)buffer[chan][sampnum]) >> shift)); + int16_t *dest = decoder->uncompressed_start[0] + offset * sampch; + for (sampnum = 0; sampnum < blocksize && offset < decoder->uncompressed_length; sampnum++, offset++) + for (chan = 0; chan < sampch; chan++) { + usample = (uint16_t)*sampbuf++; + *dest++ = (int16_t)((usample << shift) | (usample >> shift)); + } } /* non-interleaved case */ else { - for (sampnum = 0; sampnum < blocksize && decoder->uncompressed_offset < decoder->uncompressed_length; sampnum++, decoder->uncompressed_offset++) - for (chan = 0; chan < frame->header.channels; chan++) + for (sampnum = 0; sampnum < blocksize && offset < decoder->uncompressed_length; sampnum++, offset++) + for (chan = 0; chan < sampch; chan++) { + usample = (uint16_t)*sampbuf++; if (decoder->uncompressed_start[chan] != NULL) - decoder->uncompressed_start[chan][decoder->uncompressed_offset] = (int16_t) ( (((uint16_t)(buffer[chan][sampnum])) << shift) | ( ((uint16_t)(buffer[chan][sampnum])) >> shift) ); + decoder->uncompressed_start[chan][offset] = (int16_t) ((usample << shift) | (usample >> shift)); + } } - return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; + decoder->uncompressed_offset = offset; } -/** - * @fn void flac_decoder::error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) - * - * @brief ------------------------------------------------- - * error_callback - handle errors (ignore them) - * -------------------------------------------------. - * - * @param decoder The decoder. - * @param status The status. - * @param [in,out] client_data If non-null, information describing the client. + +/*------------------------------------------------- + * seek_callback - handle seeks on the output + * stream + *------------------------------------------------- */ -void flac_decoder_error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) +static drflac_bool32 flac_decoder_seek_callback(void *userdata, int offset, drflac_seek_origin origin) { - (void)decoder; - (void)status; - (void)client_data; + flac_decoder * decoder = (flac_decoder *)userdata; + uint32_t length = decoder->compressed_length + decoder->compressed2_length; + + if (origin == drflac_seek_origin_start) { + uint32_t pos = offset; + if (pos <= length) { + decoder->compressed_offset = pos; + return 1; + } + } else if (origin == drflac_seek_origin_current) { + uint32_t pos = decoder->compressed_offset + offset; + if (pos <= length) { + decoder->compressed_offset = pos; + return 1; + } + } + return 0; } + diff --git a/lib/libchdr/libchdr_huffman.c b/lib/libchdr/libchdr_huffman.c index 48dcb00..556aa34 100644 --- a/lib/libchdr/libchdr_huffman.c +++ b/lib/libchdr/libchdr_huffman.c @@ -97,7 +97,6 @@ ***************************************************************************/ #include -#include #include #include @@ -213,6 +212,8 @@ enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, stru else { int repcount = bitstream_read(bitbuf, numbits) + 3; + if (repcount + curnode > decoder->numcodes) + return HUFFERR_INVALID_DATA; while (repcount--) decoder->huffnode[curnode++].numbits = nodebits; } @@ -294,6 +295,9 @@ enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder, } } + /* make sure we free the local huffman decoder */ + delete_huffman_decoder(smallhuff); + /* make sure we ended up with the right number */ if (curcode != decoder->numcodes) return HUFFERR_INVALID_DATA; diff --git a/lib/zstd/lib/common/allocations.h b/lib/zstd/lib/common/allocations.h new file mode 100644 index 0000000..a3153c4 --- /dev/null +++ b/lib/zstd/lib/common/allocations.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +/* This file provides custom allocation primitives + */ + +#define ZSTD_DEPS_NEED_MALLOC +#include "zstd_deps.h" /* ZSTD_malloc, ZSTD_calloc, ZSTD_free, ZSTD_memset */ + +#include "mem.h" /* MEM_STATIC */ +#define ZSTD_STATIC_LINKING_ONLY +#include "../zstd.h" /* ZSTD_customMem */ + +#ifndef ZSTD_ALLOCATIONS_H +#define ZSTD_ALLOCATIONS_H + +/* custom memory allocation functions */ + +MEM_STATIC void* ZSTD_customMalloc(size_t size, ZSTD_customMem customMem) +{ + if (customMem.customAlloc) + return customMem.customAlloc(customMem.opaque, size); + return ZSTD_malloc(size); +} + +MEM_STATIC void* ZSTD_customCalloc(size_t size, ZSTD_customMem customMem) +{ + if (customMem.customAlloc) { + /* calloc implemented as malloc+memset; + * not as efficient as calloc, but next best guess for custom malloc */ + void* const ptr = customMem.customAlloc(customMem.opaque, size); + ZSTD_memset(ptr, 0, size); + return ptr; + } + return ZSTD_calloc(1, size); +} + +MEM_STATIC void ZSTD_customFree(void* ptr, ZSTD_customMem customMem) +{ + if (ptr!=NULL) { + if (customMem.customFree) + customMem.customFree(customMem.opaque, ptr); + else + ZSTD_free(ptr); + } +} + +#endif /* ZSTD_ALLOCATIONS_H */ diff --git a/lib/zstd/lib/common/bits.h b/lib/zstd/lib/common/bits.h new file mode 100644 index 0000000..def56c4 --- /dev/null +++ b/lib/zstd/lib/common/bits.h @@ -0,0 +1,200 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef ZSTD_BITS_H +#define ZSTD_BITS_H + +#include "mem.h" + +MEM_STATIC unsigned ZSTD_countTrailingZeros32_fallback(U32 val) +{ + assert(val != 0); + { + static const U32 DeBruijnBytePos[32] = {0, 1, 28, 2, 29, 14, 24, 3, + 30, 22, 20, 15, 25, 17, 4, 8, + 31, 27, 13, 23, 21, 19, 16, 7, + 26, 12, 18, 6, 11, 5, 10, 9}; + return DeBruijnBytePos[((U32) ((val & -(S32) val) * 0x077CB531U)) >> 27]; + } +} + +MEM_STATIC unsigned ZSTD_countTrailingZeros32(U32 val) +{ + assert(val != 0); +# if defined(_MSC_VER) +# if STATIC_BMI2 == 1 + return (unsigned)_tzcnt_u32(val); +# else + if (val != 0) { + unsigned long r; + _BitScanForward(&r, val); + return (unsigned)r; + } else { + /* Should not reach this code path */ + __assume(0); + } +# endif +# elif defined(__GNUC__) && (__GNUC__ >= 4) + return (unsigned)__builtin_ctz(val); +# else + return ZSTD_countTrailingZeros32_fallback(val); +# endif +} + +MEM_STATIC unsigned ZSTD_countLeadingZeros32_fallback(U32 val) { + assert(val != 0); + { + static const U32 DeBruijnClz[32] = {0, 9, 1, 10, 13, 21, 2, 29, + 11, 14, 16, 18, 22, 25, 3, 30, + 8, 12, 20, 28, 15, 17, 24, 7, + 19, 27, 23, 6, 26, 5, 4, 31}; + val |= val >> 1; + val |= val >> 2; + val |= val >> 4; + val |= val >> 8; + val |= val >> 16; + return 31 - DeBruijnClz[(val * 0x07C4ACDDU) >> 27]; + } +} + +MEM_STATIC unsigned ZSTD_countLeadingZeros32(U32 val) +{ + assert(val != 0); +# if defined(_MSC_VER) +# if STATIC_BMI2 == 1 + return (unsigned)_lzcnt_u32(val); +# else + if (val != 0) { + unsigned long r; + _BitScanReverse(&r, val); + return (unsigned)(31 - r); + } else { + /* Should not reach this code path */ + __assume(0); + } +# endif +# elif defined(__GNUC__) && (__GNUC__ >= 4) + return (unsigned)__builtin_clz(val); +# else + return ZSTD_countLeadingZeros32_fallback(val); +# endif +} + +MEM_STATIC unsigned ZSTD_countTrailingZeros64(U64 val) +{ + assert(val != 0); +# if defined(_MSC_VER) && defined(_WIN64) +# if STATIC_BMI2 == 1 + return (unsigned)_tzcnt_u64(val); +# else + if (val != 0) { + unsigned long r; + _BitScanForward64(&r, val); + return (unsigned)r; + } else { + /* Should not reach this code path */ + __assume(0); + } +# endif +# elif defined(__GNUC__) && (__GNUC__ >= 4) && defined(__LP64__) + return (unsigned)__builtin_ctzll(val); +# else + { + U32 mostSignificantWord = (U32)(val >> 32); + U32 leastSignificantWord = (U32)val; + if (leastSignificantWord == 0) { + return 32 + ZSTD_countTrailingZeros32(mostSignificantWord); + } else { + return ZSTD_countTrailingZeros32(leastSignificantWord); + } + } +# endif +} + +MEM_STATIC unsigned ZSTD_countLeadingZeros64(U64 val) +{ + assert(val != 0); +# if defined(_MSC_VER) && defined(_WIN64) +# if STATIC_BMI2 == 1 + return (unsigned)_lzcnt_u64(val); +# else + if (val != 0) { + unsigned long r; + _BitScanReverse64(&r, val); + return (unsigned)(63 - r); + } else { + /* Should not reach this code path */ + __assume(0); + } +# endif +# elif defined(__GNUC__) && (__GNUC__ >= 4) + return (unsigned)(__builtin_clzll(val)); +# else + { + U32 mostSignificantWord = (U32)(val >> 32); + U32 leastSignificantWord = (U32)val; + if (mostSignificantWord == 0) { + return 32 + ZSTD_countLeadingZeros32(leastSignificantWord); + } else { + return ZSTD_countLeadingZeros32(mostSignificantWord); + } + } +# endif +} + +MEM_STATIC unsigned ZSTD_NbCommonBytes(size_t val) +{ + if (MEM_isLittleEndian()) { + if (MEM_64bits()) { + return ZSTD_countTrailingZeros64((U64)val) >> 3; + } else { + return ZSTD_countTrailingZeros32((U32)val) >> 3; + } + } else { /* Big Endian CPU */ + if (MEM_64bits()) { + return ZSTD_countLeadingZeros64((U64)val) >> 3; + } else { + return ZSTD_countLeadingZeros32((U32)val) >> 3; + } + } +} + +MEM_STATIC unsigned ZSTD_highbit32(U32 val) /* compress, dictBuilder, decodeCorpus */ +{ + assert(val != 0); + return 31 - ZSTD_countLeadingZeros32(val); +} + +/* ZSTD_rotateRight_*(): + * Rotates a bitfield to the right by "count" bits. + * https://en.wikipedia.org/w/index.php?title=Circular_shift&oldid=991635599#Implementing_circular_shifts + */ +MEM_STATIC +U64 ZSTD_rotateRight_U64(U64 const value, U32 count) { + assert(count < 64); + count &= 0x3F; /* for fickle pattern recognition */ + return (value >> count) | (U64)(value << ((0U - count) & 0x3F)); +} + +MEM_STATIC +U32 ZSTD_rotateRight_U32(U32 const value, U32 count) { + assert(count < 32); + count &= 0x1F; /* for fickle pattern recognition */ + return (value >> count) | (U32)(value << ((0U - count) & 0x1F)); +} + +MEM_STATIC +U16 ZSTD_rotateRight_U16(U16 const value, U32 count) { + assert(count < 16); + count &= 0x0F; /* for fickle pattern recognition */ + return (value >> count) | (U16)(value << ((0U - count) & 0x0F)); +} + +#endif /* ZSTD_BITS_H */ diff --git a/lib/zstd/lib/common/bitstream.h b/lib/zstd/lib/common/bitstream.h new file mode 100644 index 0000000..72b0b3d --- /dev/null +++ b/lib/zstd/lib/common/bitstream.h @@ -0,0 +1,437 @@ +/* ****************************************************************** + * bitstream + * Part of FSE library + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * You can contact the author at : + * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +****************************************************************** */ +#ifndef BITSTREAM_H_MODULE +#define BITSTREAM_H_MODULE + +#if defined (__cplusplus) +extern "C" { +#endif +/* +* This API consists of small unitary functions, which must be inlined for best performance. +* Since link-time-optimization is not available for all compilers, +* these functions are defined into a .h to be included. +*/ + +/*-**************************************** +* Dependencies +******************************************/ +#include "mem.h" /* unaligned access routines */ +#include "compiler.h" /* UNLIKELY() */ +#include "debug.h" /* assert(), DEBUGLOG(), RAWLOG() */ +#include "error_private.h" /* error codes and messages */ +#include "bits.h" /* ZSTD_highbit32 */ + + +/*========================================= +* Target specific +=========================================*/ +#ifndef ZSTD_NO_INTRINSICS +# if (defined(__BMI__) || defined(__BMI2__)) && defined(__GNUC__) +# include /* support for bextr (experimental)/bzhi */ +# elif defined(__ICCARM__) +# include +# endif +#endif + +#define STREAM_ACCUMULATOR_MIN_32 25 +#define STREAM_ACCUMULATOR_MIN_64 57 +#define STREAM_ACCUMULATOR_MIN ((U32)(MEM_32bits() ? STREAM_ACCUMULATOR_MIN_32 : STREAM_ACCUMULATOR_MIN_64)) + + +/*-****************************************** +* bitStream encoding API (write forward) +********************************************/ +/* bitStream can mix input from multiple sources. + * A critical property of these streams is that they encode and decode in **reverse** direction. + * So the first bit sequence you add will be the last to be read, like a LIFO stack. + */ +typedef struct { + size_t bitContainer; + unsigned bitPos; + char* startPtr; + char* ptr; + char* endPtr; +} BIT_CStream_t; + +MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, void* dstBuffer, size_t dstCapacity); +MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits); +MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC); +MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC); + +/* Start with initCStream, providing the size of buffer to write into. +* bitStream will never write outside of this buffer. +* `dstCapacity` must be >= sizeof(bitD->bitContainer), otherwise @return will be an error code. +* +* bits are first added to a local register. +* Local register is size_t, hence 64-bits on 64-bits systems, or 32-bits on 32-bits systems. +* Writing data into memory is an explicit operation, performed by the flushBits function. +* Hence keep track how many bits are potentially stored into local register to avoid register overflow. +* After a flushBits, a maximum of 7 bits might still be stored into local register. +* +* Avoid storing elements of more than 24 bits if you want compatibility with 32-bits bitstream readers. +* +* Last operation is to close the bitStream. +* The function returns the final size of CStream in bytes. +* If data couldn't fit into `dstBuffer`, it will return a 0 ( == not storable) +*/ + + +/*-******************************************** +* bitStream decoding API (read backward) +**********************************************/ +typedef struct { + size_t bitContainer; + unsigned bitsConsumed; + const char* ptr; + const char* start; + const char* limitPtr; +} BIT_DStream_t; + +typedef enum { BIT_DStream_unfinished = 0, + BIT_DStream_endOfBuffer = 1, + BIT_DStream_completed = 2, + BIT_DStream_overflow = 3 } BIT_DStream_status; /* result of BIT_reloadDStream() */ + /* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */ + +MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize); +MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits); +MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD); +MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD); + + +/* Start by invoking BIT_initDStream(). +* A chunk of the bitStream is then stored into a local register. +* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t). +* You can then retrieve bitFields stored into the local register, **in reverse order**. +* Local register is explicitly reloaded from memory by the BIT_reloadDStream() method. +* A reload guarantee a minimum of ((8*sizeof(bitD->bitContainer))-7) bits when its result is BIT_DStream_unfinished. +* Otherwise, it can be less than that, so proceed accordingly. +* Checking if DStream has reached its end can be performed with BIT_endOfDStream(). +*/ + + +/*-**************************************** +* unsafe API +******************************************/ +MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, size_t value, unsigned nbBits); +/* faster, but works only if value is "clean", meaning all high bits above nbBits are 0 */ + +MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC); +/* unsafe version; does not check buffer overflow */ + +MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits); +/* faster, but works only if nbBits >= 1 */ + +/*===== Local Constants =====*/ +static const unsigned BIT_mask[] = { + 0, 1, 3, 7, 0xF, 0x1F, + 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, + 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0x1FFFF, + 0x3FFFF, 0x7FFFF, 0xFFFFF, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, + 0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF, 0x1FFFFFFF, + 0x3FFFFFFF, 0x7FFFFFFF}; /* up to 31 bits */ +#define BIT_MASK_SIZE (sizeof(BIT_mask) / sizeof(BIT_mask[0])) + +/*-************************************************************** +* bitStream encoding +****************************************************************/ +/*! BIT_initCStream() : + * `dstCapacity` must be > sizeof(size_t) + * @return : 0 if success, + * otherwise an error code (can be tested using ERR_isError()) */ +MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, + void* startPtr, size_t dstCapacity) +{ + bitC->bitContainer = 0; + bitC->bitPos = 0; + bitC->startPtr = (char*)startPtr; + bitC->ptr = bitC->startPtr; + bitC->endPtr = bitC->startPtr + dstCapacity - sizeof(bitC->bitContainer); + if (dstCapacity <= sizeof(bitC->bitContainer)) return ERROR(dstSize_tooSmall); + return 0; +} + +MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits) +{ +#if defined(STATIC_BMI2) && STATIC_BMI2 == 1 && !defined(ZSTD_NO_INTRINSICS) + return _bzhi_u64(bitContainer, nbBits); +#else + assert(nbBits < BIT_MASK_SIZE); + return bitContainer & BIT_mask[nbBits]; +#endif +} + +/*! BIT_addBits() : + * can add up to 31 bits into `bitC`. + * Note : does not check for register overflow ! */ +MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, + size_t value, unsigned nbBits) +{ + DEBUG_STATIC_ASSERT(BIT_MASK_SIZE == 32); + assert(nbBits < BIT_MASK_SIZE); + assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8); + bitC->bitContainer |= BIT_getLowerBits(value, nbBits) << bitC->bitPos; + bitC->bitPos += nbBits; +} + +/*! BIT_addBitsFast() : + * works only if `value` is _clean_, + * meaning all high bits above nbBits are 0 */ +MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, + size_t value, unsigned nbBits) +{ + assert((value>>nbBits) == 0); + assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8); + bitC->bitContainer |= value << bitC->bitPos; + bitC->bitPos += nbBits; +} + +/*! BIT_flushBitsFast() : + * assumption : bitContainer has not overflowed + * unsafe version; does not check buffer overflow */ +MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC) +{ + size_t const nbBytes = bitC->bitPos >> 3; + assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8); + assert(bitC->ptr <= bitC->endPtr); + MEM_writeLEST(bitC->ptr, bitC->bitContainer); + bitC->ptr += nbBytes; + bitC->bitPos &= 7; + bitC->bitContainer >>= nbBytes*8; +} + +/*! BIT_flushBits() : + * assumption : bitContainer has not overflowed + * safe version; check for buffer overflow, and prevents it. + * note : does not signal buffer overflow. + * overflow will be revealed later on using BIT_closeCStream() */ +MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC) +{ + size_t const nbBytes = bitC->bitPos >> 3; + assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8); + assert(bitC->ptr <= bitC->endPtr); + MEM_writeLEST(bitC->ptr, bitC->bitContainer); + bitC->ptr += nbBytes; + if (bitC->ptr > bitC->endPtr) bitC->ptr = bitC->endPtr; + bitC->bitPos &= 7; + bitC->bitContainer >>= nbBytes*8; +} + +/*! BIT_closeCStream() : + * @return : size of CStream, in bytes, + * or 0 if it could not fit into dstBuffer */ +MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC) +{ + BIT_addBitsFast(bitC, 1, 1); /* endMark */ + BIT_flushBits(bitC); + if (bitC->ptr >= bitC->endPtr) return 0; /* overflow detected */ + return (bitC->ptr - bitC->startPtr) + (bitC->bitPos > 0); +} + + +/*-******************************************************** +* bitStream decoding +**********************************************************/ +/*! BIT_initDStream() : + * Initialize a BIT_DStream_t. + * `bitD` : a pointer to an already allocated BIT_DStream_t structure. + * `srcSize` must be the *exact* size of the bitStream, in bytes. + * @return : size of stream (== srcSize), or an errorCode if a problem is detected + */ +MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize) +{ + if (srcSize < 1) { ZSTD_memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); } + + bitD->start = (const char*)srcBuffer; + bitD->limitPtr = bitD->start + sizeof(bitD->bitContainer); + + if (srcSize >= sizeof(bitD->bitContainer)) { /* normal case */ + bitD->ptr = (const char*)srcBuffer + srcSize - sizeof(bitD->bitContainer); + bitD->bitContainer = MEM_readLEST(bitD->ptr); + { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1]; + bitD->bitsConsumed = lastByte ? 8 - ZSTD_highbit32(lastByte) : 0; /* ensures bitsConsumed is always set */ + if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ } + } else { + bitD->ptr = bitD->start; + bitD->bitContainer = *(const BYTE*)(bitD->start); + switch(srcSize) + { + case 7: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16); + ZSTD_FALLTHROUGH; + + case 6: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24); + ZSTD_FALLTHROUGH; + + case 5: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32); + ZSTD_FALLTHROUGH; + + case 4: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[3]) << 24; + ZSTD_FALLTHROUGH; + + case 3: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[2]) << 16; + ZSTD_FALLTHROUGH; + + case 2: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[1]) << 8; + ZSTD_FALLTHROUGH; + + default: break; + } + { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1]; + bitD->bitsConsumed = lastByte ? 8 - ZSTD_highbit32(lastByte) : 0; + if (lastByte == 0) return ERROR(corruption_detected); /* endMark not present */ + } + bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize)*8; + } + + return srcSize; +} + +MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getUpperBits(size_t bitContainer, U32 const start) +{ + return bitContainer >> start; +} + +MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits) +{ + U32 const regMask = sizeof(bitContainer)*8 - 1; + /* if start > regMask, bitstream is corrupted, and result is undefined */ + assert(nbBits < BIT_MASK_SIZE); + /* x86 transform & ((1 << nbBits) - 1) to bzhi instruction, it is better + * than accessing memory. When bmi2 instruction is not present, we consider + * such cpus old (pre-Haswell, 2013) and their performance is not of that + * importance. + */ +#if defined(__x86_64__) || defined(_M_X86) + return (bitContainer >> (start & regMask)) & ((((U64)1) << nbBits) - 1); +#else + return (bitContainer >> (start & regMask)) & BIT_mask[nbBits]; +#endif +} + +/*! BIT_lookBits() : + * Provides next n bits from local register. + * local register is not modified. + * On 32-bits, maxNbBits==24. + * On 64-bits, maxNbBits==56. + * @return : value extracted */ +MEM_STATIC FORCE_INLINE_ATTR size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits) +{ + /* arbitrate between double-shift and shift+mask */ +#if 1 + /* if bitD->bitsConsumed + nbBits > sizeof(bitD->bitContainer)*8, + * bitstream is likely corrupted, and result is undefined */ + return BIT_getMiddleBits(bitD->bitContainer, (sizeof(bitD->bitContainer)*8) - bitD->bitsConsumed - nbBits, nbBits); +#else + /* this code path is slower on my os-x laptop */ + U32 const regMask = sizeof(bitD->bitContainer)*8 - 1; + return ((bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> 1) >> ((regMask-nbBits) & regMask); +#endif +} + +/*! BIT_lookBitsFast() : + * unsafe version; only works if nbBits >= 1 */ +MEM_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t* bitD, U32 nbBits) +{ + U32 const regMask = sizeof(bitD->bitContainer)*8 - 1; + assert(nbBits >= 1); + return (bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> (((regMask+1)-nbBits) & regMask); +} + +MEM_STATIC FORCE_INLINE_ATTR void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits) +{ + bitD->bitsConsumed += nbBits; +} + +/*! BIT_readBits() : + * Read (consume) next n bits from local register and update. + * Pay attention to not read more than nbBits contained into local register. + * @return : extracted value. */ +MEM_STATIC FORCE_INLINE_ATTR size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits) +{ + size_t const value = BIT_lookBits(bitD, nbBits); + BIT_skipBits(bitD, nbBits); + return value; +} + +/*! BIT_readBitsFast() : + * unsafe version; only works if nbBits >= 1 */ +MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits) +{ + size_t const value = BIT_lookBitsFast(bitD, nbBits); + assert(nbBits >= 1); + BIT_skipBits(bitD, nbBits); + return value; +} + +/*! BIT_reloadDStreamFast() : + * Similar to BIT_reloadDStream(), but with two differences: + * 1. bitsConsumed <= sizeof(bitD->bitContainer)*8 must hold! + * 2. Returns BIT_DStream_overflow when bitD->ptr < bitD->limitPtr, at this + * point you must use BIT_reloadDStream() to reload. + */ +MEM_STATIC BIT_DStream_status BIT_reloadDStreamFast(BIT_DStream_t* bitD) +{ + if (UNLIKELY(bitD->ptr < bitD->limitPtr)) + return BIT_DStream_overflow; + assert(bitD->bitsConsumed <= sizeof(bitD->bitContainer)*8); + bitD->ptr -= bitD->bitsConsumed >> 3; + bitD->bitsConsumed &= 7; + bitD->bitContainer = MEM_readLEST(bitD->ptr); + return BIT_DStream_unfinished; +} + +/*! BIT_reloadDStream() : + * Refill `bitD` from buffer previously set in BIT_initDStream() . + * This function is safe, it guarantees it will not read beyond src buffer. + * @return : status of `BIT_DStream_t` internal register. + * when status == BIT_DStream_unfinished, internal register is filled with at least 25 or 57 bits */ +MEM_STATIC FORCE_INLINE_ATTR BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD) +{ + if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* overflow detected, like end of stream */ + return BIT_DStream_overflow; + + if (bitD->ptr >= bitD->limitPtr) { + return BIT_reloadDStreamFast(bitD); + } + if (bitD->ptr == bitD->start) { + if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BIT_DStream_endOfBuffer; + return BIT_DStream_completed; + } + /* start < ptr < limitPtr */ + { U32 nbBytes = bitD->bitsConsumed >> 3; + BIT_DStream_status result = BIT_DStream_unfinished; + if (bitD->ptr - nbBytes < bitD->start) { + nbBytes = (U32)(bitD->ptr - bitD->start); /* ptr > start */ + result = BIT_DStream_endOfBuffer; + } + bitD->ptr -= nbBytes; + bitD->bitsConsumed -= nbBytes*8; + bitD->bitContainer = MEM_readLEST(bitD->ptr); /* reminder : srcSize > sizeof(bitD->bitContainer), otherwise bitD->ptr == bitD->start */ + return result; + } +} + +/*! BIT_endOfDStream() : + * @return : 1 if DStream has _exactly_ reached its end (all bits consumed). + */ +MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* DStream) +{ + return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer)*8)); +} + +#if defined (__cplusplus) +} +#endif + +#endif /* BITSTREAM_H_MODULE */ diff --git a/lib/zstd/lib/common/compiler.h b/lib/zstd/lib/common/compiler.h new file mode 100644 index 0000000..73f8d01 --- /dev/null +++ b/lib/zstd/lib/common/compiler.h @@ -0,0 +1,358 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef ZSTD_COMPILER_H +#define ZSTD_COMPILER_H + +#include "portability_macros.h" + +/*-******************************************************* +* Compiler specifics +*********************************************************/ +/* force inlining */ + +#if !defined(ZSTD_NO_INLINE) +#if (defined(__GNUC__) && !defined(__STRICT_ANSI__)) || defined(__cplusplus) || defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ +# define INLINE_KEYWORD inline +#else +# define INLINE_KEYWORD +#endif + +#if defined(__GNUC__) || defined(__ICCARM__) +# define FORCE_INLINE_ATTR __attribute__((always_inline)) +#elif defined(_MSC_VER) +# define FORCE_INLINE_ATTR __forceinline +#else +# define FORCE_INLINE_ATTR +#endif + +#else + +#define INLINE_KEYWORD +#define FORCE_INLINE_ATTR + +#endif + +/** + On MSVC qsort requires that functions passed into it use the __cdecl calling conversion(CC). + This explicitly marks such functions as __cdecl so that the code will still compile + if a CC other than __cdecl has been made the default. +*/ +#if defined(_MSC_VER) +# define WIN_CDECL __cdecl +#else +# define WIN_CDECL +#endif + +/** + * FORCE_INLINE_TEMPLATE is used to define C "templates", which take constant + * parameters. They must be inlined for the compiler to eliminate the constant + * branches. + */ +#define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR +/** + * HINT_INLINE is used to help the compiler generate better code. It is *not* + * used for "templates", so it can be tweaked based on the compilers + * performance. + * + * gcc-4.8 and gcc-4.9 have been shown to benefit from leaving off the + * always_inline attribute. + * + * clang up to 5.0.0 (trunk) benefit tremendously from the always_inline + * attribute. + */ +#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8 && __GNUC__ < 5 +# define HINT_INLINE static INLINE_KEYWORD +#else +# define HINT_INLINE static INLINE_KEYWORD FORCE_INLINE_ATTR +#endif + +/* UNUSED_ATTR tells the compiler it is okay if the function is unused. */ +#if defined(__GNUC__) +# define UNUSED_ATTR __attribute__((unused)) +#else +# define UNUSED_ATTR +#endif + +/* force no inlining */ +#ifdef _MSC_VER +# define FORCE_NOINLINE static __declspec(noinline) +#else +# if defined(__GNUC__) || defined(__ICCARM__) +# define FORCE_NOINLINE static __attribute__((__noinline__)) +# else +# define FORCE_NOINLINE static +# endif +#endif + + +/* target attribute */ +#if defined(__GNUC__) || defined(__ICCARM__) +# define TARGET_ATTRIBUTE(target) __attribute__((__target__(target))) +#else +# define TARGET_ATTRIBUTE(target) +#endif + +/* Target attribute for BMI2 dynamic dispatch. + * Enable lzcnt, bmi, and bmi2. + * We test for bmi1 & bmi2. lzcnt is included in bmi1. + */ +#define BMI2_TARGET_ATTRIBUTE TARGET_ATTRIBUTE("lzcnt,bmi,bmi2") + +/* prefetch + * can be disabled, by declaring NO_PREFETCH build macro */ +#if defined(NO_PREFETCH) +# define PREFETCH_L1(ptr) (void)(ptr) /* disabled */ +# define PREFETCH_L2(ptr) (void)(ptr) /* disabled */ +#else +# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) /* _mm_prefetch() is not defined outside of x86/x64 */ +# include /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */ +# define PREFETCH_L1(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0) +# define PREFETCH_L2(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T1) +# elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) ) +# define PREFETCH_L1(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */) +# define PREFETCH_L2(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 2 /* locality */) +# elif defined(__aarch64__) +# define PREFETCH_L1(ptr) __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr))) +# define PREFETCH_L2(ptr) __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr))) +# else +# define PREFETCH_L1(ptr) (void)(ptr) /* disabled */ +# define PREFETCH_L2(ptr) (void)(ptr) /* disabled */ +# endif +#endif /* NO_PREFETCH */ + +#define CACHELINE_SIZE 64 + +#define PREFETCH_AREA(p, s) { \ + const char* const _ptr = (const char*)(p); \ + size_t const _size = (size_t)(s); \ + size_t _pos; \ + for (_pos=0; _pos<_size; _pos+=CACHELINE_SIZE) { \ + PREFETCH_L2(_ptr + _pos); \ + } \ +} + +/* vectorization + * older GCC (pre gcc-4.3 picked as the cutoff) uses a different syntax, + * and some compilers, like Intel ICC and MCST LCC, do not support it at all. */ +#if !defined(__INTEL_COMPILER) && !defined(__clang__) && defined(__GNUC__) && !defined(__LCC__) +# if (__GNUC__ == 4 && __GNUC_MINOR__ > 3) || (__GNUC__ >= 5) +# define DONT_VECTORIZE __attribute__((optimize("no-tree-vectorize"))) +# else +# define DONT_VECTORIZE _Pragma("GCC optimize(\"no-tree-vectorize\")") +# endif +#else +# define DONT_VECTORIZE +#endif + +/* Tell the compiler that a branch is likely or unlikely. + * Only use these macros if it causes the compiler to generate better code. + * If you can remove a LIKELY/UNLIKELY annotation without speed changes in gcc + * and clang, please do. + */ +#if defined(__GNUC__) +#define LIKELY(x) (__builtin_expect((x), 1)) +#define UNLIKELY(x) (__builtin_expect((x), 0)) +#else +#define LIKELY(x) (x) +#define UNLIKELY(x) (x) +#endif + +#if __has_builtin(__builtin_unreachable) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))) +# define ZSTD_UNREACHABLE { assert(0), __builtin_unreachable(); } +#else +# define ZSTD_UNREACHABLE { assert(0); } +#endif + +/* disable warnings */ +#ifdef _MSC_VER /* Visual Studio */ +# include /* For Visual 2005 */ +# pragma warning(disable : 4100) /* disable: C4100: unreferenced formal parameter */ +# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ +# pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */ +# pragma warning(disable : 4214) /* disable: C4214: non-int bitfields */ +# pragma warning(disable : 4324) /* disable: C4324: padded structure */ +#endif + +/*Like DYNAMIC_BMI2 but for compile time determination of BMI2 support*/ +#ifndef STATIC_BMI2 +# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) +# ifdef __AVX2__ //MSVC does not have a BMI2 specific flag, but every CPU that supports AVX2 also supports BMI2 +# define STATIC_BMI2 1 +# endif +# elif defined(__BMI2__) && defined(__x86_64__) && defined(__GNUC__) +# define STATIC_BMI2 1 +# endif +#endif + +#ifndef STATIC_BMI2 + #define STATIC_BMI2 0 +#endif + +/* compile time determination of SIMD support */ +#if !defined(ZSTD_NO_INTRINSICS) +# if defined(__SSE2__) || defined(_M_AMD64) || (defined (_M_IX86) && defined(_M_IX86_FP) && (_M_IX86_FP >= 2)) +# define ZSTD_ARCH_X86_SSE2 +# endif +# if defined(__ARM_NEON) || defined(_M_ARM64) +# define ZSTD_ARCH_ARM_NEON +# endif +# +# if defined(ZSTD_ARCH_X86_SSE2) +# include +# elif defined(ZSTD_ARCH_ARM_NEON) +# include +# endif +#endif + +/* C-language Attributes are added in C23. */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ > 201710L) && defined(__has_c_attribute) +# define ZSTD_HAS_C_ATTRIBUTE(x) __has_c_attribute(x) +#else +# define ZSTD_HAS_C_ATTRIBUTE(x) 0 +#endif + +/* Only use C++ attributes in C++. Some compilers report support for C++ + * attributes when compiling with C. + */ +#if defined(__cplusplus) && defined(__has_cpp_attribute) +# define ZSTD_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +# define ZSTD_HAS_CPP_ATTRIBUTE(x) 0 +#endif + +/* Define ZSTD_FALLTHROUGH macro for annotating switch case with the 'fallthrough' attribute. + * - C23: https://en.cppreference.com/w/c/language/attributes/fallthrough + * - CPP17: https://en.cppreference.com/w/cpp/language/attributes/fallthrough + * - Else: __attribute__((__fallthrough__)) + */ +#ifndef ZSTD_FALLTHROUGH +# if ZSTD_HAS_C_ATTRIBUTE(fallthrough) +# define ZSTD_FALLTHROUGH [[fallthrough]] +# elif ZSTD_HAS_CPP_ATTRIBUTE(fallthrough) +# define ZSTD_FALLTHROUGH [[fallthrough]] +# elif __has_attribute(__fallthrough__) +/* Leading semicolon is to satisfy gcc-11 with -pedantic. Without the semicolon + * gcc complains about: a label can only be part of a statement and a declaration is not a statement. + */ +# define ZSTD_FALLTHROUGH ; __attribute__((__fallthrough__)) +# else +# define ZSTD_FALLTHROUGH +# endif +#endif + +/*-************************************************************** +* Alignment check +*****************************************************************/ + +/* this test was initially positioned in mem.h, + * but this file is removed (or replaced) for linux kernel + * so it's now hosted in compiler.h, + * which remains valid for both user & kernel spaces. + */ + +#ifndef ZSTD_ALIGNOF +# if defined(__GNUC__) || defined(_MSC_VER) +/* covers gcc, clang & MSVC */ +/* note : this section must come first, before C11, + * due to a limitation in the kernel source generator */ +# define ZSTD_ALIGNOF(T) __alignof(T) + +# elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) +/* C11 support */ +# include +# define ZSTD_ALIGNOF(T) alignof(T) + +# else +/* No known support for alignof() - imperfect backup */ +# define ZSTD_ALIGNOF(T) (sizeof(void*) < sizeof(T) ? sizeof(void*) : sizeof(T)) + +# endif +#endif /* ZSTD_ALIGNOF */ + +/*-************************************************************** +* Sanitizer +*****************************************************************/ + +/* Issue #3240 reports an ASAN failure on an llvm-mingw build. Out of an + * abundance of caution, disable our custom poisoning on mingw. */ +#ifdef __MINGW32__ +#ifndef ZSTD_ASAN_DONT_POISON_WORKSPACE +#define ZSTD_ASAN_DONT_POISON_WORKSPACE 1 +#endif +#ifndef ZSTD_MSAN_DONT_POISON_WORKSPACE +#define ZSTD_MSAN_DONT_POISON_WORKSPACE 1 +#endif +#endif + +#if ZSTD_MEMORY_SANITIZER && !defined(ZSTD_MSAN_DONT_POISON_WORKSPACE) +/* Not all platforms that support msan provide sanitizers/msan_interface.h. + * We therefore declare the functions we need ourselves, rather than trying to + * include the header file... */ +#include /* size_t */ +#define ZSTD_DEPS_NEED_STDINT +#include "zstd_deps.h" /* intptr_t */ + +/* Make memory region fully initialized (without changing its contents). */ +void __msan_unpoison(const volatile void *a, size_t size); + +/* Make memory region fully uninitialized (without changing its contents). + This is a legacy interface that does not update origin information. Use + __msan_allocated_memory() instead. */ +void __msan_poison(const volatile void *a, size_t size); + +/* Returns the offset of the first (at least partially) poisoned byte in the + memory range, or -1 if the whole range is good. */ +intptr_t __msan_test_shadow(const volatile void *x, size_t size); + +/* Print shadow and origin for the memory range to stderr in a human-readable + format. */ +void __msan_print_shadow(const volatile void *x, size_t size); +#endif + +#if ZSTD_ADDRESS_SANITIZER && !defined(ZSTD_ASAN_DONT_POISON_WORKSPACE) +/* Not all platforms that support asan provide sanitizers/asan_interface.h. + * We therefore declare the functions we need ourselves, rather than trying to + * include the header file... */ +#include /* size_t */ + +/** + * Marks a memory region ([addr, addr+size)) as unaddressable. + * + * This memory must be previously allocated by your program. Instrumented + * code is forbidden from accessing addresses in this region until it is + * unpoisoned. This function is not guaranteed to poison the entire region - + * it could poison only a subregion of [addr, addr+size) due to ASan + * alignment restrictions. + * + * \note This function is not thread-safe because no two threads can poison or + * unpoison memory in the same memory region simultaneously. + * + * \param addr Start of memory region. + * \param size Size of memory region. */ +void __asan_poison_memory_region(void const volatile *addr, size_t size); + +/** + * Marks a memory region ([addr, addr+size)) as addressable. + * + * This memory must be previously allocated by your program. Accessing + * addresses in this region is allowed until this region is poisoned again. + * This function could unpoison a super-region of [addr, addr+size) due + * to ASan alignment restrictions. + * + * \note This function is not thread-safe because no two threads can + * poison or unpoison memory in the same memory region simultaneously. + * + * \param addr Start of memory region. + * \param size Size of memory region. */ +void __asan_unpoison_memory_region(void const volatile *addr, size_t size); +#endif + +#endif /* ZSTD_COMPILER_H */ diff --git a/lib/zstd/lib/common/cpu.h b/lib/zstd/lib/common/cpu.h new file mode 100644 index 0000000..8bc34a3 --- /dev/null +++ b/lib/zstd/lib/common/cpu.h @@ -0,0 +1,213 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef ZSTD_COMMON_CPU_H +#define ZSTD_COMMON_CPU_H + +/** + * Implementation taken from folly/CpuId.h + * https://github.com/facebook/folly/blob/master/folly/CpuId.h + */ + +#include "mem.h" + +#ifdef _MSC_VER +#include +#endif + +typedef struct { + U32 f1c; + U32 f1d; + U32 f7b; + U32 f7c; +} ZSTD_cpuid_t; + +MEM_STATIC ZSTD_cpuid_t ZSTD_cpuid(void) { + U32 f1c = 0; + U32 f1d = 0; + U32 f7b = 0; + U32 f7c = 0; +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) + int reg[4]; + __cpuid((int*)reg, 0); + { + int const n = reg[0]; + if (n >= 1) { + __cpuid((int*)reg, 1); + f1c = (U32)reg[2]; + f1d = (U32)reg[3]; + } + if (n >= 7) { + __cpuidex((int*)reg, 7, 0); + f7b = (U32)reg[1]; + f7c = (U32)reg[2]; + } + } +#elif defined(__i386__) && defined(__PIC__) && !defined(__clang__) && defined(__GNUC__) + /* The following block like the normal cpuid branch below, but gcc + * reserves ebx for use of its pic register so we must specially + * handle the save and restore to avoid clobbering the register + */ + U32 n; + __asm__( + "pushl %%ebx\n\t" + "cpuid\n\t" + "popl %%ebx\n\t" + : "=a"(n) + : "a"(0) + : "ecx", "edx"); + if (n >= 1) { + U32 f1a; + __asm__( + "pushl %%ebx\n\t" + "cpuid\n\t" + "popl %%ebx\n\t" + : "=a"(f1a), "=c"(f1c), "=d"(f1d) + : "a"(1)); + } + if (n >= 7) { + __asm__( + "pushl %%ebx\n\t" + "cpuid\n\t" + "movl %%ebx, %%eax\n\t" + "popl %%ebx" + : "=a"(f7b), "=c"(f7c) + : "a"(7), "c"(0) + : "edx"); + } +#elif defined(__x86_64__) || defined(_M_X64) || defined(__i386__) + U32 n; + __asm__("cpuid" : "=a"(n) : "a"(0) : "ebx", "ecx", "edx"); + if (n >= 1) { + U32 f1a; + __asm__("cpuid" : "=a"(f1a), "=c"(f1c), "=d"(f1d) : "a"(1) : "ebx"); + } + if (n >= 7) { + U32 f7a; + __asm__("cpuid" + : "=a"(f7a), "=b"(f7b), "=c"(f7c) + : "a"(7), "c"(0) + : "edx"); + } +#endif + { + ZSTD_cpuid_t cpuid; + cpuid.f1c = f1c; + cpuid.f1d = f1d; + cpuid.f7b = f7b; + cpuid.f7c = f7c; + return cpuid; + } +} + +#define X(name, r, bit) \ + MEM_STATIC int ZSTD_cpuid_##name(ZSTD_cpuid_t const cpuid) { \ + return ((cpuid.r) & (1U << bit)) != 0; \ + } + +/* cpuid(1): Processor Info and Feature Bits. */ +#define C(name, bit) X(name, f1c, bit) + C(sse3, 0) + C(pclmuldq, 1) + C(dtes64, 2) + C(monitor, 3) + C(dscpl, 4) + C(vmx, 5) + C(smx, 6) + C(eist, 7) + C(tm2, 8) + C(ssse3, 9) + C(cnxtid, 10) + C(fma, 12) + C(cx16, 13) + C(xtpr, 14) + C(pdcm, 15) + C(pcid, 17) + C(dca, 18) + C(sse41, 19) + C(sse42, 20) + C(x2apic, 21) + C(movbe, 22) + C(popcnt, 23) + C(tscdeadline, 24) + C(aes, 25) + C(xsave, 26) + C(osxsave, 27) + C(avx, 28) + C(f16c, 29) + C(rdrand, 30) +#undef C +#define D(name, bit) X(name, f1d, bit) + D(fpu, 0) + D(vme, 1) + D(de, 2) + D(pse, 3) + D(tsc, 4) + D(msr, 5) + D(pae, 6) + D(mce, 7) + D(cx8, 8) + D(apic, 9) + D(sep, 11) + D(mtrr, 12) + D(pge, 13) + D(mca, 14) + D(cmov, 15) + D(pat, 16) + D(pse36, 17) + D(psn, 18) + D(clfsh, 19) + D(ds, 21) + D(acpi, 22) + D(mmx, 23) + D(fxsr, 24) + D(sse, 25) + D(sse2, 26) + D(ss, 27) + D(htt, 28) + D(tm, 29) + D(pbe, 31) +#undef D + +/* cpuid(7): Extended Features. */ +#define B(name, bit) X(name, f7b, bit) + B(bmi1, 3) + B(hle, 4) + B(avx2, 5) + B(smep, 7) + B(bmi2, 8) + B(erms, 9) + B(invpcid, 10) + B(rtm, 11) + B(mpx, 14) + B(avx512f, 16) + B(avx512dq, 17) + B(rdseed, 18) + B(adx, 19) + B(smap, 20) + B(avx512ifma, 21) + B(pcommit, 22) + B(clflushopt, 23) + B(clwb, 24) + B(avx512pf, 26) + B(avx512er, 27) + B(avx512cd, 28) + B(sha, 29) + B(avx512bw, 30) + B(avx512vl, 31) +#undef B +#define C(name, bit) X(name, f7c, bit) + C(prefetchwt1, 0) + C(avx512vbmi, 1) +#undef C + +#undef X + +#endif /* ZSTD_COMMON_CPU_H */ diff --git a/lib/zstd/lib/common/debug.c b/lib/zstd/lib/common/debug.c new file mode 100644 index 0000000..ebf7bfc --- /dev/null +++ b/lib/zstd/lib/common/debug.c @@ -0,0 +1,24 @@ +/* ****************************************************************** + * debug + * Part of FSE library + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * You can contact the author at : + * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +****************************************************************** */ + + +/* + * This module only hosts one global variable + * which can be used to dynamically influence the verbosity of traces, + * such as DEBUGLOG and RAWLOG + */ + +#include "debug.h" + +int g_debuglevel = DEBUGLEVEL; diff --git a/lib/zstd/lib/common/debug.h b/lib/zstd/lib/common/debug.h new file mode 100644 index 0000000..0e9817e --- /dev/null +++ b/lib/zstd/lib/common/debug.h @@ -0,0 +1,107 @@ +/* ****************************************************************** + * debug + * Part of FSE library + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * You can contact the author at : + * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +****************************************************************** */ + + +/* + * The purpose of this header is to enable debug functions. + * They regroup assert(), DEBUGLOG() and RAWLOG() for run-time, + * and DEBUG_STATIC_ASSERT() for compile-time. + * + * By default, DEBUGLEVEL==0, which means run-time debug is disabled. + * + * Level 1 enables assert() only. + * Starting level 2, traces can be generated and pushed to stderr. + * The higher the level, the more verbose the traces. + * + * It's possible to dynamically adjust level using variable g_debug_level, + * which is only declared if DEBUGLEVEL>=2, + * and is a global variable, not multi-thread protected (use with care) + */ + +#ifndef DEBUG_H_12987983217 +#define DEBUG_H_12987983217 + +#if defined (__cplusplus) +extern "C" { +#endif + + +/* static assert is triggered at compile time, leaving no runtime artefact. + * static assert only works with compile-time constants. + * Also, this variant can only be used inside a function. */ +#define DEBUG_STATIC_ASSERT(c) (void)sizeof(char[(c) ? 1 : -1]) + + +/* DEBUGLEVEL is expected to be defined externally, + * typically through compiler command line. + * Value must be a number. */ +#ifndef DEBUGLEVEL +# define DEBUGLEVEL 0 +#endif + + +/* recommended values for DEBUGLEVEL : + * 0 : release mode, no debug, all run-time checks disabled + * 1 : enables assert() only, no display + * 2 : reserved, for currently active debug path + * 3 : events once per object lifetime (CCtx, CDict, etc.) + * 4 : events once per frame + * 5 : events once per block + * 6 : events once per sequence (verbose) + * 7+: events at every position (*very* verbose) + * + * It's generally inconvenient to output traces > 5. + * In which case, it's possible to selectively trigger high verbosity levels + * by modifying g_debug_level. + */ + +#if (DEBUGLEVEL>=1) +# define ZSTD_DEPS_NEED_ASSERT +# include "zstd_deps.h" +#else +# ifndef assert /* assert may be already defined, due to prior #include */ +# define assert(condition) ((void)0) /* disable assert (default) */ +# endif +#endif + +#if (DEBUGLEVEL>=2) +# define ZSTD_DEPS_NEED_IO +# include "zstd_deps.h" +extern int g_debuglevel; /* the variable is only declared, + it actually lives in debug.c, + and is shared by the whole process. + It's not thread-safe. + It's useful when enabling very verbose levels + on selective conditions (such as position in src) */ + +# define RAWLOG(l, ...) { \ + if (l<=g_debuglevel) { \ + ZSTD_DEBUG_PRINT(__VA_ARGS__); \ + } } +# define DEBUGLOG(l, ...) { \ + if (l<=g_debuglevel) { \ + ZSTD_DEBUG_PRINT(__FILE__ ": " __VA_ARGS__); \ + ZSTD_DEBUG_PRINT(" \n"); \ + } } +#else +# define RAWLOG(l, ...) {} /* disabled */ +# define DEBUGLOG(l, ...) {} /* disabled */ +#endif + + +#if defined (__cplusplus) +} +#endif + +#endif /* DEBUG_H_12987983217 */ diff --git a/lib/zstd/lib/common/entropy_common.c b/lib/zstd/lib/common/entropy_common.c new file mode 100644 index 0000000..e2173af --- /dev/null +++ b/lib/zstd/lib/common/entropy_common.c @@ -0,0 +1,340 @@ +/* ****************************************************************** + * Common functions of New Generation Entropy library + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * You can contact the author at : + * - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy + * - Public forum : https://groups.google.com/forum/#!forum/lz4c + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +****************************************************************** */ + +/* ************************************* +* Dependencies +***************************************/ +#include "mem.h" +#include "error_private.h" /* ERR_*, ERROR */ +#define FSE_STATIC_LINKING_ONLY /* FSE_MIN_TABLELOG */ +#include "fse.h" +#include "huf.h" +#include "bits.h" /* ZSDT_highbit32, ZSTD_countTrailingZeros32 */ + + +/*=== Version ===*/ +unsigned FSE_versionNumber(void) { return FSE_VERSION_NUMBER; } + + +/*=== Error Management ===*/ +unsigned FSE_isError(size_t code) { return ERR_isError(code); } +const char* FSE_getErrorName(size_t code) { return ERR_getErrorName(code); } + +unsigned HUF_isError(size_t code) { return ERR_isError(code); } +const char* HUF_getErrorName(size_t code) { return ERR_getErrorName(code); } + + +/*-************************************************************** +* FSE NCount encoding-decoding +****************************************************************/ +FORCE_INLINE_TEMPLATE +size_t FSE_readNCount_body(short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, + const void* headerBuffer, size_t hbSize) +{ + const BYTE* const istart = (const BYTE*) headerBuffer; + const BYTE* const iend = istart + hbSize; + const BYTE* ip = istart; + int nbBits; + int remaining; + int threshold; + U32 bitStream; + int bitCount; + unsigned charnum = 0; + unsigned const maxSV1 = *maxSVPtr + 1; + int previous0 = 0; + + if (hbSize < 8) { + /* This function only works when hbSize >= 8 */ + char buffer[8] = {0}; + ZSTD_memcpy(buffer, headerBuffer, hbSize); + { size_t const countSize = FSE_readNCount(normalizedCounter, maxSVPtr, tableLogPtr, + buffer, sizeof(buffer)); + if (FSE_isError(countSize)) return countSize; + if (countSize > hbSize) return ERROR(corruption_detected); + return countSize; + } } + assert(hbSize >= 8); + + /* init */ + ZSTD_memset(normalizedCounter, 0, (*maxSVPtr+1) * sizeof(normalizedCounter[0])); /* all symbols not present in NCount have a frequency of 0 */ + bitStream = MEM_readLE32(ip); + nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG; /* extract tableLog */ + if (nbBits > FSE_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge); + bitStream >>= 4; + bitCount = 4; + *tableLogPtr = nbBits; + remaining = (1<> 1; + while (repeats >= 12) { + charnum += 3 * 12; + if (LIKELY(ip <= iend-7)) { + ip += 3; + } else { + bitCount -= (int)(8 * (iend - 7 - ip)); + bitCount &= 31; + ip = iend - 4; + } + bitStream = MEM_readLE32(ip) >> bitCount; + repeats = ZSTD_countTrailingZeros32(~bitStream | 0x80000000) >> 1; + } + charnum += 3 * repeats; + bitStream >>= 2 * repeats; + bitCount += 2 * repeats; + + /* Add the final repeat which isn't 0b11. */ + assert((bitStream & 3) < 3); + charnum += bitStream & 3; + bitCount += 2; + + /* This is an error, but break and return an error + * at the end, because returning out of a loop makes + * it harder for the compiler to optimize. + */ + if (charnum >= maxSV1) break; + + /* We don't need to set the normalized count to 0 + * because we already memset the whole buffer to 0. + */ + + if (LIKELY(ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { + assert((bitCount >> 3) <= 3); /* For first condition to work */ + ip += bitCount>>3; + bitCount &= 7; + } else { + bitCount -= (int)(8 * (iend - 4 - ip)); + bitCount &= 31; + ip = iend - 4; + } + bitStream = MEM_readLE32(ip) >> bitCount; + } + { + int const max = (2*threshold-1) - remaining; + int count; + + if ((bitStream & (threshold-1)) < (U32)max) { + count = bitStream & (threshold-1); + bitCount += nbBits-1; + } else { + count = bitStream & (2*threshold-1); + if (count >= threshold) count -= max; + bitCount += nbBits; + } + + count--; /* extra accuracy */ + /* When it matters (small blocks), this is a + * predictable branch, because we don't use -1. + */ + if (count >= 0) { + remaining -= count; + } else { + assert(count == -1); + remaining += count; + } + normalizedCounter[charnum++] = (short)count; + previous0 = !count; + + assert(threshold > 1); + if (remaining < threshold) { + /* This branch can be folded into the + * threshold update condition because we + * know that threshold > 1. + */ + if (remaining <= 1) break; + nbBits = ZSTD_highbit32(remaining) + 1; + threshold = 1 << (nbBits - 1); + } + if (charnum >= maxSV1) break; + + if (LIKELY(ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { + ip += bitCount>>3; + bitCount &= 7; + } else { + bitCount -= (int)(8 * (iend - 4 - ip)); + bitCount &= 31; + ip = iend - 4; + } + bitStream = MEM_readLE32(ip) >> bitCount; + } } + if (remaining != 1) return ERROR(corruption_detected); + /* Only possible when there are too many zeros. */ + if (charnum > maxSV1) return ERROR(maxSymbolValue_tooSmall); + if (bitCount > 32) return ERROR(corruption_detected); + *maxSVPtr = charnum-1; + + ip += (bitCount+7)>>3; + return ip-istart; +} + +/* Avoids the FORCE_INLINE of the _body() function. */ +static size_t FSE_readNCount_body_default( + short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, + const void* headerBuffer, size_t hbSize) +{ + return FSE_readNCount_body(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); +} + +#if DYNAMIC_BMI2 +BMI2_TARGET_ATTRIBUTE static size_t FSE_readNCount_body_bmi2( + short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, + const void* headerBuffer, size_t hbSize) +{ + return FSE_readNCount_body(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); +} +#endif + +size_t FSE_readNCount_bmi2( + short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, + const void* headerBuffer, size_t hbSize, int bmi2) +{ +#if DYNAMIC_BMI2 + if (bmi2) { + return FSE_readNCount_body_bmi2(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); + } +#endif + (void)bmi2; + return FSE_readNCount_body_default(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); +} + +size_t FSE_readNCount( + short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, + const void* headerBuffer, size_t hbSize) +{ + return FSE_readNCount_bmi2(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize, /* bmi2 */ 0); +} + + +/*! HUF_readStats() : + Read compact Huffman tree, saved by HUF_writeCTable(). + `huffWeight` is destination buffer. + `rankStats` is assumed to be a table of at least HUF_TABLELOG_MAX U32. + @return : size read from `src` , or an error Code . + Note : Needed by HUF_readCTable() and HUF_readDTableX?() . +*/ +size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, + U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize) +{ + U32 wksp[HUF_READ_STATS_WORKSPACE_SIZE_U32]; + return HUF_readStats_wksp(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, wksp, sizeof(wksp), /* flags */ 0); +} + +FORCE_INLINE_TEMPLATE size_t +HUF_readStats_body(BYTE* huffWeight, size_t hwSize, U32* rankStats, + U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize, + void* workSpace, size_t wkspSize, + int bmi2) +{ + U32 weightTotal; + const BYTE* ip = (const BYTE*) src; + size_t iSize; + size_t oSize; + + if (!srcSize) return ERROR(srcSize_wrong); + iSize = ip[0]; + /* ZSTD_memset(huffWeight, 0, hwSize); *//* is not necessary, even though some analyzer complain ... */ + + if (iSize >= 128) { /* special header */ + oSize = iSize - 127; + iSize = ((oSize+1)/2); + if (iSize+1 > srcSize) return ERROR(srcSize_wrong); + if (oSize >= hwSize) return ERROR(corruption_detected); + ip += 1; + { U32 n; + for (n=0; n> 4; + huffWeight[n+1] = ip[n/2] & 15; + } } } + else { /* header compressed with FSE (normal case) */ + if (iSize+1 > srcSize) return ERROR(srcSize_wrong); + /* max (hwSize-1) values decoded, as last one is implied */ + oSize = FSE_decompress_wksp_bmi2(huffWeight, hwSize-1, ip+1, iSize, 6, workSpace, wkspSize, bmi2); + if (FSE_isError(oSize)) return oSize; + } + + /* collect weight stats */ + ZSTD_memset(rankStats, 0, (HUF_TABLELOG_MAX + 1) * sizeof(U32)); + weightTotal = 0; + { U32 n; for (n=0; n HUF_TABLELOG_MAX) return ERROR(corruption_detected); + rankStats[huffWeight[n]]++; + weightTotal += (1 << huffWeight[n]) >> 1; + } } + if (weightTotal == 0) return ERROR(corruption_detected); + + /* get last non-null symbol weight (implied, total must be 2^n) */ + { U32 const tableLog = ZSTD_highbit32(weightTotal) + 1; + if (tableLog > HUF_TABLELOG_MAX) return ERROR(corruption_detected); + *tableLogPtr = tableLog; + /* determine last weight */ + { U32 const total = 1 << tableLog; + U32 const rest = total - weightTotal; + U32 const verif = 1 << ZSTD_highbit32(rest); + U32 const lastWeight = ZSTD_highbit32(rest) + 1; + if (verif != rest) return ERROR(corruption_detected); /* last value must be a clean power of 2 */ + huffWeight[oSize] = (BYTE)lastWeight; + rankStats[lastWeight]++; + } } + + /* check tree construction validity */ + if ((rankStats[1] < 2) || (rankStats[1] & 1)) return ERROR(corruption_detected); /* by construction : at least 2 elts of rank 1, must be even */ + + /* results */ + *nbSymbolsPtr = (U32)(oSize+1); + return iSize+1; +} + +/* Avoids the FORCE_INLINE of the _body() function. */ +static size_t HUF_readStats_body_default(BYTE* huffWeight, size_t hwSize, U32* rankStats, + U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize, + void* workSpace, size_t wkspSize) +{ + return HUF_readStats_body(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize, 0); +} + +#if DYNAMIC_BMI2 +static BMI2_TARGET_ATTRIBUTE size_t HUF_readStats_body_bmi2(BYTE* huffWeight, size_t hwSize, U32* rankStats, + U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize, + void* workSpace, size_t wkspSize) +{ + return HUF_readStats_body(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize, 1); +} +#endif + +size_t HUF_readStats_wksp(BYTE* huffWeight, size_t hwSize, U32* rankStats, + U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize, + void* workSpace, size_t wkspSize, + int flags) +{ +#if DYNAMIC_BMI2 + if (flags & HUF_flags_bmi2) { + return HUF_readStats_body_bmi2(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize); + } +#endif + (void)flags; + return HUF_readStats_body_default(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize); +} diff --git a/lib/zstd/lib/common/error_private.c b/lib/zstd/lib/common/error_private.c new file mode 100644 index 0000000..075fc5e --- /dev/null +++ b/lib/zstd/lib/common/error_private.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +/* The purpose of this file is to have a single list of error strings embedded in binary */ + +#include "error_private.h" + +const char* ERR_getErrorString(ERR_enum code) +{ +#ifdef ZSTD_STRIP_ERROR_STRINGS + (void)code; + return "Error strings stripped"; +#else + static const char* const notErrorCode = "Unspecified error code"; + switch( code ) + { + case PREFIX(no_error): return "No error detected"; + case PREFIX(GENERIC): return "Error (generic)"; + case PREFIX(prefix_unknown): return "Unknown frame descriptor"; + case PREFIX(version_unsupported): return "Version not supported"; + case PREFIX(frameParameter_unsupported): return "Unsupported frame parameter"; + case PREFIX(frameParameter_windowTooLarge): return "Frame requires too much memory for decoding"; + case PREFIX(corruption_detected): return "Data corruption detected"; + case PREFIX(checksum_wrong): return "Restored data doesn't match checksum"; + case PREFIX(literals_headerWrong): return "Header of Literals' block doesn't respect format specification"; + case PREFIX(parameter_unsupported): return "Unsupported parameter"; + case PREFIX(parameter_combination_unsupported): return "Unsupported combination of parameters"; + case PREFIX(parameter_outOfBound): return "Parameter is out of bound"; + case PREFIX(init_missing): return "Context should be init first"; + case PREFIX(memory_allocation): return "Allocation error : not enough memory"; + case PREFIX(workSpace_tooSmall): return "workSpace buffer is not large enough"; + case PREFIX(stage_wrong): return "Operation not authorized at current processing stage"; + case PREFIX(tableLog_tooLarge): return "tableLog requires too much memory : unsupported"; + case PREFIX(maxSymbolValue_tooLarge): return "Unsupported max Symbol Value : too large"; + case PREFIX(maxSymbolValue_tooSmall): return "Specified maxSymbolValue is too small"; + case PREFIX(stabilityCondition_notRespected): return "pledged buffer stability condition is not respected"; + case PREFIX(dictionary_corrupted): return "Dictionary is corrupted"; + case PREFIX(dictionary_wrong): return "Dictionary mismatch"; + case PREFIX(dictionaryCreation_failed): return "Cannot create Dictionary from provided samples"; + case PREFIX(dstSize_tooSmall): return "Destination buffer is too small"; + case PREFIX(srcSize_wrong): return "Src size is incorrect"; + case PREFIX(dstBuffer_null): return "Operation on NULL destination buffer"; + case PREFIX(noForwardProgress_destFull): return "Operation made no progress over multiple calls, due to output buffer being full"; + case PREFIX(noForwardProgress_inputEmpty): return "Operation made no progress over multiple calls, due to input being empty"; + /* following error codes are not stable and may be removed or changed in a future version */ + case PREFIX(frameIndex_tooLarge): return "Frame index is too large"; + case PREFIX(seekableIO): return "An I/O error occurred when reading/seeking"; + case PREFIX(dstBuffer_wrong): return "Destination buffer is wrong"; + case PREFIX(srcBuffer_wrong): return "Source buffer is wrong"; + case PREFIX(sequenceProducer_failed): return "Block-level external sequence producer returned an error code"; + case PREFIX(externalSequences_invalid): return "External sequences are not valid"; + case PREFIX(maxCode): + default: return notErrorCode; + } +#endif +} diff --git a/lib/zstd/lib/common/error_private.h b/lib/zstd/lib/common/error_private.h new file mode 100644 index 0000000..325daad --- /dev/null +++ b/lib/zstd/lib/common/error_private.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +/* Note : this module is expected to remain private, do not expose it */ + +#ifndef ERROR_H_MODULE +#define ERROR_H_MODULE + +#if defined (__cplusplus) +extern "C" { +#endif + + +/* **************************************** +* Dependencies +******************************************/ +#include "../zstd_errors.h" /* enum list */ +#include "compiler.h" +#include "debug.h" +#include "zstd_deps.h" /* size_t */ + + +/* **************************************** +* Compiler-specific +******************************************/ +#if defined(__GNUC__) +# define ERR_STATIC static __attribute__((unused)) +#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) +# define ERR_STATIC static inline +#elif defined(_MSC_VER) +# define ERR_STATIC static __inline +#else +# define ERR_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */ +#endif + + +/*-**************************************** +* Customization (error_public.h) +******************************************/ +typedef ZSTD_ErrorCode ERR_enum; +#define PREFIX(name) ZSTD_error_##name + + +/*-**************************************** +* Error codes handling +******************************************/ +#undef ERROR /* already defined on Visual Studio */ +#define ERROR(name) ZSTD_ERROR(name) +#define ZSTD_ERROR(name) ((size_t)-PREFIX(name)) + +ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); } + +ERR_STATIC ERR_enum ERR_getErrorCode(size_t code) { if (!ERR_isError(code)) return (ERR_enum)0; return (ERR_enum) (0-code); } + +/* check and forward error code */ +#define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return e +#define CHECK_F(f) { CHECK_V_F(_var_err__, f); } + + +/*-**************************************** +* Error Strings +******************************************/ + +const char* ERR_getErrorString(ERR_enum code); /* error_private.c */ + +ERR_STATIC const char* ERR_getErrorName(size_t code) +{ + return ERR_getErrorString(ERR_getErrorCode(code)); +} + +/** + * Ignore: this is an internal helper. + * + * This is a helper function to help force C99-correctness during compilation. + * Under strict compilation modes, variadic macro arguments can't be empty. + * However, variadic function arguments can be. Using a function therefore lets + * us statically check that at least one (string) argument was passed, + * independent of the compilation flags. + */ +static INLINE_KEYWORD UNUSED_ATTR +void _force_has_format_string(const char *format, ...) { + (void)format; +} + +/** + * Ignore: this is an internal helper. + * + * We want to force this function invocation to be syntactically correct, but + * we don't want to force runtime evaluation of its arguments. + */ +#define _FORCE_HAS_FORMAT_STRING(...) \ + if (0) { \ + _force_has_format_string(__VA_ARGS__); \ + } + +#define ERR_QUOTE(str) #str + +/** + * Return the specified error if the condition evaluates to true. + * + * In debug modes, prints additional information. + * In order to do that (particularly, printing the conditional that failed), + * this can't just wrap RETURN_ERROR(). + */ +#define RETURN_ERROR_IF(cond, err, ...) \ + if (cond) { \ + RAWLOG(3, "%s:%d: ERROR!: check %s failed, returning %s", \ + __FILE__, __LINE__, ERR_QUOTE(cond), ERR_QUOTE(ERROR(err))); \ + _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ + RAWLOG(3, ": " __VA_ARGS__); \ + RAWLOG(3, "\n"); \ + return ERROR(err); \ + } + +/** + * Unconditionally return the specified error. + * + * In debug modes, prints additional information. + */ +#define RETURN_ERROR(err, ...) \ + do { \ + RAWLOG(3, "%s:%d: ERROR!: unconditional check failed, returning %s", \ + __FILE__, __LINE__, ERR_QUOTE(ERROR(err))); \ + _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ + RAWLOG(3, ": " __VA_ARGS__); \ + RAWLOG(3, "\n"); \ + return ERROR(err); \ + } while(0); + +/** + * If the provided expression evaluates to an error code, returns that error code. + * + * In debug modes, prints additional information. + */ +#define FORWARD_IF_ERROR(err, ...) \ + do { \ + size_t const err_code = (err); \ + if (ERR_isError(err_code)) { \ + RAWLOG(3, "%s:%d: ERROR!: forwarding error in %s: %s", \ + __FILE__, __LINE__, ERR_QUOTE(err), ERR_getErrorName(err_code)); \ + _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ + RAWLOG(3, ": " __VA_ARGS__); \ + RAWLOG(3, "\n"); \ + return err_code; \ + } \ + } while(0); + +#if defined (__cplusplus) +} +#endif + +#endif /* ERROR_H_MODULE */ diff --git a/lib/zstd/lib/common/fse.h b/lib/zstd/lib/common/fse.h new file mode 100644 index 0000000..02a1f0b --- /dev/null +++ b/lib/zstd/lib/common/fse.h @@ -0,0 +1,639 @@ +/* ****************************************************************** + * FSE : Finite State Entropy codec + * Public Prototypes declaration + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * You can contact the author at : + * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +****************************************************************** */ + +#if defined (__cplusplus) +extern "C" { +#endif + +#ifndef FSE_H +#define FSE_H + + +/*-***************************************** +* Dependencies +******************************************/ +#include "zstd_deps.h" /* size_t, ptrdiff_t */ + + +/*-***************************************** +* FSE_PUBLIC_API : control library symbols visibility +******************************************/ +#if defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) && defined(__GNUC__) && (__GNUC__ >= 4) +# define FSE_PUBLIC_API __attribute__ ((visibility ("default"))) +#elif defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) /* Visual expected */ +# define FSE_PUBLIC_API __declspec(dllexport) +#elif defined(FSE_DLL_IMPORT) && (FSE_DLL_IMPORT==1) +# define FSE_PUBLIC_API __declspec(dllimport) /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ +#else +# define FSE_PUBLIC_API +#endif + +/*------ Version ------*/ +#define FSE_VERSION_MAJOR 0 +#define FSE_VERSION_MINOR 9 +#define FSE_VERSION_RELEASE 0 + +#define FSE_LIB_VERSION FSE_VERSION_MAJOR.FSE_VERSION_MINOR.FSE_VERSION_RELEASE +#define FSE_QUOTE(str) #str +#define FSE_EXPAND_AND_QUOTE(str) FSE_QUOTE(str) +#define FSE_VERSION_STRING FSE_EXPAND_AND_QUOTE(FSE_LIB_VERSION) + +#define FSE_VERSION_NUMBER (FSE_VERSION_MAJOR *100*100 + FSE_VERSION_MINOR *100 + FSE_VERSION_RELEASE) +FSE_PUBLIC_API unsigned FSE_versionNumber(void); /**< library version number; to be used when checking dll version */ + + +/*-***************************************** +* Tool functions +******************************************/ +FSE_PUBLIC_API size_t FSE_compressBound(size_t size); /* maximum compressed size */ + +/* Error Management */ +FSE_PUBLIC_API unsigned FSE_isError(size_t code); /* tells if a return value is an error code */ +FSE_PUBLIC_API const char* FSE_getErrorName(size_t code); /* provides error code string (useful for debugging) */ + + +/*-***************************************** +* FSE detailed API +******************************************/ +/*! +FSE_compress() does the following: +1. count symbol occurrence from source[] into table count[] (see hist.h) +2. normalize counters so that sum(count[]) == Power_of_2 (2^tableLog) +3. save normalized counters to memory buffer using writeNCount() +4. build encoding table 'CTable' from normalized counters +5. encode the data stream using encoding table 'CTable' + +FSE_decompress() does the following: +1. read normalized counters with readNCount() +2. build decoding table 'DTable' from normalized counters +3. decode the data stream using decoding table 'DTable' + +The following API allows targeting specific sub-functions for advanced tasks. +For example, it's possible to compress several blocks using the same 'CTable', +or to save and provide normalized distribution using external method. +*/ + +/* *** COMPRESSION *** */ + +/*! FSE_optimalTableLog(): + dynamically downsize 'tableLog' when conditions are met. + It saves CPU time, by using smaller tables, while preserving or even improving compression ratio. + @return : recommended tableLog (necessarily <= 'maxTableLog') */ +FSE_PUBLIC_API unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue); + +/*! FSE_normalizeCount(): + normalize counts so that sum(count[]) == Power_of_2 (2^tableLog) + 'normalizedCounter' is a table of short, of minimum size (maxSymbolValue+1). + useLowProbCount is a boolean parameter which trades off compressed size for + faster header decoding. When it is set to 1, the compressed data will be slightly + smaller. And when it is set to 0, FSE_readNCount() and FSE_buildDTable() will be + faster. If you are compressing a small amount of data (< 2 KB) then useLowProbCount=0 + is a good default, since header deserialization makes a big speed difference. + Otherwise, useLowProbCount=1 is a good default, since the speed difference is small. + @return : tableLog, + or an errorCode, which can be tested using FSE_isError() */ +FSE_PUBLIC_API size_t FSE_normalizeCount(short* normalizedCounter, unsigned tableLog, + const unsigned* count, size_t srcSize, unsigned maxSymbolValue, unsigned useLowProbCount); + +/*! FSE_NCountWriteBound(): + Provides the maximum possible size of an FSE normalized table, given 'maxSymbolValue' and 'tableLog'. + Typically useful for allocation purpose. */ +FSE_PUBLIC_API size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog); + +/*! FSE_writeNCount(): + Compactly save 'normalizedCounter' into 'buffer'. + @return : size of the compressed table, + or an errorCode, which can be tested using FSE_isError(). */ +FSE_PUBLIC_API size_t FSE_writeNCount (void* buffer, size_t bufferSize, + const short* normalizedCounter, + unsigned maxSymbolValue, unsigned tableLog); + +/*! Constructor and Destructor of FSE_CTable. + Note that FSE_CTable size depends on 'tableLog' and 'maxSymbolValue' */ +typedef unsigned FSE_CTable; /* don't allocate that. It's only meant to be more restrictive than void* */ + +/*! FSE_buildCTable(): + Builds `ct`, which must be already allocated, using FSE_createCTable(). + @return : 0, or an errorCode, which can be tested using FSE_isError() */ +FSE_PUBLIC_API size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog); + +/*! FSE_compress_usingCTable(): + Compress `src` using `ct` into `dst` which must be already allocated. + @return : size of compressed data (<= `dstCapacity`), + or 0 if compressed data could not fit into `dst`, + or an errorCode, which can be tested using FSE_isError() */ +FSE_PUBLIC_API size_t FSE_compress_usingCTable (void* dst, size_t dstCapacity, const void* src, size_t srcSize, const FSE_CTable* ct); + +/*! +Tutorial : +---------- +The first step is to count all symbols. FSE_count() does this job very fast. +Result will be saved into 'count', a table of unsigned int, which must be already allocated, and have 'maxSymbolValuePtr[0]+1' cells. +'src' is a table of bytes of size 'srcSize'. All values within 'src' MUST be <= maxSymbolValuePtr[0] +maxSymbolValuePtr[0] will be updated, with its real value (necessarily <= original value) +FSE_count() will return the number of occurrence of the most frequent symbol. +This can be used to know if there is a single symbol within 'src', and to quickly evaluate its compressibility. +If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()). + +The next step is to normalize the frequencies. +FSE_normalizeCount() will ensure that sum of frequencies is == 2 ^'tableLog'. +It also guarantees a minimum of 1 to any Symbol with frequency >= 1. +You can use 'tableLog'==0 to mean "use default tableLog value". +If you are unsure of which tableLog value to use, you can ask FSE_optimalTableLog(), +which will provide the optimal valid tableLog given sourceSize, maxSymbolValue, and a user-defined maximum (0 means "default"). + +The result of FSE_normalizeCount() will be saved into a table, +called 'normalizedCounter', which is a table of signed short. +'normalizedCounter' must be already allocated, and have at least 'maxSymbolValue+1' cells. +The return value is tableLog if everything proceeded as expected. +It is 0 if there is a single symbol within distribution. +If there is an error (ex: invalid tableLog value), the function will return an ErrorCode (which can be tested using FSE_isError()). + +'normalizedCounter' can be saved in a compact manner to a memory area using FSE_writeNCount(). +'buffer' must be already allocated. +For guaranteed success, buffer size must be at least FSE_headerBound(). +The result of the function is the number of bytes written into 'buffer'. +If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError(); ex : buffer size too small). + +'normalizedCounter' can then be used to create the compression table 'CTable'. +The space required by 'CTable' must be already allocated, using FSE_createCTable(). +You can then use FSE_buildCTable() to fill 'CTable'. +If there is an error, both functions will return an ErrorCode (which can be tested using FSE_isError()). + +'CTable' can then be used to compress 'src', with FSE_compress_usingCTable(). +Similar to FSE_count(), the convention is that 'src' is assumed to be a table of char of size 'srcSize' +The function returns the size of compressed data (without header), necessarily <= `dstCapacity`. +If it returns '0', compressed data could not fit into 'dst'. +If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()). +*/ + + +/* *** DECOMPRESSION *** */ + +/*! FSE_readNCount(): + Read compactly saved 'normalizedCounter' from 'rBuffer'. + @return : size read from 'rBuffer', + or an errorCode, which can be tested using FSE_isError(). + maxSymbolValuePtr[0] and tableLogPtr[0] will also be updated with their respective values */ +FSE_PUBLIC_API size_t FSE_readNCount (short* normalizedCounter, + unsigned* maxSymbolValuePtr, unsigned* tableLogPtr, + const void* rBuffer, size_t rBuffSize); + +/*! FSE_readNCount_bmi2(): + * Same as FSE_readNCount() but pass bmi2=1 when your CPU supports BMI2 and 0 otherwise. + */ +FSE_PUBLIC_API size_t FSE_readNCount_bmi2(short* normalizedCounter, + unsigned* maxSymbolValuePtr, unsigned* tableLogPtr, + const void* rBuffer, size_t rBuffSize, int bmi2); + +typedef unsigned FSE_DTable; /* don't allocate that. It's just a way to be more restrictive than void* */ + +/*! +Tutorial : +---------- +(Note : these functions only decompress FSE-compressed blocks. + If block is uncompressed, use memcpy() instead + If block is a single repeated byte, use memset() instead ) + +The first step is to obtain the normalized frequencies of symbols. +This can be performed by FSE_readNCount() if it was saved using FSE_writeNCount(). +'normalizedCounter' must be already allocated, and have at least 'maxSymbolValuePtr[0]+1' cells of signed short. +In practice, that means it's necessary to know 'maxSymbolValue' beforehand, +or size the table to handle worst case situations (typically 256). +FSE_readNCount() will provide 'tableLog' and 'maxSymbolValue'. +The result of FSE_readNCount() is the number of bytes read from 'rBuffer'. +Note that 'rBufferSize' must be at least 4 bytes, even if useful information is less than that. +If there is an error, the function will return an error code, which can be tested using FSE_isError(). + +The next step is to build the decompression tables 'FSE_DTable' from 'normalizedCounter'. +This is performed by the function FSE_buildDTable(). +The space required by 'FSE_DTable' must be already allocated using FSE_createDTable(). +If there is an error, the function will return an error code, which can be tested using FSE_isError(). + +`FSE_DTable` can then be used to decompress `cSrc`, with FSE_decompress_usingDTable(). +`cSrcSize` must be strictly correct, otherwise decompression will fail. +FSE_decompress_usingDTable() result will tell how many bytes were regenerated (<=`dstCapacity`). +If there is an error, the function will return an error code, which can be tested using FSE_isError(). (ex: dst buffer too small) +*/ + +#endif /* FSE_H */ + +#if defined(FSE_STATIC_LINKING_ONLY) && !defined(FSE_H_FSE_STATIC_LINKING_ONLY) +#define FSE_H_FSE_STATIC_LINKING_ONLY + +/* *** Dependency *** */ +#include "bitstream.h" + + +/* ***************************************** +* Static allocation +*******************************************/ +/* FSE buffer bounds */ +#define FSE_NCOUNTBOUND 512 +#define FSE_BLOCKBOUND(size) ((size) + ((size)>>7) + 4 /* fse states */ + sizeof(size_t) /* bitContainer */) +#define FSE_COMPRESSBOUND(size) (FSE_NCOUNTBOUND + FSE_BLOCKBOUND(size)) /* Macro version, useful for static allocation */ + +/* It is possible to statically allocate FSE CTable/DTable as a table of FSE_CTable/FSE_DTable using below macros */ +#define FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) (1 + (1<<((maxTableLog)-1)) + (((maxSymbolValue)+1)*2)) +#define FSE_DTABLE_SIZE_U32(maxTableLog) (1 + (1<<(maxTableLog))) + +/* or use the size to malloc() space directly. Pay attention to alignment restrictions though */ +#define FSE_CTABLE_SIZE(maxTableLog, maxSymbolValue) (FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) * sizeof(FSE_CTable)) +#define FSE_DTABLE_SIZE(maxTableLog) (FSE_DTABLE_SIZE_U32(maxTableLog) * sizeof(FSE_DTable)) + + +/* ***************************************** + * FSE advanced API + ***************************************** */ + +unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus); +/**< same as FSE_optimalTableLog(), which used `minus==2` */ + +size_t FSE_buildCTable_rle (FSE_CTable* ct, unsigned char symbolValue); +/**< build a fake FSE_CTable, designed to compress always the same symbolValue */ + +/* FSE_buildCTable_wksp() : + * Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`). + * `wkspSize` must be >= `FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog)` of `unsigned`. + * See FSE_buildCTable_wksp() for breakdown of workspace usage. + */ +#define FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog) (((maxSymbolValue + 2) + (1ull << (tableLog)))/2 + sizeof(U64)/sizeof(U32) /* additional 8 bytes for potential table overwrite */) +#define FSE_BUILD_CTABLE_WORKSPACE_SIZE(maxSymbolValue, tableLog) (sizeof(unsigned) * FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog)) +size_t FSE_buildCTable_wksp(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); + +#define FSE_BUILD_DTABLE_WKSP_SIZE(maxTableLog, maxSymbolValue) (sizeof(short) * (maxSymbolValue + 1) + (1ULL << maxTableLog) + 8) +#define FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) ((FSE_BUILD_DTABLE_WKSP_SIZE(maxTableLog, maxSymbolValue) + sizeof(unsigned) - 1) / sizeof(unsigned)) +FSE_PUBLIC_API size_t FSE_buildDTable_wksp(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); +/**< Same as FSE_buildDTable(), using an externally allocated `workspace` produced with `FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxSymbolValue)` */ + +#define FSE_DECOMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) (FSE_DTABLE_SIZE_U32(maxTableLog) + 1 + FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) + (FSE_MAX_SYMBOL_VALUE + 1) / 2 + 1) +#define FSE_DECOMPRESS_WKSP_SIZE(maxTableLog, maxSymbolValue) (FSE_DECOMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) * sizeof(unsigned)) +size_t FSE_decompress_wksp_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize, int bmi2); +/**< same as FSE_decompress(), using an externally allocated `workSpace` produced with `FSE_DECOMPRESS_WKSP_SIZE_U32(maxLog, maxSymbolValue)`. + * Set bmi2 to 1 if your CPU supports BMI2 or 0 if it doesn't */ + +typedef enum { + FSE_repeat_none, /**< Cannot use the previous table */ + FSE_repeat_check, /**< Can use the previous table but it must be checked */ + FSE_repeat_valid /**< Can use the previous table and it is assumed to be valid */ + } FSE_repeat; + +/* ***************************************** +* FSE symbol compression API +*******************************************/ +/*! + This API consists of small unitary functions, which highly benefit from being inlined. + Hence their body are included in next section. +*/ +typedef struct { + ptrdiff_t value; + const void* stateTable; + const void* symbolTT; + unsigned stateLog; +} FSE_CState_t; + +static void FSE_initCState(FSE_CState_t* CStatePtr, const FSE_CTable* ct); + +static void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* CStatePtr, unsigned symbol); + +static void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* CStatePtr); + +/**< +These functions are inner components of FSE_compress_usingCTable(). +They allow the creation of custom streams, mixing multiple tables and bit sources. + +A key property to keep in mind is that encoding and decoding are done **in reverse direction**. +So the first symbol you will encode is the last you will decode, like a LIFO stack. + +You will need a few variables to track your CStream. They are : + +FSE_CTable ct; // Provided by FSE_buildCTable() +BIT_CStream_t bitStream; // bitStream tracking structure +FSE_CState_t state; // State tracking structure (can have several) + + +The first thing to do is to init bitStream and state. + size_t errorCode = BIT_initCStream(&bitStream, dstBuffer, maxDstSize); + FSE_initCState(&state, ct); + +Note that BIT_initCStream() can produce an error code, so its result should be tested, using FSE_isError(); +You can then encode your input data, byte after byte. +FSE_encodeSymbol() outputs a maximum of 'tableLog' bits at a time. +Remember decoding will be done in reverse direction. + FSE_encodeByte(&bitStream, &state, symbol); + +At any time, you can also add any bit sequence. +Note : maximum allowed nbBits is 25, for compatibility with 32-bits decoders + BIT_addBits(&bitStream, bitField, nbBits); + +The above methods don't commit data to memory, they just store it into local register, for speed. +Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t). +Writing data to memory is a manual operation, performed by the flushBits function. + BIT_flushBits(&bitStream); + +Your last FSE encoding operation shall be to flush your last state value(s). + FSE_flushState(&bitStream, &state); + +Finally, you must close the bitStream. +The function returns the size of CStream in bytes. +If data couldn't fit into dstBuffer, it will return a 0 ( == not compressible) +If there is an error, it returns an errorCode (which can be tested using FSE_isError()). + size_t size = BIT_closeCStream(&bitStream); +*/ + + +/* ***************************************** +* FSE symbol decompression API +*******************************************/ +typedef struct { + size_t state; + const void* table; /* precise table may vary, depending on U16 */ +} FSE_DState_t; + + +static void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt); + +static unsigned char FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD); + +static unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr); + +/**< +Let's now decompose FSE_decompress_usingDTable() into its unitary components. +You will decode FSE-encoded symbols from the bitStream, +and also any other bitFields you put in, **in reverse order**. + +You will need a few variables to track your bitStream. They are : + +BIT_DStream_t DStream; // Stream context +FSE_DState_t DState; // State context. Multiple ones are possible +FSE_DTable* DTablePtr; // Decoding table, provided by FSE_buildDTable() + +The first thing to do is to init the bitStream. + errorCode = BIT_initDStream(&DStream, srcBuffer, srcSize); + +You should then retrieve your initial state(s) +(in reverse flushing order if you have several ones) : + errorCode = FSE_initDState(&DState, &DStream, DTablePtr); + +You can then decode your data, symbol after symbol. +For information the maximum number of bits read by FSE_decodeSymbol() is 'tableLog'. +Keep in mind that symbols are decoded in reverse order, like a LIFO stack (last in, first out). + unsigned char symbol = FSE_decodeSymbol(&DState, &DStream); + +You can retrieve any bitfield you eventually stored into the bitStream (in reverse order) +Note : maximum allowed nbBits is 25, for 32-bits compatibility + size_t bitField = BIT_readBits(&DStream, nbBits); + +All above operations only read from local register (which size depends on size_t). +Refueling the register from memory is manually performed by the reload method. + endSignal = FSE_reloadDStream(&DStream); + +BIT_reloadDStream() result tells if there is still some more data to read from DStream. +BIT_DStream_unfinished : there is still some data left into the DStream. +BIT_DStream_endOfBuffer : Dstream reached end of buffer. Its container may no longer be completely filled. +BIT_DStream_completed : Dstream reached its exact end, corresponding in general to decompression completed. +BIT_DStream_tooFar : Dstream went too far. Decompression result is corrupted. + +When reaching end of buffer (BIT_DStream_endOfBuffer), progress slowly, notably if you decode multiple symbols per loop, +to properly detect the exact end of stream. +After each decoded symbol, check if DStream is fully consumed using this simple test : + BIT_reloadDStream(&DStream) >= BIT_DStream_completed + +When it's done, verify decompression is fully completed, by checking both DStream and the relevant states. +Checking if DStream has reached its end is performed by : + BIT_endOfDStream(&DStream); +Check also the states. There might be some symbols left there, if some high probability ones (>50%) are possible. + FSE_endOfDState(&DState); +*/ + + +/* ***************************************** +* FSE unsafe API +*******************************************/ +static unsigned char FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD); +/* faster, but works only if nbBits is always >= 1 (otherwise, result will be corrupted) */ + + +/* ***************************************** +* Implementation of inlined functions +*******************************************/ +typedef struct { + int deltaFindState; + U32 deltaNbBits; +} FSE_symbolCompressionTransform; /* total 8 bytes */ + +MEM_STATIC void FSE_initCState(FSE_CState_t* statePtr, const FSE_CTable* ct) +{ + const void* ptr = ct; + const U16* u16ptr = (const U16*) ptr; + const U32 tableLog = MEM_read16(ptr); + statePtr->value = (ptrdiff_t)1<stateTable = u16ptr+2; + statePtr->symbolTT = ct + 1 + (tableLog ? (1<<(tableLog-1)) : 1); + statePtr->stateLog = tableLog; +} + + +/*! FSE_initCState2() : +* Same as FSE_initCState(), but the first symbol to include (which will be the last to be read) +* uses the smallest state value possible, saving the cost of this symbol */ +MEM_STATIC void FSE_initCState2(FSE_CState_t* statePtr, const FSE_CTable* ct, U32 symbol) +{ + FSE_initCState(statePtr, ct); + { const FSE_symbolCompressionTransform symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol]; + const U16* stateTable = (const U16*)(statePtr->stateTable); + U32 nbBitsOut = (U32)((symbolTT.deltaNbBits + (1<<15)) >> 16); + statePtr->value = (nbBitsOut << 16) - symbolTT.deltaNbBits; + statePtr->value = stateTable[(statePtr->value >> nbBitsOut) + symbolTT.deltaFindState]; + } +} + +MEM_STATIC void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* statePtr, unsigned symbol) +{ + FSE_symbolCompressionTransform const symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol]; + const U16* const stateTable = (const U16*)(statePtr->stateTable); + U32 const nbBitsOut = (U32)((statePtr->value + symbolTT.deltaNbBits) >> 16); + BIT_addBits(bitC, statePtr->value, nbBitsOut); + statePtr->value = stateTable[ (statePtr->value >> nbBitsOut) + symbolTT.deltaFindState]; +} + +MEM_STATIC void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* statePtr) +{ + BIT_addBits(bitC, statePtr->value, statePtr->stateLog); + BIT_flushBits(bitC); +} + + +/* FSE_getMaxNbBits() : + * Approximate maximum cost of a symbol, in bits. + * Fractional get rounded up (i.e. a symbol with a normalized frequency of 3 gives the same result as a frequency of 2) + * note 1 : assume symbolValue is valid (<= maxSymbolValue) + * note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */ +MEM_STATIC U32 FSE_getMaxNbBits(const void* symbolTTPtr, U32 symbolValue) +{ + const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr; + return (symbolTT[symbolValue].deltaNbBits + ((1<<16)-1)) >> 16; +} + +/* FSE_bitCost() : + * Approximate symbol cost, as fractional value, using fixed-point format (accuracyLog fractional bits) + * note 1 : assume symbolValue is valid (<= maxSymbolValue) + * note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */ +MEM_STATIC U32 FSE_bitCost(const void* symbolTTPtr, U32 tableLog, U32 symbolValue, U32 accuracyLog) +{ + const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr; + U32 const minNbBits = symbolTT[symbolValue].deltaNbBits >> 16; + U32 const threshold = (minNbBits+1) << 16; + assert(tableLog < 16); + assert(accuracyLog < 31-tableLog); /* ensure enough room for renormalization double shift */ + { U32 const tableSize = 1 << tableLog; + U32 const deltaFromThreshold = threshold - (symbolTT[symbolValue].deltaNbBits + tableSize); + U32 const normalizedDeltaFromThreshold = (deltaFromThreshold << accuracyLog) >> tableLog; /* linear interpolation (very approximate) */ + U32 const bitMultiplier = 1 << accuracyLog; + assert(symbolTT[symbolValue].deltaNbBits + tableSize <= threshold); + assert(normalizedDeltaFromThreshold <= bitMultiplier); + return (minNbBits+1)*bitMultiplier - normalizedDeltaFromThreshold; + } +} + + +/* ====== Decompression ====== */ + +typedef struct { + U16 tableLog; + U16 fastMode; +} FSE_DTableHeader; /* sizeof U32 */ + +typedef struct +{ + unsigned short newState; + unsigned char symbol; + unsigned char nbBits; +} FSE_decode_t; /* size == U32 */ + +MEM_STATIC void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt) +{ + const void* ptr = dt; + const FSE_DTableHeader* const DTableH = (const FSE_DTableHeader*)ptr; + DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog); + BIT_reloadDStream(bitD); + DStatePtr->table = dt + 1; +} + +MEM_STATIC BYTE FSE_peekSymbol(const FSE_DState_t* DStatePtr) +{ + FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; + return DInfo.symbol; +} + +MEM_STATIC void FSE_updateState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD) +{ + FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; + U32 const nbBits = DInfo.nbBits; + size_t const lowBits = BIT_readBits(bitD, nbBits); + DStatePtr->state = DInfo.newState + lowBits; +} + +MEM_STATIC BYTE FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD) +{ + FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; + U32 const nbBits = DInfo.nbBits; + BYTE const symbol = DInfo.symbol; + size_t const lowBits = BIT_readBits(bitD, nbBits); + + DStatePtr->state = DInfo.newState + lowBits; + return symbol; +} + +/*! FSE_decodeSymbolFast() : + unsafe, only works if no symbol has a probability > 50% */ +MEM_STATIC BYTE FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD) +{ + FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; + U32 const nbBits = DInfo.nbBits; + BYTE const symbol = DInfo.symbol; + size_t const lowBits = BIT_readBitsFast(bitD, nbBits); + + DStatePtr->state = DInfo.newState + lowBits; + return symbol; +} + +MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr) +{ + return DStatePtr->state == 0; +} + + + +#ifndef FSE_COMMONDEFS_ONLY + +/* ************************************************************** +* Tuning parameters +****************************************************************/ +/*!MEMORY_USAGE : +* Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) +* Increasing memory usage improves compression ratio +* Reduced memory usage can improve speed, due to cache effect +* Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */ +#ifndef FSE_MAX_MEMORY_USAGE +# define FSE_MAX_MEMORY_USAGE 14 +#endif +#ifndef FSE_DEFAULT_MEMORY_USAGE +# define FSE_DEFAULT_MEMORY_USAGE 13 +#endif +#if (FSE_DEFAULT_MEMORY_USAGE > FSE_MAX_MEMORY_USAGE) +# error "FSE_DEFAULT_MEMORY_USAGE must be <= FSE_MAX_MEMORY_USAGE" +#endif + +/*!FSE_MAX_SYMBOL_VALUE : +* Maximum symbol value authorized. +* Required for proper stack allocation */ +#ifndef FSE_MAX_SYMBOL_VALUE +# define FSE_MAX_SYMBOL_VALUE 255 +#endif + +/* ************************************************************** +* template functions type & suffix +****************************************************************/ +#define FSE_FUNCTION_TYPE BYTE +#define FSE_FUNCTION_EXTENSION +#define FSE_DECODE_TYPE FSE_decode_t + + +#endif /* !FSE_COMMONDEFS_ONLY */ + + +/* *************************************************************** +* Constants +*****************************************************************/ +#define FSE_MAX_TABLELOG (FSE_MAX_MEMORY_USAGE-2) +#define FSE_MAX_TABLESIZE (1U< FSE_TABLELOG_ABSOLUTE_MAX +# error "FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX is not supported" +#endif + +#define FSE_TABLESTEP(tableSize) (((tableSize)>>1) + ((tableSize)>>3) + 3) + + +#endif /* FSE_STATIC_LINKING_ONLY */ + + +#if defined (__cplusplus) +} +#endif diff --git a/lib/zstd/lib/common/fse_decompress.c b/lib/zstd/lib/common/fse_decompress.c new file mode 100644 index 0000000..1e1c9f9 --- /dev/null +++ b/lib/zstd/lib/common/fse_decompress.c @@ -0,0 +1,311 @@ +/* ****************************************************************** + * FSE : Finite State Entropy decoder + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * You can contact the author at : + * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy + * - Public forum : https://groups.google.com/forum/#!forum/lz4c + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +****************************************************************** */ + + +/* ************************************************************** +* Includes +****************************************************************/ +#include "debug.h" /* assert */ +#include "bitstream.h" +#include "compiler.h" +#define FSE_STATIC_LINKING_ONLY +#include "fse.h" +#include "error_private.h" +#define ZSTD_DEPS_NEED_MALLOC +#include "zstd_deps.h" +#include "bits.h" /* ZSTD_highbit32 */ + + +/* ************************************************************** +* Error Management +****************************************************************/ +#define FSE_isError ERR_isError +#define FSE_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) /* use only *after* variable declarations */ + + +/* ************************************************************** +* Templates +****************************************************************/ +/* + designed to be included + for type-specific functions (template emulation in C) + Objective is to write these functions only once, for improved maintenance +*/ + +/* safety checks */ +#ifndef FSE_FUNCTION_EXTENSION +# error "FSE_FUNCTION_EXTENSION must be defined" +#endif +#ifndef FSE_FUNCTION_TYPE +# error "FSE_FUNCTION_TYPE must be defined" +#endif + +/* Function names */ +#define FSE_CAT(X,Y) X##Y +#define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y) +#define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y) + +static size_t FSE_buildDTable_internal(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize) +{ + void* const tdPtr = dt+1; /* because *dt is unsigned, 32-bits aligned on 32-bits */ + FSE_DECODE_TYPE* const tableDecode = (FSE_DECODE_TYPE*) (tdPtr); + U16* symbolNext = (U16*)workSpace; + BYTE* spread = (BYTE*)(symbolNext + maxSymbolValue + 1); + + U32 const maxSV1 = maxSymbolValue + 1; + U32 const tableSize = 1 << tableLog; + U32 highThreshold = tableSize-1; + + /* Sanity Checks */ + if (FSE_BUILD_DTABLE_WKSP_SIZE(tableLog, maxSymbolValue) > wkspSize) return ERROR(maxSymbolValue_tooLarge); + if (maxSymbolValue > FSE_MAX_SYMBOL_VALUE) return ERROR(maxSymbolValue_tooLarge); + if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); + + /* Init, lay down lowprob symbols */ + { FSE_DTableHeader DTableH; + DTableH.tableLog = (U16)tableLog; + DTableH.fastMode = 1; + { S16 const largeLimit= (S16)(1 << (tableLog-1)); + U32 s; + for (s=0; s= largeLimit) DTableH.fastMode=0; + symbolNext[s] = normalizedCounter[s]; + } } } + ZSTD_memcpy(dt, &DTableH, sizeof(DTableH)); + } + + /* Spread symbols */ + if (highThreshold == tableSize - 1) { + size_t const tableMask = tableSize-1; + size_t const step = FSE_TABLESTEP(tableSize); + /* First lay down the symbols in order. + * We use a uint64_t to lay down 8 bytes at a time. This reduces branch + * misses since small blocks generally have small table logs, so nearly + * all symbols have counts <= 8. We ensure we have 8 bytes at the end of + * our buffer to handle the over-write. + */ + { + U64 const add = 0x0101010101010101ull; + size_t pos = 0; + U64 sv = 0; + U32 s; + for (s=0; s highThreshold) position = (position + step) & tableMask; /* lowprob area */ + } } + if (position!=0) return ERROR(GENERIC); /* position must reach all cells once, otherwise normalizedCounter is incorrect */ + } + + /* Build Decoding table */ + { U32 u; + for (u=0; u sizeof(bitD.bitContainer)*8) /* This test must be static */ + BIT_reloadDStream(&bitD); + + op[1] = FSE_GETSYMBOL(&state2); + + if (FSE_MAX_TABLELOG*4+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */ + { if (BIT_reloadDStream(&bitD) > BIT_DStream_unfinished) { op+=2; break; } } + + op[2] = FSE_GETSYMBOL(&state1); + + if (FSE_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */ + BIT_reloadDStream(&bitD); + + op[3] = FSE_GETSYMBOL(&state2); + } + + /* tail */ + /* note : BIT_reloadDStream(&bitD) >= FSE_DStream_partiallyFilled; Ends at exactly BIT_DStream_completed */ + while (1) { + if (op>(omax-2)) return ERROR(dstSize_tooSmall); + *op++ = FSE_GETSYMBOL(&state1); + if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) { + *op++ = FSE_GETSYMBOL(&state2); + break; + } + + if (op>(omax-2)) return ERROR(dstSize_tooSmall); + *op++ = FSE_GETSYMBOL(&state2); + if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) { + *op++ = FSE_GETSYMBOL(&state1); + break; + } } + + return op-ostart; +} + +typedef struct { + short ncount[FSE_MAX_SYMBOL_VALUE + 1]; + FSE_DTable dtable[1]; /* Dynamically sized */ +} FSE_DecompressWksp; + + +FORCE_INLINE_TEMPLATE size_t FSE_decompress_wksp_body( + void* dst, size_t dstCapacity, + const void* cSrc, size_t cSrcSize, + unsigned maxLog, void* workSpace, size_t wkspSize, + int bmi2) +{ + const BYTE* const istart = (const BYTE*)cSrc; + const BYTE* ip = istart; + unsigned tableLog; + unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE; + FSE_DecompressWksp* const wksp = (FSE_DecompressWksp*)workSpace; + + DEBUG_STATIC_ASSERT((FSE_MAX_SYMBOL_VALUE + 1) % 2 == 0); + if (wkspSize < sizeof(*wksp)) return ERROR(GENERIC); + + /* normal FSE decoding mode */ + { + size_t const NCountLength = FSE_readNCount_bmi2(wksp->ncount, &maxSymbolValue, &tableLog, istart, cSrcSize, bmi2); + if (FSE_isError(NCountLength)) return NCountLength; + if (tableLog > maxLog) return ERROR(tableLog_tooLarge); + assert(NCountLength <= cSrcSize); + ip += NCountLength; + cSrcSize -= NCountLength; + } + + if (FSE_DECOMPRESS_WKSP_SIZE(tableLog, maxSymbolValue) > wkspSize) return ERROR(tableLog_tooLarge); + assert(sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog) <= wkspSize); + workSpace = (BYTE*)workSpace + sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog); + wkspSize -= sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog); + + CHECK_F( FSE_buildDTable_internal(wksp->dtable, wksp->ncount, maxSymbolValue, tableLog, workSpace, wkspSize) ); + + { + const void* ptr = wksp->dtable; + const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr; + const U32 fastMode = DTableH->fastMode; + + /* select fast mode (static) */ + if (fastMode) return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, wksp->dtable, 1); + return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, wksp->dtable, 0); + } +} + +/* Avoids the FORCE_INLINE of the _body() function. */ +static size_t FSE_decompress_wksp_body_default(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize) +{ + return FSE_decompress_wksp_body(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, 0); +} + +#if DYNAMIC_BMI2 +BMI2_TARGET_ATTRIBUTE static size_t FSE_decompress_wksp_body_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize) +{ + return FSE_decompress_wksp_body(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, 1); +} +#endif + +size_t FSE_decompress_wksp_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize, int bmi2) +{ +#if DYNAMIC_BMI2 + if (bmi2) { + return FSE_decompress_wksp_body_bmi2(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize); + } +#endif + (void)bmi2; + return FSE_decompress_wksp_body_default(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize); +} + +#endif /* FSE_COMMONDEFS_ONLY */ diff --git a/lib/zstd/lib/common/huf.h b/lib/zstd/lib/common/huf.h new file mode 100644 index 0000000..73d1ee5 --- /dev/null +++ b/lib/zstd/lib/common/huf.h @@ -0,0 +1,273 @@ +/* ****************************************************************** + * huff0 huffman codec, + * part of Finite State Entropy library + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * You can contact the author at : + * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +****************************************************************** */ + +#if defined (__cplusplus) +extern "C" { +#endif + +#ifndef HUF_H_298734234 +#define HUF_H_298734234 + +/* *** Dependencies *** */ +#include "zstd_deps.h" /* size_t */ +#include "mem.h" /* U32 */ +#define FSE_STATIC_LINKING_ONLY +#include "fse.h" + + +/* *** Tool functions *** */ +#define HUF_BLOCKSIZE_MAX (128 * 1024) /**< maximum input size for a single block compressed with HUF_compress */ +size_t HUF_compressBound(size_t size); /**< maximum compressed size (worst case) */ + +/* Error Management */ +unsigned HUF_isError(size_t code); /**< tells if a return value is an error code */ +const char* HUF_getErrorName(size_t code); /**< provides error code string (useful for debugging) */ + + +#define HUF_WORKSPACE_SIZE ((8 << 10) + 512 /* sorting scratch space */) +#define HUF_WORKSPACE_SIZE_U64 (HUF_WORKSPACE_SIZE / sizeof(U64)) + +/* *** Constants *** */ +#define HUF_TABLELOG_MAX 12 /* max runtime value of tableLog (due to static allocation); can be modified up to HUF_TABLELOG_ABSOLUTEMAX */ +#define HUF_TABLELOG_DEFAULT 11 /* default tableLog value when none specified */ +#define HUF_SYMBOLVALUE_MAX 255 + +#define HUF_TABLELOG_ABSOLUTEMAX 12 /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */ +#if (HUF_TABLELOG_MAX > HUF_TABLELOG_ABSOLUTEMAX) +# error "HUF_TABLELOG_MAX is too large !" +#endif + + +/* **************************************** +* Static allocation +******************************************/ +/* HUF buffer bounds */ +#define HUF_CTABLEBOUND 129 +#define HUF_BLOCKBOUND(size) (size + (size>>8) + 8) /* only true when incompressible is pre-filtered with fast heuristic */ +#define HUF_COMPRESSBOUND(size) (HUF_CTABLEBOUND + HUF_BLOCKBOUND(size)) /* Macro version, useful for static allocation */ + +/* static allocation of HUF's Compression Table */ +/* this is a private definition, just exposed for allocation and strict aliasing purpose. never EVER access its members directly */ +typedef size_t HUF_CElt; /* consider it an incomplete type */ +#define HUF_CTABLE_SIZE_ST(maxSymbolValue) ((maxSymbolValue)+2) /* Use tables of size_t, for proper alignment */ +#define HUF_CTABLE_SIZE(maxSymbolValue) (HUF_CTABLE_SIZE_ST(maxSymbolValue) * sizeof(size_t)) +#define HUF_CREATE_STATIC_CTABLE(name, maxSymbolValue) \ + HUF_CElt name[HUF_CTABLE_SIZE_ST(maxSymbolValue)] /* no final ; */ + +/* static allocation of HUF's DTable */ +typedef U32 HUF_DTable; +#define HUF_DTABLE_SIZE(maxTableLog) (1 + (1<<(maxTableLog))) +#define HUF_CREATE_STATIC_DTABLEX1(DTable, maxTableLog) \ + HUF_DTable DTable[HUF_DTABLE_SIZE((maxTableLog)-1)] = { ((U32)((maxTableLog)-1) * 0x01000001) } +#define HUF_CREATE_STATIC_DTABLEX2(DTable, maxTableLog) \ + HUF_DTable DTable[HUF_DTABLE_SIZE(maxTableLog)] = { ((U32)(maxTableLog) * 0x01000001) } + + +/* **************************************** +* Advanced decompression functions +******************************************/ + +/** + * Huffman flags bitset. + * For all flags, 0 is the default value. + */ +typedef enum { + /** + * If compiled with DYNAMIC_BMI2: Set flag only if the CPU supports BMI2 at runtime. + * Otherwise: Ignored. + */ + HUF_flags_bmi2 = (1 << 0), + /** + * If set: Test possible table depths to find the one that produces the smallest header + encoded size. + * If unset: Use heuristic to find the table depth. + */ + HUF_flags_optimalDepth = (1 << 1), + /** + * If set: If the previous table can encode the input, always reuse the previous table. + * If unset: If the previous table can encode the input, reuse the previous table if it results in a smaller output. + */ + HUF_flags_preferRepeat = (1 << 2), + /** + * If set: Sample the input and check if the sample is uncompressible, if it is then don't attempt to compress. + * If unset: Always histogram the entire input. + */ + HUF_flags_suspectUncompressible = (1 << 3), + /** + * If set: Don't use assembly implementations + * If unset: Allow using assembly implementations + */ + HUF_flags_disableAsm = (1 << 4), + /** + * If set: Don't use the fast decoding loop, always use the fallback decoding loop. + * If unset: Use the fast decoding loop when possible. + */ + HUF_flags_disableFast = (1 << 5) +} HUF_flags_e; + + +/* **************************************** + * HUF detailed API + * ****************************************/ +#define HUF_OPTIMAL_DEPTH_THRESHOLD ZSTD_btultra + +/*! HUF_compress() does the following: + * 1. count symbol occurrence from source[] into table count[] using FSE_count() (exposed within "fse.h") + * 2. (optional) refine tableLog using HUF_optimalTableLog() + * 3. build Huffman table from count using HUF_buildCTable() + * 4. save Huffman table to memory buffer using HUF_writeCTable() + * 5. encode the data stream using HUF_compress4X_usingCTable() + * + * The following API allows targeting specific sub-functions for advanced tasks. + * For example, it's possible to compress several blocks using the same 'CTable', + * or to save and regenerate 'CTable' using external methods. + */ +unsigned HUF_minTableLog(unsigned symbolCardinality); +unsigned HUF_cardinality(const unsigned* count, unsigned maxSymbolValue); +unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, void* workSpace, + size_t wkspSize, HUF_CElt* table, const unsigned* count, int flags); /* table is used as scratch space for building and testing tables, not a return value */ +size_t HUF_writeCTable_wksp(void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog, void* workspace, size_t workspaceSize); +size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int flags); +size_t HUF_estimateCompressedSize(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue); +int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue); + +typedef enum { + HUF_repeat_none, /**< Cannot use the previous table */ + HUF_repeat_check, /**< Can use the previous table but it must be checked. Note : The previous table must have been constructed by HUF_compress{1, 4}X_repeat */ + HUF_repeat_valid /**< Can use the previous table and it is assumed to be valid */ + } HUF_repeat; + +/** HUF_compress4X_repeat() : + * Same as HUF_compress4X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none. + * If it uses hufTable it does not modify hufTable or repeat. + * If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used. + * If preferRepeat then the old table will always be used if valid. + * If suspectUncompressible then some sampling checks will be run to potentially skip huffman coding */ +size_t HUF_compress4X_repeat(void* dst, size_t dstSize, + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned tableLog, + void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */ + HUF_CElt* hufTable, HUF_repeat* repeat, int flags); + +/** HUF_buildCTable_wksp() : + * Same as HUF_buildCTable(), but using externally allocated scratch buffer. + * `workSpace` must be aligned on 4-bytes boundaries, and its size must be >= HUF_CTABLE_WORKSPACE_SIZE. + */ +#define HUF_CTABLE_WORKSPACE_SIZE_U32 ((4 * (HUF_SYMBOLVALUE_MAX + 1)) + 192) +#define HUF_CTABLE_WORKSPACE_SIZE (HUF_CTABLE_WORKSPACE_SIZE_U32 * sizeof(unsigned)) +size_t HUF_buildCTable_wksp (HUF_CElt* tree, + const unsigned* count, U32 maxSymbolValue, U32 maxNbBits, + void* workSpace, size_t wkspSize); + +/*! HUF_readStats() : + * Read compact Huffman tree, saved by HUF_writeCTable(). + * `huffWeight` is destination buffer. + * @return : size read from `src` , or an error Code . + * Note : Needed by HUF_readCTable() and HUF_readDTableXn() . */ +size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, + U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize); + +/*! HUF_readStats_wksp() : + * Same as HUF_readStats() but takes an external workspace which must be + * 4-byte aligned and its size must be >= HUF_READ_STATS_WORKSPACE_SIZE. + * If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0. + */ +#define HUF_READ_STATS_WORKSPACE_SIZE_U32 FSE_DECOMPRESS_WKSP_SIZE_U32(6, HUF_TABLELOG_MAX-1) +#define HUF_READ_STATS_WORKSPACE_SIZE (HUF_READ_STATS_WORKSPACE_SIZE_U32 * sizeof(unsigned)) +size_t HUF_readStats_wksp(BYTE* huffWeight, size_t hwSize, + U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize, + void* workspace, size_t wkspSize, + int flags); + +/** HUF_readCTable() : + * Loading a CTable saved with HUF_writeCTable() */ +size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned *hasZeroWeights); + +/** HUF_getNbBitsFromCTable() : + * Read nbBits from CTable symbolTable, for symbol `symbolValue` presumed <= HUF_SYMBOLVALUE_MAX + * Note 1 : is not inlined, as HUF_CElt definition is private */ +U32 HUF_getNbBitsFromCTable(const HUF_CElt* symbolTable, U32 symbolValue); + +/* + * HUF_decompress() does the following: + * 1. select the decompression algorithm (X1, X2) based on pre-computed heuristics + * 2. build Huffman table from save, using HUF_readDTableX?() + * 3. decode 1 or 4 segments in parallel using HUF_decompress?X?_usingDTable() + */ + +/** HUF_selectDecoder() : + * Tells which decoder is likely to decode faster, + * based on a set of pre-computed metrics. + * @return : 0==HUF_decompress4X1, 1==HUF_decompress4X2 . + * Assumption : 0 < dstSize <= 128 KB */ +U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize); + +/** + * The minimum workspace size for the `workSpace` used in + * HUF_readDTableX1_wksp() and HUF_readDTableX2_wksp(). + * + * The space used depends on HUF_TABLELOG_MAX, ranging from ~1500 bytes when + * HUF_TABLE_LOG_MAX=12 to ~1850 bytes when HUF_TABLE_LOG_MAX=15. + * Buffer overflow errors may potentially occur if code modifications result in + * a required workspace size greater than that specified in the following + * macro. + */ +#define HUF_DECOMPRESS_WORKSPACE_SIZE ((2 << 10) + (1 << 9)) +#define HUF_DECOMPRESS_WORKSPACE_SIZE_U32 (HUF_DECOMPRESS_WORKSPACE_SIZE / sizeof(U32)) + + +/* ====================== */ +/* single stream variants */ +/* ====================== */ + +size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int flags); +/** HUF_compress1X_repeat() : + * Same as HUF_compress1X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none. + * If it uses hufTable it does not modify hufTable or repeat. + * If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used. + * If preferRepeat then the old table will always be used if valid. + * If suspectUncompressible then some sampling checks will be run to potentially skip huffman coding */ +size_t HUF_compress1X_repeat(void* dst, size_t dstSize, + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned tableLog, + void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */ + HUF_CElt* hufTable, HUF_repeat* repeat, int flags); + +size_t HUF_decompress1X_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int flags); +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int flags); /**< double-symbols decoder */ +#endif + +/* BMI2 variants. + * If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0. + */ +size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int flags); +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int flags); +#endif +size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int flags); +size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int flags); +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_readDTableX1_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int flags); +#endif +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_readDTableX2_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int flags); +#endif + +#endif /* HUF_H_298734234 */ + +#if defined (__cplusplus) +} +#endif diff --git a/lib/zstd/lib/common/mem.h b/lib/zstd/lib/common/mem.h new file mode 100644 index 0000000..98dd47a --- /dev/null +++ b/lib/zstd/lib/common/mem.h @@ -0,0 +1,435 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef MEM_H_MODULE +#define MEM_H_MODULE + +#if defined (__cplusplus) +extern "C" { +#endif + +/*-**************************************** +* Dependencies +******************************************/ +#include /* size_t, ptrdiff_t */ +#include "compiler.h" /* __has_builtin */ +#include "debug.h" /* DEBUG_STATIC_ASSERT */ +#include "zstd_deps.h" /* ZSTD_memcpy */ + + +/*-**************************************** +* Compiler specifics +******************************************/ +#if defined(_MSC_VER) /* Visual Studio */ +# include /* _byteswap_ulong */ +# include /* _byteswap_* */ +#endif +#if defined(__GNUC__) +# define MEM_STATIC static __inline __attribute__((unused)) +#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) +# define MEM_STATIC static inline +#elif defined(_MSC_VER) +# define MEM_STATIC static __inline +#else +# define MEM_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */ +#endif + +/*-************************************************************** +* Basic Types +*****************************************************************/ +#if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) +# if defined(_AIX) +# include +# else +# include /* intptr_t */ +# endif + typedef uint8_t BYTE; + typedef uint8_t U8; + typedef int8_t S8; + typedef uint16_t U16; + typedef int16_t S16; + typedef uint32_t U32; + typedef int32_t S32; + typedef uint64_t U64; + typedef int64_t S64; +#else +# include +#if CHAR_BIT != 8 +# error "this implementation requires char to be exactly 8-bit type" +#endif + typedef unsigned char BYTE; + typedef unsigned char U8; + typedef signed char S8; +#if USHRT_MAX != 65535 +# error "this implementation requires short to be exactly 16-bit type" +#endif + typedef unsigned short U16; + typedef signed short S16; +#if UINT_MAX != 4294967295 +# error "this implementation requires int to be exactly 32-bit type" +#endif + typedef unsigned int U32; + typedef signed int S32; +/* note : there are no limits defined for long long type in C90. + * limits exist in C99, however, in such case, is preferred */ + typedef unsigned long long U64; + typedef signed long long S64; +#endif + + +/*-************************************************************** +* Memory I/O API +*****************************************************************/ +/*=== Static platform detection ===*/ +MEM_STATIC unsigned MEM_32bits(void); +MEM_STATIC unsigned MEM_64bits(void); +MEM_STATIC unsigned MEM_isLittleEndian(void); + +/*=== Native unaligned read/write ===*/ +MEM_STATIC U16 MEM_read16(const void* memPtr); +MEM_STATIC U32 MEM_read32(const void* memPtr); +MEM_STATIC U64 MEM_read64(const void* memPtr); +MEM_STATIC size_t MEM_readST(const void* memPtr); + +MEM_STATIC void MEM_write16(void* memPtr, U16 value); +MEM_STATIC void MEM_write32(void* memPtr, U32 value); +MEM_STATIC void MEM_write64(void* memPtr, U64 value); + +/*=== Little endian unaligned read/write ===*/ +MEM_STATIC U16 MEM_readLE16(const void* memPtr); +MEM_STATIC U32 MEM_readLE24(const void* memPtr); +MEM_STATIC U32 MEM_readLE32(const void* memPtr); +MEM_STATIC U64 MEM_readLE64(const void* memPtr); +MEM_STATIC size_t MEM_readLEST(const void* memPtr); + +MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val); +MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val); +MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32); +MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64); +MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val); + +/*=== Big endian unaligned read/write ===*/ +MEM_STATIC U32 MEM_readBE32(const void* memPtr); +MEM_STATIC U64 MEM_readBE64(const void* memPtr); +MEM_STATIC size_t MEM_readBEST(const void* memPtr); + +MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32); +MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64); +MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val); + +/*=== Byteswap ===*/ +MEM_STATIC U32 MEM_swap32(U32 in); +MEM_STATIC U64 MEM_swap64(U64 in); +MEM_STATIC size_t MEM_swapST(size_t in); + + +/*-************************************************************** +* Memory I/O Implementation +*****************************************************************/ +/* MEM_FORCE_MEMORY_ACCESS : For accessing unaligned memory: + * Method 0 : always use `memcpy()`. Safe and portable. + * Method 1 : Use compiler extension to set unaligned access. + * Method 2 : direct access. This method is portable but violate C standard. + * It can generate buggy code on targets depending on alignment. + * Default : method 1 if supported, else method 0 + */ +#ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ +# ifdef __GNUC__ +# define MEM_FORCE_MEMORY_ACCESS 1 +# endif +#endif + +MEM_STATIC unsigned MEM_32bits(void) { return sizeof(size_t)==4; } +MEM_STATIC unsigned MEM_64bits(void) { return sizeof(size_t)==8; } + +MEM_STATIC unsigned MEM_isLittleEndian(void) +{ +#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + return 1; +#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + return 0; +#elif defined(__clang__) && __LITTLE_ENDIAN__ + return 1; +#elif defined(__clang__) && __BIG_ENDIAN__ + return 0; +#elif defined(_MSC_VER) && (_M_AMD64 || _M_IX86) + return 1; +#elif defined(__DMC__) && defined(_M_IX86) + return 1; +#else + const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ + return one.c[0]; +#endif +} + +#if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2) + +/* violates C standard, by lying on structure alignment. +Only use if no other choice to achieve best performance on target platform */ +MEM_STATIC U16 MEM_read16(const void* memPtr) { return *(const U16*) memPtr; } +MEM_STATIC U32 MEM_read32(const void* memPtr) { return *(const U32*) memPtr; } +MEM_STATIC U64 MEM_read64(const void* memPtr) { return *(const U64*) memPtr; } +MEM_STATIC size_t MEM_readST(const void* memPtr) { return *(const size_t*) memPtr; } + +MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; } +MEM_STATIC void MEM_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; } +MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(U64*)memPtr = value; } + +#elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1) + +typedef __attribute__((aligned(1))) U16 unalign16; +typedef __attribute__((aligned(1))) U32 unalign32; +typedef __attribute__((aligned(1))) U64 unalign64; +typedef __attribute__((aligned(1))) size_t unalignArch; + +MEM_STATIC U16 MEM_read16(const void* ptr) { return *(const unalign16*)ptr; } +MEM_STATIC U32 MEM_read32(const void* ptr) { return *(const unalign32*)ptr; } +MEM_STATIC U64 MEM_read64(const void* ptr) { return *(const unalign64*)ptr; } +MEM_STATIC size_t MEM_readST(const void* ptr) { return *(const unalignArch*)ptr; } + +MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(unalign16*)memPtr = value; } +MEM_STATIC void MEM_write32(void* memPtr, U32 value) { *(unalign32*)memPtr = value; } +MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(unalign64*)memPtr = value; } + +#else + +/* default method, safe and standard. + can sometimes prove slower */ + +MEM_STATIC U16 MEM_read16(const void* memPtr) +{ + U16 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val; +} + +MEM_STATIC U32 MEM_read32(const void* memPtr) +{ + U32 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val; +} + +MEM_STATIC U64 MEM_read64(const void* memPtr) +{ + U64 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val; +} + +MEM_STATIC size_t MEM_readST(const void* memPtr) +{ + size_t val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val; +} + +MEM_STATIC void MEM_write16(void* memPtr, U16 value) +{ + ZSTD_memcpy(memPtr, &value, sizeof(value)); +} + +MEM_STATIC void MEM_write32(void* memPtr, U32 value) +{ + ZSTD_memcpy(memPtr, &value, sizeof(value)); +} + +MEM_STATIC void MEM_write64(void* memPtr, U64 value) +{ + ZSTD_memcpy(memPtr, &value, sizeof(value)); +} + +#endif /* MEM_FORCE_MEMORY_ACCESS */ + +MEM_STATIC U32 MEM_swap32_fallback(U32 in) +{ + return ((in << 24) & 0xff000000 ) | + ((in << 8) & 0x00ff0000 ) | + ((in >> 8) & 0x0000ff00 ) | + ((in >> 24) & 0x000000ff ); +} + +MEM_STATIC U32 MEM_swap32(U32 in) +{ +#if defined(_MSC_VER) /* Visual Studio */ + return _byteswap_ulong(in); +#elif (defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) \ + || (defined(__clang__) && __has_builtin(__builtin_bswap32)) + return __builtin_bswap32(in); +#else + return MEM_swap32_fallback(in); +#endif +} + +MEM_STATIC U64 MEM_swap64_fallback(U64 in) +{ + return ((in << 56) & 0xff00000000000000ULL) | + ((in << 40) & 0x00ff000000000000ULL) | + ((in << 24) & 0x0000ff0000000000ULL) | + ((in << 8) & 0x000000ff00000000ULL) | + ((in >> 8) & 0x00000000ff000000ULL) | + ((in >> 24) & 0x0000000000ff0000ULL) | + ((in >> 40) & 0x000000000000ff00ULL) | + ((in >> 56) & 0x00000000000000ffULL); +} + +MEM_STATIC U64 MEM_swap64(U64 in) +{ +#if defined(_MSC_VER) /* Visual Studio */ + return _byteswap_uint64(in); +#elif (defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) \ + || (defined(__clang__) && __has_builtin(__builtin_bswap64)) + return __builtin_bswap64(in); +#else + return MEM_swap64_fallback(in); +#endif +} + +MEM_STATIC size_t MEM_swapST(size_t in) +{ + if (MEM_32bits()) + return (size_t)MEM_swap32((U32)in); + else + return (size_t)MEM_swap64((U64)in); +} + +/*=== Little endian r/w ===*/ + +MEM_STATIC U16 MEM_readLE16(const void* memPtr) +{ + if (MEM_isLittleEndian()) + return MEM_read16(memPtr); + else { + const BYTE* p = (const BYTE*)memPtr; + return (U16)(p[0] + (p[1]<<8)); + } +} + +MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val) +{ + if (MEM_isLittleEndian()) { + MEM_write16(memPtr, val); + } else { + BYTE* p = (BYTE*)memPtr; + p[0] = (BYTE)val; + p[1] = (BYTE)(val>>8); + } +} + +MEM_STATIC U32 MEM_readLE24(const void* memPtr) +{ + return (U32)MEM_readLE16(memPtr) + ((U32)(((const BYTE*)memPtr)[2]) << 16); +} + +MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val) +{ + MEM_writeLE16(memPtr, (U16)val); + ((BYTE*)memPtr)[2] = (BYTE)(val>>16); +} + +MEM_STATIC U32 MEM_readLE32(const void* memPtr) +{ + if (MEM_isLittleEndian()) + return MEM_read32(memPtr); + else + return MEM_swap32(MEM_read32(memPtr)); +} + +MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32) +{ + if (MEM_isLittleEndian()) + MEM_write32(memPtr, val32); + else + MEM_write32(memPtr, MEM_swap32(val32)); +} + +MEM_STATIC U64 MEM_readLE64(const void* memPtr) +{ + if (MEM_isLittleEndian()) + return MEM_read64(memPtr); + else + return MEM_swap64(MEM_read64(memPtr)); +} + +MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64) +{ + if (MEM_isLittleEndian()) + MEM_write64(memPtr, val64); + else + MEM_write64(memPtr, MEM_swap64(val64)); +} + +MEM_STATIC size_t MEM_readLEST(const void* memPtr) +{ + if (MEM_32bits()) + return (size_t)MEM_readLE32(memPtr); + else + return (size_t)MEM_readLE64(memPtr); +} + +MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val) +{ + if (MEM_32bits()) + MEM_writeLE32(memPtr, (U32)val); + else + MEM_writeLE64(memPtr, (U64)val); +} + +/*=== Big endian r/w ===*/ + +MEM_STATIC U32 MEM_readBE32(const void* memPtr) +{ + if (MEM_isLittleEndian()) + return MEM_swap32(MEM_read32(memPtr)); + else + return MEM_read32(memPtr); +} + +MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32) +{ + if (MEM_isLittleEndian()) + MEM_write32(memPtr, MEM_swap32(val32)); + else + MEM_write32(memPtr, val32); +} + +MEM_STATIC U64 MEM_readBE64(const void* memPtr) +{ + if (MEM_isLittleEndian()) + return MEM_swap64(MEM_read64(memPtr)); + else + return MEM_read64(memPtr); +} + +MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64) +{ + if (MEM_isLittleEndian()) + MEM_write64(memPtr, MEM_swap64(val64)); + else + MEM_write64(memPtr, val64); +} + +MEM_STATIC size_t MEM_readBEST(const void* memPtr) +{ + if (MEM_32bits()) + return (size_t)MEM_readBE32(memPtr); + else + return (size_t)MEM_readBE64(memPtr); +} + +MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val) +{ + if (MEM_32bits()) + MEM_writeBE32(memPtr, (U32)val); + else + MEM_writeBE64(memPtr, (U64)val); +} + +/* code only tested on 32 and 64 bits systems */ +MEM_STATIC void MEM_check(void) { DEBUG_STATIC_ASSERT((sizeof(size_t)==4) || (sizeof(size_t)==8)); } + + +#if defined (__cplusplus) +} +#endif + +#endif /* MEM_H_MODULE */ diff --git a/lib/zstd/lib/common/pool.c b/lib/zstd/lib/common/pool.c new file mode 100644 index 0000000..d5ca5a7 --- /dev/null +++ b/lib/zstd/lib/common/pool.c @@ -0,0 +1,371 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + + +/* ====== Dependencies ======= */ +#include "../common/allocations.h" /* ZSTD_customCalloc, ZSTD_customFree */ +#include "zstd_deps.h" /* size_t */ +#include "debug.h" /* assert */ +#include "pool.h" + +/* ====== Compiler specifics ====== */ +#if defined(_MSC_VER) +# pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */ +#endif + + +#ifdef ZSTD_MULTITHREAD + +#include "threading.h" /* pthread adaptation */ + +/* A job is a function and an opaque argument */ +typedef struct POOL_job_s { + POOL_function function; + void *opaque; +} POOL_job; + +struct POOL_ctx_s { + ZSTD_customMem customMem; + /* Keep track of the threads */ + ZSTD_pthread_t* threads; + size_t threadCapacity; + size_t threadLimit; + + /* The queue is a circular buffer */ + POOL_job *queue; + size_t queueHead; + size_t queueTail; + size_t queueSize; + + /* The number of threads working on jobs */ + size_t numThreadsBusy; + /* Indicates if the queue is empty */ + int queueEmpty; + + /* The mutex protects the queue */ + ZSTD_pthread_mutex_t queueMutex; + /* Condition variable for pushers to wait on when the queue is full */ + ZSTD_pthread_cond_t queuePushCond; + /* Condition variables for poppers to wait on when the queue is empty */ + ZSTD_pthread_cond_t queuePopCond; + /* Indicates if the queue is shutting down */ + int shutdown; +}; + +/* POOL_thread() : + * Work thread for the thread pool. + * Waits for jobs and executes them. + * @returns : NULL on failure else non-null. + */ +static void* POOL_thread(void* opaque) { + POOL_ctx* const ctx = (POOL_ctx*)opaque; + if (!ctx) { return NULL; } + for (;;) { + /* Lock the mutex and wait for a non-empty queue or until shutdown */ + ZSTD_pthread_mutex_lock(&ctx->queueMutex); + + while ( ctx->queueEmpty + || (ctx->numThreadsBusy >= ctx->threadLimit) ) { + if (ctx->shutdown) { + /* even if !queueEmpty, (possible if numThreadsBusy >= threadLimit), + * a few threads will be shutdown while !queueEmpty, + * but enough threads will remain active to finish the queue */ + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + return opaque; + } + ZSTD_pthread_cond_wait(&ctx->queuePopCond, &ctx->queueMutex); + } + /* Pop a job off the queue */ + { POOL_job const job = ctx->queue[ctx->queueHead]; + ctx->queueHead = (ctx->queueHead + 1) % ctx->queueSize; + ctx->numThreadsBusy++; + ctx->queueEmpty = (ctx->queueHead == ctx->queueTail); + /* Unlock the mutex, signal a pusher, and run the job */ + ZSTD_pthread_cond_signal(&ctx->queuePushCond); + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + + job.function(job.opaque); + + /* If the intended queue size was 0, signal after finishing job */ + ZSTD_pthread_mutex_lock(&ctx->queueMutex); + ctx->numThreadsBusy--; + ZSTD_pthread_cond_signal(&ctx->queuePushCond); + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + } + } /* for (;;) */ + assert(0); /* Unreachable */ +} + +/* ZSTD_createThreadPool() : public access point */ +POOL_ctx* ZSTD_createThreadPool(size_t numThreads) { + return POOL_create (numThreads, 0); +} + +POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) { + return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem); +} + +POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, + ZSTD_customMem customMem) +{ + POOL_ctx* ctx; + /* Check parameters */ + if (!numThreads) { return NULL; } + /* Allocate the context and zero initialize */ + ctx = (POOL_ctx*)ZSTD_customCalloc(sizeof(POOL_ctx), customMem); + if (!ctx) { return NULL; } + /* Initialize the job queue. + * It needs one extra space since one space is wasted to differentiate + * empty and full queues. + */ + ctx->queueSize = queueSize + 1; + ctx->queue = (POOL_job*)ZSTD_customCalloc(ctx->queueSize * sizeof(POOL_job), customMem); + ctx->queueHead = 0; + ctx->queueTail = 0; + ctx->numThreadsBusy = 0; + ctx->queueEmpty = 1; + { + int error = 0; + error |= ZSTD_pthread_mutex_init(&ctx->queueMutex, NULL); + error |= ZSTD_pthread_cond_init(&ctx->queuePushCond, NULL); + error |= ZSTD_pthread_cond_init(&ctx->queuePopCond, NULL); + if (error) { POOL_free(ctx); return NULL; } + } + ctx->shutdown = 0; + /* Allocate space for the thread handles */ + ctx->threads = (ZSTD_pthread_t*)ZSTD_customCalloc(numThreads * sizeof(ZSTD_pthread_t), customMem); + ctx->threadCapacity = 0; + ctx->customMem = customMem; + /* Check for errors */ + if (!ctx->threads || !ctx->queue) { POOL_free(ctx); return NULL; } + /* Initialize the threads */ + { size_t i; + for (i = 0; i < numThreads; ++i) { + if (ZSTD_pthread_create(&ctx->threads[i], NULL, &POOL_thread, ctx)) { + ctx->threadCapacity = i; + POOL_free(ctx); + return NULL; + } } + ctx->threadCapacity = numThreads; + ctx->threadLimit = numThreads; + } + return ctx; +} + +/*! POOL_join() : + Shutdown the queue, wake any sleeping threads, and join all of the threads. +*/ +static void POOL_join(POOL_ctx* ctx) { + /* Shut down the queue */ + ZSTD_pthread_mutex_lock(&ctx->queueMutex); + ctx->shutdown = 1; + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + /* Wake up sleeping threads */ + ZSTD_pthread_cond_broadcast(&ctx->queuePushCond); + ZSTD_pthread_cond_broadcast(&ctx->queuePopCond); + /* Join all of the threads */ + { size_t i; + for (i = 0; i < ctx->threadCapacity; ++i) { + ZSTD_pthread_join(ctx->threads[i]); /* note : could fail */ + } } +} + +void POOL_free(POOL_ctx *ctx) { + if (!ctx) { return; } + POOL_join(ctx); + ZSTD_pthread_mutex_destroy(&ctx->queueMutex); + ZSTD_pthread_cond_destroy(&ctx->queuePushCond); + ZSTD_pthread_cond_destroy(&ctx->queuePopCond); + ZSTD_customFree(ctx->queue, ctx->customMem); + ZSTD_customFree(ctx->threads, ctx->customMem); + ZSTD_customFree(ctx, ctx->customMem); +} + +/*! POOL_joinJobs() : + * Waits for all queued jobs to finish executing. + */ +void POOL_joinJobs(POOL_ctx* ctx) { + ZSTD_pthread_mutex_lock(&ctx->queueMutex); + while(!ctx->queueEmpty || ctx->numThreadsBusy > 0) { + ZSTD_pthread_cond_wait(&ctx->queuePushCond, &ctx->queueMutex); + } + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); +} + +void ZSTD_freeThreadPool (ZSTD_threadPool* pool) { + POOL_free (pool); +} + +size_t POOL_sizeof(const POOL_ctx* ctx) { + if (ctx==NULL) return 0; /* supports sizeof NULL */ + return sizeof(*ctx) + + ctx->queueSize * sizeof(POOL_job) + + ctx->threadCapacity * sizeof(ZSTD_pthread_t); +} + + +/* @return : 0 on success, 1 on error */ +static int POOL_resize_internal(POOL_ctx* ctx, size_t numThreads) +{ + if (numThreads <= ctx->threadCapacity) { + if (!numThreads) return 1; + ctx->threadLimit = numThreads; + return 0; + } + /* numThreads > threadCapacity */ + { ZSTD_pthread_t* const threadPool = (ZSTD_pthread_t*)ZSTD_customCalloc(numThreads * sizeof(ZSTD_pthread_t), ctx->customMem); + if (!threadPool) return 1; + /* replace existing thread pool */ + ZSTD_memcpy(threadPool, ctx->threads, ctx->threadCapacity * sizeof(*threadPool)); + ZSTD_customFree(ctx->threads, ctx->customMem); + ctx->threads = threadPool; + /* Initialize additional threads */ + { size_t threadId; + for (threadId = ctx->threadCapacity; threadId < numThreads; ++threadId) { + if (ZSTD_pthread_create(&threadPool[threadId], NULL, &POOL_thread, ctx)) { + ctx->threadCapacity = threadId; + return 1; + } } + } } + /* successfully expanded */ + ctx->threadCapacity = numThreads; + ctx->threadLimit = numThreads; + return 0; +} + +/* @return : 0 on success, 1 on error */ +int POOL_resize(POOL_ctx* ctx, size_t numThreads) +{ + int result; + if (ctx==NULL) return 1; + ZSTD_pthread_mutex_lock(&ctx->queueMutex); + result = POOL_resize_internal(ctx, numThreads); + ZSTD_pthread_cond_broadcast(&ctx->queuePopCond); + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + return result; +} + +/** + * Returns 1 if the queue is full and 0 otherwise. + * + * When queueSize is 1 (pool was created with an intended queueSize of 0), + * then a queue is empty if there is a thread free _and_ no job is waiting. + */ +static int isQueueFull(POOL_ctx const* ctx) { + if (ctx->queueSize > 1) { + return ctx->queueHead == ((ctx->queueTail + 1) % ctx->queueSize); + } else { + return (ctx->numThreadsBusy == ctx->threadLimit) || + !ctx->queueEmpty; + } +} + + +static void +POOL_add_internal(POOL_ctx* ctx, POOL_function function, void *opaque) +{ + POOL_job job; + job.function = function; + job.opaque = opaque; + assert(ctx != NULL); + if (ctx->shutdown) return; + + ctx->queueEmpty = 0; + ctx->queue[ctx->queueTail] = job; + ctx->queueTail = (ctx->queueTail + 1) % ctx->queueSize; + ZSTD_pthread_cond_signal(&ctx->queuePopCond); +} + +void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque) +{ + assert(ctx != NULL); + ZSTD_pthread_mutex_lock(&ctx->queueMutex); + /* Wait until there is space in the queue for the new job */ + while (isQueueFull(ctx) && (!ctx->shutdown)) { + ZSTD_pthread_cond_wait(&ctx->queuePushCond, &ctx->queueMutex); + } + POOL_add_internal(ctx, function, opaque); + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); +} + + +int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque) +{ + assert(ctx != NULL); + ZSTD_pthread_mutex_lock(&ctx->queueMutex); + if (isQueueFull(ctx)) { + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + return 0; + } + POOL_add_internal(ctx, function, opaque); + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + return 1; +} + + +#else /* ZSTD_MULTITHREAD not defined */ + +/* ========================== */ +/* No multi-threading support */ +/* ========================== */ + + +/* We don't need any data, but if it is empty, malloc() might return NULL. */ +struct POOL_ctx_s { + int dummy; +}; +static POOL_ctx g_poolCtx; + +POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) { + return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem); +} + +POOL_ctx* +POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customMem customMem) +{ + (void)numThreads; + (void)queueSize; + (void)customMem; + return &g_poolCtx; +} + +void POOL_free(POOL_ctx* ctx) { + assert(!ctx || ctx == &g_poolCtx); + (void)ctx; +} + +void POOL_joinJobs(POOL_ctx* ctx){ + assert(!ctx || ctx == &g_poolCtx); + (void)ctx; +} + +int POOL_resize(POOL_ctx* ctx, size_t numThreads) { + (void)ctx; (void)numThreads; + return 0; +} + +void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque) { + (void)ctx; + function(opaque); +} + +int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque) { + (void)ctx; + function(opaque); + return 1; +} + +size_t POOL_sizeof(const POOL_ctx* ctx) { + if (ctx==NULL) return 0; /* supports sizeof NULL */ + assert(ctx == &g_poolCtx); + return sizeof(*ctx); +} + +#endif /* ZSTD_MULTITHREAD */ diff --git a/lib/zstd/lib/common/pool.h b/lib/zstd/lib/common/pool.h new file mode 100644 index 0000000..eb22ff5 --- /dev/null +++ b/lib/zstd/lib/common/pool.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef POOL_H +#define POOL_H + +#if defined (__cplusplus) +extern "C" { +#endif + + +#include "zstd_deps.h" +#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_customMem */ +#include "../zstd.h" + +typedef struct POOL_ctx_s POOL_ctx; + +/*! POOL_create() : + * Create a thread pool with at most `numThreads` threads. + * `numThreads` must be at least 1. + * The maximum number of queued jobs before blocking is `queueSize`. + * @return : POOL_ctx pointer on success, else NULL. +*/ +POOL_ctx* POOL_create(size_t numThreads, size_t queueSize); + +POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, + ZSTD_customMem customMem); + +/*! POOL_free() : + * Free a thread pool returned by POOL_create(). + */ +void POOL_free(POOL_ctx* ctx); + + +/*! POOL_joinJobs() : + * Waits for all queued jobs to finish executing. + */ +void POOL_joinJobs(POOL_ctx* ctx); + +/*! POOL_resize() : + * Expands or shrinks pool's number of threads. + * This is more efficient than releasing + creating a new context, + * since it tries to preserve and re-use existing threads. + * `numThreads` must be at least 1. + * @return : 0 when resize was successful, + * !0 (typically 1) if there is an error. + * note : only numThreads can be resized, queueSize remains unchanged. + */ +int POOL_resize(POOL_ctx* ctx, size_t numThreads); + +/*! POOL_sizeof() : + * @return threadpool memory usage + * note : compatible with NULL (returns 0 in this case) + */ +size_t POOL_sizeof(const POOL_ctx* ctx); + +/*! POOL_function : + * The function type that can be added to a thread pool. + */ +typedef void (*POOL_function)(void*); + +/*! POOL_add() : + * Add the job `function(opaque)` to the thread pool. `ctx` must be valid. + * Possibly blocks until there is room in the queue. + * Note : The function may be executed asynchronously, + * therefore, `opaque` must live until function has been completed. + */ +void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque); + + +/*! POOL_tryAdd() : + * Add the job `function(opaque)` to thread pool _if_ a queue slot is available. + * Returns immediately even if not (does not block). + * @return : 1 if successful, 0 if not. + */ +int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque); + + +#if defined (__cplusplus) +} +#endif + +#endif diff --git a/lib/zstd/lib/common/portability_macros.h b/lib/zstd/lib/common/portability_macros.h new file mode 100644 index 0000000..8fd6ea8 --- /dev/null +++ b/lib/zstd/lib/common/portability_macros.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef ZSTD_PORTABILITY_MACROS_H +#define ZSTD_PORTABILITY_MACROS_H + +/** + * This header file contains macro definitions to support portability. + * This header is shared between C and ASM code, so it MUST only + * contain macro definitions. It MUST not contain any C code. + * + * This header ONLY defines macros to detect platforms/feature support. + * + */ + + +/* compat. with non-clang compilers */ +#ifndef __has_attribute + #define __has_attribute(x) 0 +#endif + +/* compat. with non-clang compilers */ +#ifndef __has_builtin +# define __has_builtin(x) 0 +#endif + +/* compat. with non-clang compilers */ +#ifndef __has_feature +# define __has_feature(x) 0 +#endif + +/* detects whether we are being compiled under msan */ +#ifndef ZSTD_MEMORY_SANITIZER +# if __has_feature(memory_sanitizer) +# define ZSTD_MEMORY_SANITIZER 1 +# else +# define ZSTD_MEMORY_SANITIZER 0 +# endif +#endif + +/* detects whether we are being compiled under asan */ +#ifndef ZSTD_ADDRESS_SANITIZER +# if __has_feature(address_sanitizer) +# define ZSTD_ADDRESS_SANITIZER 1 +# elif defined(__SANITIZE_ADDRESS__) +# define ZSTD_ADDRESS_SANITIZER 1 +# else +# define ZSTD_ADDRESS_SANITIZER 0 +# endif +#endif + +/* detects whether we are being compiled under dfsan */ +#ifndef ZSTD_DATAFLOW_SANITIZER +# if __has_feature(dataflow_sanitizer) +# define ZSTD_DATAFLOW_SANITIZER 1 +# else +# define ZSTD_DATAFLOW_SANITIZER 0 +# endif +#endif + +/* Mark the internal assembly functions as hidden */ +#ifdef __ELF__ +# define ZSTD_HIDE_ASM_FUNCTION(func) .hidden func +#else +# define ZSTD_HIDE_ASM_FUNCTION(func) +#endif + +/* Enable runtime BMI2 dispatch based on the CPU. + * Enabled for clang & gcc >=4.8 on x86 when BMI2 isn't enabled by default. + */ +#ifndef DYNAMIC_BMI2 + #if ((defined(__clang__) && __has_attribute(__target__)) \ + || (defined(__GNUC__) \ + && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))) \ + && (defined(__x86_64__) || defined(_M_X64)) \ + && !defined(__BMI2__) + # define DYNAMIC_BMI2 1 + #else + # define DYNAMIC_BMI2 0 + #endif +#endif + +/** + * Only enable assembly for GNUC compatible compilers, + * because other platforms may not support GAS assembly syntax. + * + * Only enable assembly for Linux / MacOS, other platforms may + * work, but they haven't been tested. This could likely be + * extended to BSD systems. + * + * Disable assembly when MSAN is enabled, because MSAN requires + * 100% of code to be instrumented to work. + */ +#if defined(__GNUC__) +# if defined(__linux__) || defined(__linux) || defined(__APPLE__) +# if ZSTD_MEMORY_SANITIZER +# define ZSTD_ASM_SUPPORTED 0 +# elif ZSTD_DATAFLOW_SANITIZER +# define ZSTD_ASM_SUPPORTED 0 +# else +# define ZSTD_ASM_SUPPORTED 1 +# endif +# else +# define ZSTD_ASM_SUPPORTED 0 +# endif +#else +# define ZSTD_ASM_SUPPORTED 0 +#endif + +/** + * Determines whether we should enable assembly for x86-64 + * with BMI2. + * + * Enable if all of the following conditions hold: + * - ASM hasn't been explicitly disabled by defining ZSTD_DISABLE_ASM + * - Assembly is supported + * - We are compiling for x86-64 and either: + * - DYNAMIC_BMI2 is enabled + * - BMI2 is supported at compile time + */ +#if !defined(ZSTD_DISABLE_ASM) && \ + ZSTD_ASM_SUPPORTED && \ + defined(__x86_64__) && \ + (DYNAMIC_BMI2 || defined(__BMI2__)) +# define ZSTD_ENABLE_ASM_X86_64_BMI2 1 +#else +# define ZSTD_ENABLE_ASM_X86_64_BMI2 0 +#endif + +/* + * For x86 ELF targets, add .note.gnu.property section for Intel CET in + * assembly sources when CET is enabled. + * + * Additionally, any function that may be called indirectly must begin + * with ZSTD_CET_ENDBRANCH. + */ +#if defined(__ELF__) && (defined(__x86_64__) || defined(__i386__)) \ + && defined(__has_include) +# if __has_include() +# include +# define ZSTD_CET_ENDBRANCH _CET_ENDBR +# endif +#endif + +#ifndef ZSTD_CET_ENDBRANCH +# define ZSTD_CET_ENDBRANCH +#endif + +#endif /* ZSTD_PORTABILITY_MACROS_H */ diff --git a/lib/zstd/lib/common/threading.c b/lib/zstd/lib/common/threading.c new file mode 100644 index 0000000..ca155b9 --- /dev/null +++ b/lib/zstd/lib/common/threading.c @@ -0,0 +1,176 @@ +/** + * Copyright (c) 2016 Tino Reichardt + * All rights reserved. + * + * You can contact the author at: + * - zstdmt source repository: https://github.com/mcmilk/zstdmt + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +/** + * This file will hold wrapper for systems, which do not support pthreads + */ + +#include "threading.h" + +/* create fake symbol to avoid empty translation unit warning */ +int g_ZSTD_threading_useless_symbol; + +#if defined(ZSTD_MULTITHREAD) && defined(_WIN32) + +/** + * Windows minimalist Pthread Wrapper + */ + + +/* === Dependencies === */ +#include +#include + + +/* === Implementation === */ + +typedef struct { + void* (*start_routine)(void*); + void* arg; + int initialized; + ZSTD_pthread_cond_t initialized_cond; + ZSTD_pthread_mutex_t initialized_mutex; +} ZSTD_thread_params_t; + +static unsigned __stdcall worker(void *arg) +{ + void* (*start_routine)(void*); + void* thread_arg; + + /* Initialized thread_arg and start_routine and signal main thread that we don't need it + * to wait any longer. + */ + { + ZSTD_thread_params_t* thread_param = (ZSTD_thread_params_t*)arg; + thread_arg = thread_param->arg; + start_routine = thread_param->start_routine; + + /* Signal main thread that we are running and do not depend on its memory anymore */ + ZSTD_pthread_mutex_lock(&thread_param->initialized_mutex); + thread_param->initialized = 1; + ZSTD_pthread_cond_signal(&thread_param->initialized_cond); + ZSTD_pthread_mutex_unlock(&thread_param->initialized_mutex); + } + + start_routine(thread_arg); + + return 0; +} + +int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused, + void* (*start_routine) (void*), void* arg) +{ + ZSTD_thread_params_t thread_param; + (void)unused; + + thread_param.start_routine = start_routine; + thread_param.arg = arg; + thread_param.initialized = 0; + *thread = NULL; + + /* Setup thread initialization synchronization */ + if(ZSTD_pthread_cond_init(&thread_param.initialized_cond, NULL)) { + /* Should never happen on Windows */ + return -1; + } + if(ZSTD_pthread_mutex_init(&thread_param.initialized_mutex, NULL)) { + /* Should never happen on Windows */ + ZSTD_pthread_cond_destroy(&thread_param.initialized_cond); + return -1; + } + + /* Spawn thread */ + *thread = (HANDLE)_beginthreadex(NULL, 0, worker, &thread_param, 0, NULL); + if (!thread) { + ZSTD_pthread_mutex_destroy(&thread_param.initialized_mutex); + ZSTD_pthread_cond_destroy(&thread_param.initialized_cond); + return errno; + } + + /* Wait for thread to be initialized */ + ZSTD_pthread_mutex_lock(&thread_param.initialized_mutex); + while(!thread_param.initialized) { + ZSTD_pthread_cond_wait(&thread_param.initialized_cond, &thread_param.initialized_mutex); + } + ZSTD_pthread_mutex_unlock(&thread_param.initialized_mutex); + ZSTD_pthread_mutex_destroy(&thread_param.initialized_mutex); + ZSTD_pthread_cond_destroy(&thread_param.initialized_cond); + + return 0; +} + +int ZSTD_pthread_join(ZSTD_pthread_t thread) +{ + DWORD result; + + if (!thread) return 0; + + result = WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + + switch (result) { + case WAIT_OBJECT_0: + return 0; + case WAIT_ABANDONED: + return EINVAL; + default: + return GetLastError(); + } +} + +#endif /* ZSTD_MULTITHREAD */ + +#if defined(ZSTD_MULTITHREAD) && DEBUGLEVEL >= 1 && !defined(_WIN32) + +#define ZSTD_DEPS_NEED_MALLOC +#include "zstd_deps.h" + +int ZSTD_pthread_mutex_init(ZSTD_pthread_mutex_t* mutex, pthread_mutexattr_t const* attr) +{ + *mutex = (pthread_mutex_t*)ZSTD_malloc(sizeof(pthread_mutex_t)); + if (!*mutex) + return 1; + return pthread_mutex_init(*mutex, attr); +} + +int ZSTD_pthread_mutex_destroy(ZSTD_pthread_mutex_t* mutex) +{ + if (!*mutex) + return 0; + { + int const ret = pthread_mutex_destroy(*mutex); + ZSTD_free(*mutex); + return ret; + } +} + +int ZSTD_pthread_cond_init(ZSTD_pthread_cond_t* cond, pthread_condattr_t const* attr) +{ + *cond = (pthread_cond_t*)ZSTD_malloc(sizeof(pthread_cond_t)); + if (!*cond) + return 1; + return pthread_cond_init(*cond, attr); +} + +int ZSTD_pthread_cond_destroy(ZSTD_pthread_cond_t* cond) +{ + if (!*cond) + return 0; + { + int const ret = pthread_cond_destroy(*cond); + ZSTD_free(*cond); + return ret; + } +} + +#endif diff --git a/lib/zstd/lib/common/threading.h b/lib/zstd/lib/common/threading.h new file mode 100644 index 0000000..fb5c1c8 --- /dev/null +++ b/lib/zstd/lib/common/threading.h @@ -0,0 +1,150 @@ +/** + * Copyright (c) 2016 Tino Reichardt + * All rights reserved. + * + * You can contact the author at: + * - zstdmt source repository: https://github.com/mcmilk/zstdmt + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef THREADING_H_938743 +#define THREADING_H_938743 + +#include "debug.h" + +#if defined (__cplusplus) +extern "C" { +#endif + +#if defined(ZSTD_MULTITHREAD) && defined(_WIN32) + +/** + * Windows minimalist Pthread Wrapper + */ +#ifdef WINVER +# undef WINVER +#endif +#define WINVER 0x0600 + +#ifdef _WIN32_WINNT +# undef _WIN32_WINNT +#endif +#define _WIN32_WINNT 0x0600 + +#ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif + +#undef ERROR /* reported already defined on VS 2015 (Rich Geldreich) */ +#include +#undef ERROR +#define ERROR(name) ZSTD_ERROR(name) + + +/* mutex */ +#define ZSTD_pthread_mutex_t CRITICAL_SECTION +#define ZSTD_pthread_mutex_init(a, b) ((void)(b), InitializeCriticalSection((a)), 0) +#define ZSTD_pthread_mutex_destroy(a) DeleteCriticalSection((a)) +#define ZSTD_pthread_mutex_lock(a) EnterCriticalSection((a)) +#define ZSTD_pthread_mutex_unlock(a) LeaveCriticalSection((a)) + +/* condition variable */ +#define ZSTD_pthread_cond_t CONDITION_VARIABLE +#define ZSTD_pthread_cond_init(a, b) ((void)(b), InitializeConditionVariable((a)), 0) +#define ZSTD_pthread_cond_destroy(a) ((void)(a)) +#define ZSTD_pthread_cond_wait(a, b) SleepConditionVariableCS((a), (b), INFINITE) +#define ZSTD_pthread_cond_signal(a) WakeConditionVariable((a)) +#define ZSTD_pthread_cond_broadcast(a) WakeAllConditionVariable((a)) + +/* ZSTD_pthread_create() and ZSTD_pthread_join() */ +typedef HANDLE ZSTD_pthread_t; + +int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused, + void* (*start_routine) (void*), void* arg); + +int ZSTD_pthread_join(ZSTD_pthread_t thread); + +/** + * add here more wrappers as required + */ + + +#elif defined(ZSTD_MULTITHREAD) /* posix assumed ; need a better detection method */ +/* === POSIX Systems === */ +# include + +#if DEBUGLEVEL < 1 + +#define ZSTD_pthread_mutex_t pthread_mutex_t +#define ZSTD_pthread_mutex_init(a, b) pthread_mutex_init((a), (b)) +#define ZSTD_pthread_mutex_destroy(a) pthread_mutex_destroy((a)) +#define ZSTD_pthread_mutex_lock(a) pthread_mutex_lock((a)) +#define ZSTD_pthread_mutex_unlock(a) pthread_mutex_unlock((a)) + +#define ZSTD_pthread_cond_t pthread_cond_t +#define ZSTD_pthread_cond_init(a, b) pthread_cond_init((a), (b)) +#define ZSTD_pthread_cond_destroy(a) pthread_cond_destroy((a)) +#define ZSTD_pthread_cond_wait(a, b) pthread_cond_wait((a), (b)) +#define ZSTD_pthread_cond_signal(a) pthread_cond_signal((a)) +#define ZSTD_pthread_cond_broadcast(a) pthread_cond_broadcast((a)) + +#define ZSTD_pthread_t pthread_t +#define ZSTD_pthread_create(a, b, c, d) pthread_create((a), (b), (c), (d)) +#define ZSTD_pthread_join(a) pthread_join((a),NULL) + +#else /* DEBUGLEVEL >= 1 */ + +/* Debug implementation of threading. + * In this implementation we use pointers for mutexes and condition variables. + * This way, if we forget to init/destroy them the program will crash or ASAN + * will report leaks. + */ + +#define ZSTD_pthread_mutex_t pthread_mutex_t* +int ZSTD_pthread_mutex_init(ZSTD_pthread_mutex_t* mutex, pthread_mutexattr_t const* attr); +int ZSTD_pthread_mutex_destroy(ZSTD_pthread_mutex_t* mutex); +#define ZSTD_pthread_mutex_lock(a) pthread_mutex_lock(*(a)) +#define ZSTD_pthread_mutex_unlock(a) pthread_mutex_unlock(*(a)) + +#define ZSTD_pthread_cond_t pthread_cond_t* +int ZSTD_pthread_cond_init(ZSTD_pthread_cond_t* cond, pthread_condattr_t const* attr); +int ZSTD_pthread_cond_destroy(ZSTD_pthread_cond_t* cond); +#define ZSTD_pthread_cond_wait(a, b) pthread_cond_wait(*(a), *(b)) +#define ZSTD_pthread_cond_signal(a) pthread_cond_signal(*(a)) +#define ZSTD_pthread_cond_broadcast(a) pthread_cond_broadcast(*(a)) + +#define ZSTD_pthread_t pthread_t +#define ZSTD_pthread_create(a, b, c, d) pthread_create((a), (b), (c), (d)) +#define ZSTD_pthread_join(a) pthread_join((a),NULL) + +#endif + +#else /* ZSTD_MULTITHREAD not defined */ +/* No multithreading support */ + +typedef int ZSTD_pthread_mutex_t; +#define ZSTD_pthread_mutex_init(a, b) ((void)(a), (void)(b), 0) +#define ZSTD_pthread_mutex_destroy(a) ((void)(a)) +#define ZSTD_pthread_mutex_lock(a) ((void)(a)) +#define ZSTD_pthread_mutex_unlock(a) ((void)(a)) + +typedef int ZSTD_pthread_cond_t; +#define ZSTD_pthread_cond_init(a, b) ((void)(a), (void)(b), 0) +#define ZSTD_pthread_cond_destroy(a) ((void)(a)) +#define ZSTD_pthread_cond_wait(a, b) ((void)(a), (void)(b)) +#define ZSTD_pthread_cond_signal(a) ((void)(a)) +#define ZSTD_pthread_cond_broadcast(a) ((void)(a)) + +/* do not use ZSTD_pthread_t */ + +#endif /* ZSTD_MULTITHREAD */ + +#if defined (__cplusplus) +} +#endif + +#endif /* THREADING_H_938743 */ diff --git a/lib/zstd/lib/common/xxhash.c b/lib/zstd/lib/common/xxhash.c new file mode 100644 index 0000000..fd237c9 --- /dev/null +++ b/lib/zstd/lib/common/xxhash.c @@ -0,0 +1,24 @@ +/* + * xxHash - Fast Hash algorithm + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * You can contact the author at : + * - xxHash homepage: https://cyan4973.github.io/xxHash/ + * - xxHash source repository : https://github.com/Cyan4973/xxHash + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +*/ + + + +/* + * xxhash.c instantiates functions defined in xxhash.h + */ + +#define XXH_STATIC_LINKING_ONLY /* access advanced declarations */ +#define XXH_IMPLEMENTATION /* access definitions */ + +#include "xxhash.h" diff --git a/lib/zstd/lib/common/xxhash.h b/lib/zstd/lib/common/xxhash.h new file mode 100644 index 0000000..b8b7329 --- /dev/null +++ b/lib/zstd/lib/common/xxhash.h @@ -0,0 +1,5686 @@ +/* + * xxHash - Fast Hash algorithm + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * You can contact the author at : + * - xxHash homepage: https://cyan4973.github.io/xxHash/ + * - xxHash source repository : https://github.com/Cyan4973/xxHash + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +*/ + + +#ifndef XXH_NO_XXH3 +# define XXH_NO_XXH3 +#endif + +#ifndef XXH_NAMESPACE +# define XXH_NAMESPACE ZSTD_ +#endif + +/*! + * @mainpage xxHash + * + * @file xxhash.h + * xxHash prototypes and implementation + */ +/* TODO: update */ +/* Notice extracted from xxHash homepage: + +xxHash is an extremely fast hash algorithm, running at RAM speed limits. +It also successfully passes all tests from the SMHasher suite. + +Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz) + +Name Speed Q.Score Author +xxHash 5.4 GB/s 10 +CrapWow 3.2 GB/s 2 Andrew +MurmurHash 3a 2.7 GB/s 10 Austin Appleby +SpookyHash 2.0 GB/s 10 Bob Jenkins +SBox 1.4 GB/s 9 Bret Mulvey +Lookup3 1.2 GB/s 9 Bob Jenkins +SuperFastHash 1.2 GB/s 1 Paul Hsieh +CityHash64 1.05 GB/s 10 Pike & Alakuijala +FNV 0.55 GB/s 5 Fowler, Noll, Vo +CRC32 0.43 GB/s 9 +MD5-32 0.33 GB/s 10 Ronald L. Rivest +SHA1-32 0.28 GB/s 10 + +Q.Score is a measure of quality of the hash function. +It depends on successfully passing SMHasher test set. +10 is a perfect score. + +Note: SMHasher's CRC32 implementation is not the fastest one. +Other speed-oriented implementations can be faster, +especially in combination with PCLMUL instruction: +https://fastcompression.blogspot.com/2019/03/presenting-xxh3.html?showComment=1552696407071#c3490092340461170735 + +A 64-bit version, named XXH64, is available since r35. +It offers much better speed, but for 64-bit applications only. +Name Speed on 64 bits Speed on 32 bits +XXH64 13.8 GB/s 1.9 GB/s +XXH32 6.8 GB/s 6.0 GB/s +*/ + +#if defined (__cplusplus) +extern "C" { +#endif + +/* **************************** + * INLINE mode + ******************************/ +/*! + * XXH_INLINE_ALL (and XXH_PRIVATE_API) + * Use these build macros to inline xxhash into the target unit. + * Inlining improves performance on small inputs, especially when the length is + * expressed as a compile-time constant: + * + * https://fastcompression.blogspot.com/2018/03/xxhash-for-small-keys-impressive-power.html + * + * It also keeps xxHash symbols private to the unit, so they are not exported. + * + * Usage: + * #define XXH_INLINE_ALL + * #include "xxhash.h" + * + * Do not compile and link xxhash.o as a separate object, as it is not useful. + */ +#if (defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)) \ + && !defined(XXH_INLINE_ALL_31684351384) + /* this section should be traversed only once */ +# define XXH_INLINE_ALL_31684351384 + /* give access to the advanced API, required to compile implementations */ +# undef XXH_STATIC_LINKING_ONLY /* avoid macro redef */ +# define XXH_STATIC_LINKING_ONLY + /* make all functions private */ +# undef XXH_PUBLIC_API +# if defined(__GNUC__) +# define XXH_PUBLIC_API static __inline __attribute__((unused)) +# elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) +# define XXH_PUBLIC_API static inline +# elif defined(_MSC_VER) +# define XXH_PUBLIC_API static __inline +# else + /* note: this version may generate warnings for unused static functions */ +# define XXH_PUBLIC_API static +# endif + + /* + * This part deals with the special case where a unit wants to inline xxHash, + * but "xxhash.h" has previously been included without XXH_INLINE_ALL, + * such as part of some previously included *.h header file. + * Without further action, the new include would just be ignored, + * and functions would effectively _not_ be inlined (silent failure). + * The following macros solve this situation by prefixing all inlined names, + * avoiding naming collision with previous inclusions. + */ + /* Before that, we unconditionally #undef all symbols, + * in case they were already defined with XXH_NAMESPACE. + * They will then be redefined for XXH_INLINE_ALL + */ +# undef XXH_versionNumber + /* XXH32 */ +# undef XXH32 +# undef XXH32_createState +# undef XXH32_freeState +# undef XXH32_reset +# undef XXH32_update +# undef XXH32_digest +# undef XXH32_copyState +# undef XXH32_canonicalFromHash +# undef XXH32_hashFromCanonical + /* XXH64 */ +# undef XXH64 +# undef XXH64_createState +# undef XXH64_freeState +# undef XXH64_reset +# undef XXH64_update +# undef XXH64_digest +# undef XXH64_copyState +# undef XXH64_canonicalFromHash +# undef XXH64_hashFromCanonical + /* XXH3_64bits */ +# undef XXH3_64bits +# undef XXH3_64bits_withSecret +# undef XXH3_64bits_withSeed +# undef XXH3_64bits_withSecretandSeed +# undef XXH3_createState +# undef XXH3_freeState +# undef XXH3_copyState +# undef XXH3_64bits_reset +# undef XXH3_64bits_reset_withSeed +# undef XXH3_64bits_reset_withSecret +# undef XXH3_64bits_update +# undef XXH3_64bits_digest +# undef XXH3_generateSecret + /* XXH3_128bits */ +# undef XXH128 +# undef XXH3_128bits +# undef XXH3_128bits_withSeed +# undef XXH3_128bits_withSecret +# undef XXH3_128bits_reset +# undef XXH3_128bits_reset_withSeed +# undef XXH3_128bits_reset_withSecret +# undef XXH3_128bits_reset_withSecretandSeed +# undef XXH3_128bits_update +# undef XXH3_128bits_digest +# undef XXH128_isEqual +# undef XXH128_cmp +# undef XXH128_canonicalFromHash +# undef XXH128_hashFromCanonical + /* Finally, free the namespace itself */ +# undef XXH_NAMESPACE + + /* employ the namespace for XXH_INLINE_ALL */ +# define XXH_NAMESPACE XXH_INLINE_ + /* + * Some identifiers (enums, type names) are not symbols, + * but they must nonetheless be renamed to avoid redeclaration. + * Alternative solution: do not redeclare them. + * However, this requires some #ifdefs, and has a more dispersed impact. + * Meanwhile, renaming can be achieved in a single place. + */ +# define XXH_IPREF(Id) XXH_NAMESPACE ## Id +# define XXH_OK XXH_IPREF(XXH_OK) +# define XXH_ERROR XXH_IPREF(XXH_ERROR) +# define XXH_errorcode XXH_IPREF(XXH_errorcode) +# define XXH32_canonical_t XXH_IPREF(XXH32_canonical_t) +# define XXH64_canonical_t XXH_IPREF(XXH64_canonical_t) +# define XXH128_canonical_t XXH_IPREF(XXH128_canonical_t) +# define XXH32_state_s XXH_IPREF(XXH32_state_s) +# define XXH32_state_t XXH_IPREF(XXH32_state_t) +# define XXH64_state_s XXH_IPREF(XXH64_state_s) +# define XXH64_state_t XXH_IPREF(XXH64_state_t) +# define XXH3_state_s XXH_IPREF(XXH3_state_s) +# define XXH3_state_t XXH_IPREF(XXH3_state_t) +# define XXH128_hash_t XXH_IPREF(XXH128_hash_t) + /* Ensure the header is parsed again, even if it was previously included */ +# undef XXHASH_H_5627135585666179 +# undef XXHASH_H_STATIC_13879238742 +#endif /* XXH_INLINE_ALL || XXH_PRIVATE_API */ + + + +/* **************************************************************** + * Stable API + *****************************************************************/ +#ifndef XXHASH_H_5627135585666179 +#define XXHASH_H_5627135585666179 1 + + +/*! + * @defgroup public Public API + * Contains details on the public xxHash functions. + * @{ + */ +/* specific declaration modes for Windows */ +#if !defined(XXH_INLINE_ALL) && !defined(XXH_PRIVATE_API) +# if defined(WIN32) && defined(_MSC_VER) && (defined(XXH_IMPORT) || defined(XXH_EXPORT)) +# ifdef XXH_EXPORT +# define XXH_PUBLIC_API __declspec(dllexport) +# elif XXH_IMPORT +# define XXH_PUBLIC_API __declspec(dllimport) +# endif +# else +# define XXH_PUBLIC_API /* do nothing */ +# endif +#endif + +#ifdef XXH_DOXYGEN +/*! + * @brief Emulate a namespace by transparently prefixing all symbols. + * + * If you want to include _and expose_ xxHash functions from within your own + * library, but also want to avoid symbol collisions with other libraries which + * may also include xxHash, you can use XXH_NAMESPACE to automatically prefix + * any public symbol from xxhash library with the value of XXH_NAMESPACE + * (therefore, avoid empty or numeric values). + * + * Note that no change is required within the calling program as long as it + * includes `xxhash.h`: Regular symbol names will be automatically translated + * by this header. + */ +# define XXH_NAMESPACE /* YOUR NAME HERE */ +# undef XXH_NAMESPACE +#endif + +#ifdef XXH_NAMESPACE +# define XXH_CAT(A,B) A##B +# define XXH_NAME2(A,B) XXH_CAT(A,B) +# define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber) +/* XXH32 */ +# define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32) +# define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState) +# define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState) +# define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset) +# define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update) +# define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest) +# define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState) +# define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash) +# define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical) +/* XXH64 */ +# define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64) +# define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState) +# define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState) +# define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset) +# define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update) +# define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest) +# define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState) +# define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash) +# define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical) +/* XXH3_64bits */ +# define XXH3_64bits XXH_NAME2(XXH_NAMESPACE, XXH3_64bits) +# define XXH3_64bits_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSecret) +# define XXH3_64bits_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSeed) +# define XXH3_64bits_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSecretandSeed) +# define XXH3_createState XXH_NAME2(XXH_NAMESPACE, XXH3_createState) +# define XXH3_freeState XXH_NAME2(XXH_NAMESPACE, XXH3_freeState) +# define XXH3_copyState XXH_NAME2(XXH_NAMESPACE, XXH3_copyState) +# define XXH3_64bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset) +# define XXH3_64bits_reset_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSeed) +# define XXH3_64bits_reset_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSecret) +# define XXH3_64bits_reset_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSecretandSeed) +# define XXH3_64bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_update) +# define XXH3_64bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_digest) +# define XXH3_generateSecret XXH_NAME2(XXH_NAMESPACE, XXH3_generateSecret) +# define XXH3_generateSecret_fromSeed XXH_NAME2(XXH_NAMESPACE, XXH3_generateSecret_fromSeed) +/* XXH3_128bits */ +# define XXH128 XXH_NAME2(XXH_NAMESPACE, XXH128) +# define XXH3_128bits XXH_NAME2(XXH_NAMESPACE, XXH3_128bits) +# define XXH3_128bits_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSeed) +# define XXH3_128bits_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSecret) +# define XXH3_128bits_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSecretandSeed) +# define XXH3_128bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset) +# define XXH3_128bits_reset_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSeed) +# define XXH3_128bits_reset_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSecret) +# define XXH3_128bits_reset_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSecretandSeed) +# define XXH3_128bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_update) +# define XXH3_128bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_digest) +# define XXH128_isEqual XXH_NAME2(XXH_NAMESPACE, XXH128_isEqual) +# define XXH128_cmp XXH_NAME2(XXH_NAMESPACE, XXH128_cmp) +# define XXH128_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH128_canonicalFromHash) +# define XXH128_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH128_hashFromCanonical) +#endif + + +/* ************************************* +* Version +***************************************/ +#define XXH_VERSION_MAJOR 0 +#define XXH_VERSION_MINOR 8 +#define XXH_VERSION_RELEASE 1 +#define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE) + +/*! + * @brief Obtains the xxHash version. + * + * This is mostly useful when xxHash is compiled as a shared library, + * since the returned value comes from the library, as opposed to header file. + * + * @return `XXH_VERSION_NUMBER` of the invoked library. + */ +XXH_PUBLIC_API unsigned XXH_versionNumber (void); + + +/* **************************** +* Common basic types +******************************/ +#include /* size_t */ +typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode; + + +/*-********************************************************************** +* 32-bit hash +************************************************************************/ +#if defined(XXH_DOXYGEN) /* Don't show include */ +/*! + * @brief An unsigned 32-bit integer. + * + * Not necessarily defined to `uint32_t` but functionally equivalent. + */ +typedef uint32_t XXH32_hash_t; + +#elif !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) +# include + typedef uint32_t XXH32_hash_t; + +#else +# include +# if UINT_MAX == 0xFFFFFFFFUL + typedef unsigned int XXH32_hash_t; +# else +# if ULONG_MAX == 0xFFFFFFFFUL + typedef unsigned long XXH32_hash_t; +# else +# error "unsupported platform: need a 32-bit type" +# endif +# endif +#endif + +/*! + * @} + * + * @defgroup xxh32_family XXH32 family + * @ingroup public + * Contains functions used in the classic 32-bit xxHash algorithm. + * + * @note + * XXH32 is useful for older platforms, with no or poor 64-bit performance. + * Note that @ref xxh3_family provides competitive speed + * for both 32-bit and 64-bit systems, and offers true 64/128 bit hash results. + * + * @see @ref xxh64_family, @ref xxh3_family : Other xxHash families + * @see @ref xxh32_impl for implementation details + * @{ + */ + +/*! + * @brief Calculates the 32-bit hash of @p input using xxHash32. + * + * Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark): 5.4 GB/s + * + * @param input The block of data to be hashed, at least @p length bytes in size. + * @param length The length of @p input, in bytes. + * @param seed The 32-bit seed to alter the hash's output predictably. + * + * @pre + * The memory between @p input and @p input + @p length must be valid, + * readable, contiguous memory. However, if @p length is `0`, @p input may be + * `NULL`. In C++, this also must be *TriviallyCopyable*. + * + * @return The calculated 32-bit hash value. + * + * @see + * XXH64(), XXH3_64bits_withSeed(), XXH3_128bits_withSeed(), XXH128(): + * Direct equivalents for the other variants of xxHash. + * @see + * XXH32_createState(), XXH32_update(), XXH32_digest(): Streaming version. + */ +XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, XXH32_hash_t seed); + +/*! + * Streaming functions generate the xxHash value from an incremental input. + * This method is slower than single-call functions, due to state management. + * For small inputs, prefer `XXH32()` and `XXH64()`, which are better optimized. + * + * An XXH state must first be allocated using `XXH*_createState()`. + * + * Start a new hash by initializing the state with a seed using `XXH*_reset()`. + * + * Then, feed the hash state by calling `XXH*_update()` as many times as necessary. + * + * The function returns an error code, with 0 meaning OK, and any other value + * meaning there is an error. + * + * Finally, a hash value can be produced anytime, by using `XXH*_digest()`. + * This function returns the nn-bits hash as an int or long long. + * + * It's still possible to continue inserting input into the hash state after a + * digest, and generate new hash values later on by invoking `XXH*_digest()`. + * + * When done, release the state using `XXH*_freeState()`. + * + * Example code for incrementally hashing a file: + * @code{.c} + * #include + * #include + * #define BUFFER_SIZE 256 + * + * // Note: XXH64 and XXH3 use the same interface. + * XXH32_hash_t + * hashFile(FILE* stream) + * { + * XXH32_state_t* state; + * unsigned char buf[BUFFER_SIZE]; + * size_t amt; + * XXH32_hash_t hash; + * + * state = XXH32_createState(); // Create a state + * assert(state != NULL); // Error check here + * XXH32_reset(state, 0xbaad5eed); // Reset state with our seed + * while ((amt = fread(buf, 1, sizeof(buf), stream)) != 0) { + * XXH32_update(state, buf, amt); // Hash the file in chunks + * } + * hash = XXH32_digest(state); // Finalize the hash + * XXH32_freeState(state); // Clean up + * return hash; + * } + * @endcode + */ + +/*! + * @typedef struct XXH32_state_s XXH32_state_t + * @brief The opaque state struct for the XXH32 streaming API. + * + * @see XXH32_state_s for details. + */ +typedef struct XXH32_state_s XXH32_state_t; + +/*! + * @brief Allocates an @ref XXH32_state_t. + * + * Must be freed with XXH32_freeState(). + * @return An allocated XXH32_state_t on success, `NULL` on failure. + */ +XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void); +/*! + * @brief Frees an @ref XXH32_state_t. + * + * Must be allocated with XXH32_createState(). + * @param statePtr A pointer to an @ref XXH32_state_t allocated with @ref XXH32_createState(). + * @return XXH_OK. + */ +XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr); +/*! + * @brief Copies one @ref XXH32_state_t to another. + * + * @param dst_state The state to copy to. + * @param src_state The state to copy from. + * @pre + * @p dst_state and @p src_state must not be `NULL` and must not overlap. + */ +XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state); + +/*! + * @brief Resets an @ref XXH32_state_t to begin a new hash. + * + * This function resets and seeds a state. Call it before @ref XXH32_update(). + * + * @param statePtr The state struct to reset. + * @param seed The 32-bit seed to alter the hash result predictably. + * + * @pre + * @p statePtr must not be `NULL`. + * + * @return @ref XXH_OK on success, @ref XXH_ERROR on failure. + */ +XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, XXH32_hash_t seed); + +/*! + * @brief Consumes a block of @p input to an @ref XXH32_state_t. + * + * Call this to incrementally consume blocks of data. + * + * @param statePtr The state struct to update. + * @param input The block of data to be hashed, at least @p length bytes in size. + * @param length The length of @p input, in bytes. + * + * @pre + * @p statePtr must not be `NULL`. + * @pre + * The memory between @p input and @p input + @p length must be valid, + * readable, contiguous memory. However, if @p length is `0`, @p input may be + * `NULL`. In C++, this also must be *TriviallyCopyable*. + * + * @return @ref XXH_OK on success, @ref XXH_ERROR on failure. + */ +XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length); + +/*! + * @brief Returns the calculated hash value from an @ref XXH32_state_t. + * + * @note + * Calling XXH32_digest() will not affect @p statePtr, so you can update, + * digest, and update again. + * + * @param statePtr The state struct to calculate the hash from. + * + * @pre + * @p statePtr must not be `NULL`. + * + * @return The calculated xxHash32 value from that state. + */ +XXH_PUBLIC_API XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr); + +/******* Canonical representation *******/ + +/* + * The default return values from XXH functions are unsigned 32 and 64 bit + * integers. + * This the simplest and fastest format for further post-processing. + * + * However, this leaves open the question of what is the order on the byte level, + * since little and big endian conventions will store the same number differently. + * + * The canonical representation settles this issue by mandating big-endian + * convention, the same convention as human-readable numbers (large digits first). + * + * When writing hash values to storage, sending them over a network, or printing + * them, it's highly recommended to use the canonical representation to ensure + * portability across a wider range of systems, present and future. + * + * The following functions allow transformation of hash values to and from + * canonical format. + */ + +/*! + * @brief Canonical (big endian) representation of @ref XXH32_hash_t. + */ +typedef struct { + unsigned char digest[4]; /*!< Hash bytes, big endian */ +} XXH32_canonical_t; + +/*! + * @brief Converts an @ref XXH32_hash_t to a big endian @ref XXH32_canonical_t. + * + * @param dst The @ref XXH32_canonical_t pointer to be stored to. + * @param hash The @ref XXH32_hash_t to be converted. + * + * @pre + * @p dst must not be `NULL`. + */ +XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash); + +/*! + * @brief Converts an @ref XXH32_canonical_t to a native @ref XXH32_hash_t. + * + * @param src The @ref XXH32_canonical_t to convert. + * + * @pre + * @p src must not be `NULL`. + * + * @return The converted hash. + */ +XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src); + + +#ifdef __has_attribute +# define XXH_HAS_ATTRIBUTE(x) __has_attribute(x) +#else +# define XXH_HAS_ATTRIBUTE(x) 0 +#endif + +/* C-language Attributes are added in C23. */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ > 201710L) && defined(__has_c_attribute) +# define XXH_HAS_C_ATTRIBUTE(x) __has_c_attribute(x) +#else +# define XXH_HAS_C_ATTRIBUTE(x) 0 +#endif + +#if defined(__cplusplus) && defined(__has_cpp_attribute) +# define XXH_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +# define XXH_HAS_CPP_ATTRIBUTE(x) 0 +#endif + +/* +Define XXH_FALLTHROUGH macro for annotating switch case with the 'fallthrough' attribute +introduced in CPP17 and C23. +CPP17 : https://en.cppreference.com/w/cpp/language/attributes/fallthrough +C23 : https://en.cppreference.com/w/c/language/attributes/fallthrough +*/ +#if XXH_HAS_C_ATTRIBUTE(x) +# define XXH_FALLTHROUGH [[fallthrough]] +#elif XXH_HAS_CPP_ATTRIBUTE(x) +# define XXH_FALLTHROUGH [[fallthrough]] +#elif XXH_HAS_ATTRIBUTE(__fallthrough__) +# define XXH_FALLTHROUGH __attribute__ ((fallthrough)) +#else +# define XXH_FALLTHROUGH +#endif + +/*! + * @} + * @ingroup public + * @{ + */ + +#ifndef XXH_NO_LONG_LONG +/*-********************************************************************** +* 64-bit hash +************************************************************************/ +#if defined(XXH_DOXYGEN) /* don't include */ +/*! + * @brief An unsigned 64-bit integer. + * + * Not necessarily defined to `uint64_t` but functionally equivalent. + */ +typedef uint64_t XXH64_hash_t; +#elif !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) +# include + typedef uint64_t XXH64_hash_t; +#else +# include +# if defined(__LP64__) && ULONG_MAX == 0xFFFFFFFFFFFFFFFFULL + /* LP64 ABI says uint64_t is unsigned long */ + typedef unsigned long XXH64_hash_t; +# else + /* the following type must have a width of 64-bit */ + typedef unsigned long long XXH64_hash_t; +# endif +#endif + +/*! + * @} + * + * @defgroup xxh64_family XXH64 family + * @ingroup public + * @{ + * Contains functions used in the classic 64-bit xxHash algorithm. + * + * @note + * XXH3 provides competitive speed for both 32-bit and 64-bit systems, + * and offers true 64/128 bit hash results. + * It provides better speed for systems with vector processing capabilities. + */ + + +/*! + * @brief Calculates the 64-bit hash of @p input using xxHash64. + * + * This function usually runs faster on 64-bit systems, but slower on 32-bit + * systems (see benchmark). + * + * @param input The block of data to be hashed, at least @p length bytes in size. + * @param length The length of @p input, in bytes. + * @param seed The 64-bit seed to alter the hash's output predictably. + * + * @pre + * The memory between @p input and @p input + @p length must be valid, + * readable, contiguous memory. However, if @p length is `0`, @p input may be + * `NULL`. In C++, this also must be *TriviallyCopyable*. + * + * @return The calculated 64-bit hash. + * + * @see + * XXH32(), XXH3_64bits_withSeed(), XXH3_128bits_withSeed(), XXH128(): + * Direct equivalents for the other variants of xxHash. + * @see + * XXH64_createState(), XXH64_update(), XXH64_digest(): Streaming version. + */ +XXH_PUBLIC_API XXH64_hash_t XXH64(const void* input, size_t length, XXH64_hash_t seed); + +/******* Streaming *******/ +/*! + * @brief The opaque state struct for the XXH64 streaming API. + * + * @see XXH64_state_s for details. + */ +typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */ +XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void); +XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr); +XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dst_state, const XXH64_state_t* src_state); + +XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, XXH64_hash_t seed); +XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length); +XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* statePtr); + +/******* Canonical representation *******/ +typedef struct { unsigned char digest[sizeof(XXH64_hash_t)]; } XXH64_canonical_t; +XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash); +XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src); + +#ifndef XXH_NO_XXH3 +/*! + * @} + * ************************************************************************ + * @defgroup xxh3_family XXH3 family + * @ingroup public + * @{ + * + * XXH3 is a more recent hash algorithm featuring: + * - Improved speed for both small and large inputs + * - True 64-bit and 128-bit outputs + * - SIMD acceleration + * - Improved 32-bit viability + * + * Speed analysis methodology is explained here: + * + * https://fastcompression.blogspot.com/2019/03/presenting-xxh3.html + * + * Compared to XXH64, expect XXH3 to run approximately + * ~2x faster on large inputs and >3x faster on small ones, + * exact differences vary depending on platform. + * + * XXH3's speed benefits greatly from SIMD and 64-bit arithmetic, + * but does not require it. + * Any 32-bit and 64-bit targets that can run XXH32 smoothly + * can run XXH3 at competitive speeds, even without vector support. + * Further details are explained in the implementation. + * + * Optimized implementations are provided for AVX512, AVX2, SSE2, NEON, POWER8, + * ZVector and scalar targets. This can be controlled via the XXH_VECTOR macro. + * + * XXH3 implementation is portable: + * it has a generic C90 formulation that can be compiled on any platform, + * all implementations generage exactly the same hash value on all platforms. + * Starting from v0.8.0, it's also labelled "stable", meaning that + * any future version will also generate the same hash value. + * + * XXH3 offers 2 variants, _64bits and _128bits. + * + * When only 64 bits are needed, prefer invoking the _64bits variant, as it + * reduces the amount of mixing, resulting in faster speed on small inputs. + * It's also generally simpler to manipulate a scalar return type than a struct. + * + * The API supports one-shot hashing, streaming mode, and custom secrets. + */ + +/*-********************************************************************** +* XXH3 64-bit variant +************************************************************************/ + +/* XXH3_64bits(): + * default 64-bit variant, using default secret and default seed of 0. + * It's the fastest variant. */ +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits(const void* data, size_t len); + +/* + * XXH3_64bits_withSeed(): + * This variant generates a custom secret on the fly + * based on default secret altered using the `seed` value. + * While this operation is decently fast, note that it's not completely free. + * Note: seed==0 produces the same results as XXH3_64bits(). + */ +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSeed(const void* data, size_t len, XXH64_hash_t seed); + +/*! + * The bare minimum size for a custom secret. + * + * @see + * XXH3_64bits_withSecret(), XXH3_64bits_reset_withSecret(), + * XXH3_128bits_withSecret(), XXH3_128bits_reset_withSecret(). + */ +#define XXH3_SECRET_SIZE_MIN 136 + +/* + * XXH3_64bits_withSecret(): + * It's possible to provide any blob of bytes as a "secret" to generate the hash. + * This makes it more difficult for an external actor to prepare an intentional collision. + * The main condition is that secretSize *must* be large enough (>= XXH3_SECRET_SIZE_MIN). + * However, the quality of the secret impacts the dispersion of the hash algorithm. + * Therefore, the secret _must_ look like a bunch of random bytes. + * Avoid "trivial" or structured data such as repeated sequences or a text document. + * Whenever in doubt about the "randomness" of the blob of bytes, + * consider employing "XXH3_generateSecret()" instead (see below). + * It will generate a proper high entropy secret derived from the blob of bytes. + * Another advantage of using XXH3_generateSecret() is that + * it guarantees that all bits within the initial blob of bytes + * will impact every bit of the output. + * This is not necessarily the case when using the blob of bytes directly + * because, when hashing _small_ inputs, only a portion of the secret is employed. + */ +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSecret(const void* data, size_t len, const void* secret, size_t secretSize); + + +/******* Streaming *******/ +/* + * Streaming requires state maintenance. + * This operation costs memory and CPU. + * As a consequence, streaming is slower than one-shot hashing. + * For better performance, prefer one-shot functions whenever applicable. + */ + +/*! + * @brief The state struct for the XXH3 streaming API. + * + * @see XXH3_state_s for details. + */ +typedef struct XXH3_state_s XXH3_state_t; +XXH_PUBLIC_API XXH3_state_t* XXH3_createState(void); +XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr); +XXH_PUBLIC_API void XXH3_copyState(XXH3_state_t* dst_state, const XXH3_state_t* src_state); + +/* + * XXH3_64bits_reset(): + * Initialize with default parameters. + * digest will be equivalent to `XXH3_64bits()`. + */ +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset(XXH3_state_t* statePtr); +/* + * XXH3_64bits_reset_withSeed(): + * Generate a custom secret from `seed`, and store it into `statePtr`. + * digest will be equivalent to `XXH3_64bits_withSeed()`. + */ +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed); +/* + * XXH3_64bits_reset_withSecret(): + * `secret` is referenced, it _must outlive_ the hash streaming session. + * Similar to one-shot API, `secretSize` must be >= `XXH3_SECRET_SIZE_MIN`, + * and the quality of produced hash values depends on secret's entropy + * (secret's content should look like a bunch of random bytes). + * When in doubt about the randomness of a candidate `secret`, + * consider employing `XXH3_generateSecret()` instead (see below). + */ +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize); + +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_update (XXH3_state_t* statePtr, const void* input, size_t length); +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest (const XXH3_state_t* statePtr); + +/* note : canonical representation of XXH3 is the same as XXH64 + * since they both produce XXH64_hash_t values */ + + +/*-********************************************************************** +* XXH3 128-bit variant +************************************************************************/ + +/*! + * @brief The return value from 128-bit hashes. + * + * Stored in little endian order, although the fields themselves are in native + * endianness. + */ +typedef struct { + XXH64_hash_t low64; /*!< `value & 0xFFFFFFFFFFFFFFFF` */ + XXH64_hash_t high64; /*!< `value >> 64` */ +} XXH128_hash_t; + +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits(const void* data, size_t len); +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSeed(const void* data, size_t len, XXH64_hash_t seed); +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSecret(const void* data, size_t len, const void* secret, size_t secretSize); + +/******* Streaming *******/ +/* + * Streaming requires state maintenance. + * This operation costs memory and CPU. + * As a consequence, streaming is slower than one-shot hashing. + * For better performance, prefer one-shot functions whenever applicable. + * + * XXH3_128bits uses the same XXH3_state_t as XXH3_64bits(). + * Use already declared XXH3_createState() and XXH3_freeState(). + * + * All reset and streaming functions have same meaning as their 64-bit counterpart. + */ + +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset(XXH3_state_t* statePtr); +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed); +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize); + +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_update (XXH3_state_t* statePtr, const void* input, size_t length); +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest (const XXH3_state_t* statePtr); + +/* Following helper functions make it possible to compare XXH128_hast_t values. + * Since XXH128_hash_t is a structure, this capability is not offered by the language. + * Note: For better performance, these functions can be inlined using XXH_INLINE_ALL */ + +/*! + * XXH128_isEqual(): + * Return: 1 if `h1` and `h2` are equal, 0 if they are not. + */ +XXH_PUBLIC_API int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2); + +/*! + * XXH128_cmp(): + * + * This comparator is compatible with stdlib's `qsort()`/`bsearch()`. + * + * return: >0 if *h128_1 > *h128_2 + * =0 if *h128_1 == *h128_2 + * <0 if *h128_1 < *h128_2 + */ +XXH_PUBLIC_API int XXH128_cmp(const void* h128_1, const void* h128_2); + + +/******* Canonical representation *******/ +typedef struct { unsigned char digest[sizeof(XXH128_hash_t)]; } XXH128_canonical_t; +XXH_PUBLIC_API void XXH128_canonicalFromHash(XXH128_canonical_t* dst, XXH128_hash_t hash); +XXH_PUBLIC_API XXH128_hash_t XXH128_hashFromCanonical(const XXH128_canonical_t* src); + + +#endif /* !XXH_NO_XXH3 */ +#endif /* XXH_NO_LONG_LONG */ + +/*! + * @} + */ +#endif /* XXHASH_H_5627135585666179 */ + + + +#if defined(XXH_STATIC_LINKING_ONLY) && !defined(XXHASH_H_STATIC_13879238742) +#define XXHASH_H_STATIC_13879238742 +/* **************************************************************************** + * This section contains declarations which are not guaranteed to remain stable. + * They may change in future versions, becoming incompatible with a different + * version of the library. + * These declarations should only be used with static linking. + * Never use them in association with dynamic linking! + ***************************************************************************** */ + +/* + * These definitions are only present to allow static allocation + * of XXH states, on stack or in a struct, for example. + * Never **ever** access their members directly. + */ + +/*! + * @internal + * @brief Structure for XXH32 streaming API. + * + * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY, + * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. Otherwise it is + * an opaque type. This allows fields to safely be changed. + * + * Typedef'd to @ref XXH32_state_t. + * Do not access the members of this struct directly. + * @see XXH64_state_s, XXH3_state_s + */ +struct XXH32_state_s { + XXH32_hash_t total_len_32; /*!< Total length hashed, modulo 2^32 */ + XXH32_hash_t large_len; /*!< Whether the hash is >= 16 (handles @ref total_len_32 overflow) */ + XXH32_hash_t v[4]; /*!< Accumulator lanes */ + XXH32_hash_t mem32[4]; /*!< Internal buffer for partial reads. Treated as unsigned char[16]. */ + XXH32_hash_t memsize; /*!< Amount of data in @ref mem32 */ + XXH32_hash_t reserved; /*!< Reserved field. Do not read nor write to it. */ +}; /* typedef'd to XXH32_state_t */ + + +#ifndef XXH_NO_LONG_LONG /* defined when there is no 64-bit support */ + +/*! + * @internal + * @brief Structure for XXH64 streaming API. + * + * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY, + * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. Otherwise it is + * an opaque type. This allows fields to safely be changed. + * + * Typedef'd to @ref XXH64_state_t. + * Do not access the members of this struct directly. + * @see XXH32_state_s, XXH3_state_s + */ +struct XXH64_state_s { + XXH64_hash_t total_len; /*!< Total length hashed. This is always 64-bit. */ + XXH64_hash_t v[4]; /*!< Accumulator lanes */ + XXH64_hash_t mem64[4]; /*!< Internal buffer for partial reads. Treated as unsigned char[32]. */ + XXH32_hash_t memsize; /*!< Amount of data in @ref mem64 */ + XXH32_hash_t reserved32; /*!< Reserved field, needed for padding anyways*/ + XXH64_hash_t reserved64; /*!< Reserved field. Do not read or write to it. */ +}; /* typedef'd to XXH64_state_t */ + + +#ifndef XXH_NO_XXH3 + +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* >= C11 */ +# include +# define XXH_ALIGN(n) alignas(n) +#elif defined(__cplusplus) && (__cplusplus >= 201103L) /* >= C++11 */ +/* In C++ alignas() is a keyword */ +# define XXH_ALIGN(n) alignas(n) +#elif defined(__GNUC__) +# define XXH_ALIGN(n) __attribute__ ((aligned(n))) +#elif defined(_MSC_VER) +# define XXH_ALIGN(n) __declspec(align(n)) +#else +# define XXH_ALIGN(n) /* disabled */ +#endif + +/* Old GCC versions only accept the attribute after the type in structures. */ +#if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) /* C11+ */ \ + && ! (defined(__cplusplus) && (__cplusplus >= 201103L)) /* >= C++11 */ \ + && defined(__GNUC__) +# define XXH_ALIGN_MEMBER(align, type) type XXH_ALIGN(align) +#else +# define XXH_ALIGN_MEMBER(align, type) XXH_ALIGN(align) type +#endif + +/*! + * @brief The size of the internal XXH3 buffer. + * + * This is the optimal update size for incremental hashing. + * + * @see XXH3_64b_update(), XXH3_128b_update(). + */ +#define XXH3_INTERNALBUFFER_SIZE 256 + +/*! + * @brief Default size of the secret buffer (and @ref XXH3_kSecret). + * + * This is the size used in @ref XXH3_kSecret and the seeded functions. + * + * Not to be confused with @ref XXH3_SECRET_SIZE_MIN. + */ +#define XXH3_SECRET_DEFAULT_SIZE 192 + +/*! + * @internal + * @brief Structure for XXH3 streaming API. + * + * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY, + * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. + * Otherwise it is an opaque type. + * Never use this definition in combination with dynamic library. + * This allows fields to safely be changed in the future. + * + * @note ** This structure has a strict alignment requirement of 64 bytes!! ** + * Do not allocate this with `malloc()` or `new`, + * it will not be sufficiently aligned. + * Use @ref XXH3_createState() and @ref XXH3_freeState(), or stack allocation. + * + * Typedef'd to @ref XXH3_state_t. + * Do never access the members of this struct directly. + * + * @see XXH3_INITSTATE() for stack initialization. + * @see XXH3_createState(), XXH3_freeState(). + * @see XXH32_state_s, XXH64_state_s + */ +struct XXH3_state_s { + XXH_ALIGN_MEMBER(64, XXH64_hash_t acc[8]); + /*!< The 8 accumulators. Similar to `vN` in @ref XXH32_state_s::v1 and @ref XXH64_state_s */ + XXH_ALIGN_MEMBER(64, unsigned char customSecret[XXH3_SECRET_DEFAULT_SIZE]); + /*!< Used to store a custom secret generated from a seed. */ + XXH_ALIGN_MEMBER(64, unsigned char buffer[XXH3_INTERNALBUFFER_SIZE]); + /*!< The internal buffer. @see XXH32_state_s::mem32 */ + XXH32_hash_t bufferedSize; + /*!< The amount of memory in @ref buffer, @see XXH32_state_s::memsize */ + XXH32_hash_t useSeed; + /*!< Reserved field. Needed for padding on 64-bit. */ + size_t nbStripesSoFar; + /*!< Number or stripes processed. */ + XXH64_hash_t totalLen; + /*!< Total length hashed. 64-bit even on 32-bit targets. */ + size_t nbStripesPerBlock; + /*!< Number of stripes per block. */ + size_t secretLimit; + /*!< Size of @ref customSecret or @ref extSecret */ + XXH64_hash_t seed; + /*!< Seed for _withSeed variants. Must be zero otherwise, @see XXH3_INITSTATE() */ + XXH64_hash_t reserved64; + /*!< Reserved field. */ + const unsigned char* extSecret; + /*!< Reference to an external secret for the _withSecret variants, NULL + * for other variants. */ + /* note: there may be some padding at the end due to alignment on 64 bytes */ +}; /* typedef'd to XXH3_state_t */ + +#undef XXH_ALIGN_MEMBER + +/*! + * @brief Initializes a stack-allocated `XXH3_state_s`. + * + * When the @ref XXH3_state_t structure is merely emplaced on stack, + * it should be initialized with XXH3_INITSTATE() or a memset() + * in case its first reset uses XXH3_NNbits_reset_withSeed(). + * This init can be omitted if the first reset uses default or _withSecret mode. + * This operation isn't necessary when the state is created with XXH3_createState(). + * Note that this doesn't prepare the state for a streaming operation, + * it's still necessary to use XXH3_NNbits_reset*() afterwards. + */ +#define XXH3_INITSTATE(XXH3_state_ptr) { (XXH3_state_ptr)->seed = 0; } + + +/* XXH128() : + * simple alias to pre-selected XXH3_128bits variant + */ +XXH_PUBLIC_API XXH128_hash_t XXH128(const void* data, size_t len, XXH64_hash_t seed); + + +/* === Experimental API === */ +/* Symbols defined below must be considered tied to a specific library version. */ + +/* + * XXH3_generateSecret(): + * + * Derive a high-entropy secret from any user-defined content, named customSeed. + * The generated secret can be used in combination with `*_withSecret()` functions. + * The `_withSecret()` variants are useful to provide a higher level of protection than 64-bit seed, + * as it becomes much more difficult for an external actor to guess how to impact the calculation logic. + * + * The function accepts as input a custom seed of any length and any content, + * and derives from it a high-entropy secret of length @secretSize + * into an already allocated buffer @secretBuffer. + * @secretSize must be >= XXH3_SECRET_SIZE_MIN + * + * The generated secret can then be used with any `*_withSecret()` variant. + * Functions `XXH3_128bits_withSecret()`, `XXH3_64bits_withSecret()`, + * `XXH3_128bits_reset_withSecret()` and `XXH3_64bits_reset_withSecret()` + * are part of this list. They all accept a `secret` parameter + * which must be large enough for implementation reasons (>= XXH3_SECRET_SIZE_MIN) + * _and_ feature very high entropy (consist of random-looking bytes). + * These conditions can be a high bar to meet, so + * XXH3_generateSecret() can be employed to ensure proper quality. + * + * customSeed can be anything. It can have any size, even small ones, + * and its content can be anything, even "poor entropy" sources such as a bunch of zeroes. + * The resulting `secret` will nonetheless provide all required qualities. + * + * When customSeedSize > 0, supplying NULL as customSeed is undefined behavior. + */ +XXH_PUBLIC_API XXH_errorcode XXH3_generateSecret(void* secretBuffer, size_t secretSize, const void* customSeed, size_t customSeedSize); + + +/* + * XXH3_generateSecret_fromSeed(): + * + * Generate the same secret as the _withSeed() variants. + * + * The resulting secret has a length of XXH3_SECRET_DEFAULT_SIZE (necessarily). + * @secretBuffer must be already allocated, of size at least XXH3_SECRET_DEFAULT_SIZE bytes. + * + * The generated secret can be used in combination with + *`*_withSecret()` and `_withSecretandSeed()` variants. + * This generator is notably useful in combination with `_withSecretandSeed()`, + * as a way to emulate a faster `_withSeed()` variant. + */ +XXH_PUBLIC_API void XXH3_generateSecret_fromSeed(void* secretBuffer, XXH64_hash_t seed); + +/* + * *_withSecretandSeed() : + * These variants generate hash values using either + * @seed for "short" keys (< XXH3_MIDSIZE_MAX = 240 bytes) + * or @secret for "large" keys (>= XXH3_MIDSIZE_MAX). + * + * This generally benefits speed, compared to `_withSeed()` or `_withSecret()`. + * `_withSeed()` has to generate the secret on the fly for "large" keys. + * It's fast, but can be perceptible for "not so large" keys (< 1 KB). + * `_withSecret()` has to generate the masks on the fly for "small" keys, + * which requires more instructions than _withSeed() variants. + * Therefore, _withSecretandSeed variant combines the best of both worlds. + * + * When @secret has been generated by XXH3_generateSecret_fromSeed(), + * this variant produces *exactly* the same results as `_withSeed()` variant, + * hence offering only a pure speed benefit on "large" input, + * by skipping the need to regenerate the secret for every large input. + * + * Another usage scenario is to hash the secret to a 64-bit hash value, + * for example with XXH3_64bits(), which then becomes the seed, + * and then employ both the seed and the secret in _withSecretandSeed(). + * On top of speed, an added benefit is that each bit in the secret + * has a 50% chance to swap each bit in the output, + * via its impact to the seed. + * This is not guaranteed when using the secret directly in "small data" scenarios, + * because only portions of the secret are employed for small data. + */ +XXH_PUBLIC_API XXH64_hash_t +XXH3_64bits_withSecretandSeed(const void* data, size_t len, + const void* secret, size_t secretSize, + XXH64_hash_t seed); + +XXH_PUBLIC_API XXH128_hash_t +XXH3_128bits_withSecretandSeed(const void* data, size_t len, + const void* secret, size_t secretSize, + XXH64_hash_t seed64); + +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset_withSecretandSeed(XXH3_state_t* statePtr, + const void* secret, size_t secretSize, + XXH64_hash_t seed64); + +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset_withSecretandSeed(XXH3_state_t* statePtr, + const void* secret, size_t secretSize, + XXH64_hash_t seed64); + + +#endif /* XXH_NO_XXH3 */ +#endif /* XXH_NO_LONG_LONG */ +#if defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API) +# define XXH_IMPLEMENTATION +#endif + +#endif /* defined(XXH_STATIC_LINKING_ONLY) && !defined(XXHASH_H_STATIC_13879238742) */ + + +/* ======================================================================== */ +/* ======================================================================== */ +/* ======================================================================== */ + + +/*-********************************************************************** + * xxHash implementation + *-********************************************************************** + * xxHash's implementation used to be hosted inside xxhash.c. + * + * However, inlining requires implementation to be visible to the compiler, + * hence be included alongside the header. + * Previously, implementation was hosted inside xxhash.c, + * which was then #included when inlining was activated. + * This construction created issues with a few build and install systems, + * as it required xxhash.c to be stored in /include directory. + * + * xxHash implementation is now directly integrated within xxhash.h. + * As a consequence, xxhash.c is no longer needed in /include. + * + * xxhash.c is still available and is still useful. + * In a "normal" setup, when xxhash is not inlined, + * xxhash.h only exposes the prototypes and public symbols, + * while xxhash.c can be built into an object file xxhash.o + * which can then be linked into the final binary. + ************************************************************************/ + +#if ( defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API) \ + || defined(XXH_IMPLEMENTATION) ) && !defined(XXH_IMPLEM_13a8737387) +# define XXH_IMPLEM_13a8737387 + +/* ************************************* +* Tuning parameters +***************************************/ + +/*! + * @defgroup tuning Tuning parameters + * @{ + * + * Various macros to control xxHash's behavior. + */ +#ifdef XXH_DOXYGEN +/*! + * @brief Define this to disable 64-bit code. + * + * Useful if only using the @ref xxh32_family and you have a strict C90 compiler. + */ +# define XXH_NO_LONG_LONG +# undef XXH_NO_LONG_LONG /* don't actually */ +/*! + * @brief Controls how unaligned memory is accessed. + * + * By default, access to unaligned memory is controlled by `memcpy()`, which is + * safe and portable. + * + * Unfortunately, on some target/compiler combinations, the generated assembly + * is sub-optimal. + * + * The below switch allow selection of a different access method + * in the search for improved performance. + * + * @par Possible options: + * + * - `XXH_FORCE_MEMORY_ACCESS=0` (default): `memcpy` + * @par + * Use `memcpy()`. Safe and portable. Note that most modern compilers will + * eliminate the function call and treat it as an unaligned access. + * + * - `XXH_FORCE_MEMORY_ACCESS=1`: `__attribute__((packed))` + * @par + * Depends on compiler extensions and is therefore not portable. + * This method is safe _if_ your compiler supports it, + * and *generally* as fast or faster than `memcpy`. + * + * - `XXH_FORCE_MEMORY_ACCESS=2`: Direct cast + * @par + * Casts directly and dereferences. This method doesn't depend on the + * compiler, but it violates the C standard as it directly dereferences an + * unaligned pointer. It can generate buggy code on targets which do not + * support unaligned memory accesses, but in some circumstances, it's the + * only known way to get the most performance. + * + * - `XXH_FORCE_MEMORY_ACCESS=3`: Byteshift + * @par + * Also portable. This can generate the best code on old compilers which don't + * inline small `memcpy()` calls, and it might also be faster on big-endian + * systems which lack a native byteswap instruction. However, some compilers + * will emit literal byteshifts even if the target supports unaligned access. + * . + * + * @warning + * Methods 1 and 2 rely on implementation-defined behavior. Use these with + * care, as what works on one compiler/platform/optimization level may cause + * another to read garbage data or even crash. + * + * See https://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html for details. + * + * Prefer these methods in priority order (0 > 3 > 1 > 2) + */ +# define XXH_FORCE_MEMORY_ACCESS 0 + +/*! + * @def XXH_FORCE_ALIGN_CHECK + * @brief If defined to non-zero, adds a special path for aligned inputs (XXH32() + * and XXH64() only). + * + * This is an important performance trick for architectures without decent + * unaligned memory access performance. + * + * It checks for input alignment, and when conditions are met, uses a "fast + * path" employing direct 32-bit/64-bit reads, resulting in _dramatically + * faster_ read speed. + * + * The check costs one initial branch per hash, which is generally negligible, + * but not zero. + * + * Moreover, it's not useful to generate an additional code path if memory + * access uses the same instruction for both aligned and unaligned + * addresses (e.g. x86 and aarch64). + * + * In these cases, the alignment check can be removed by setting this macro to 0. + * Then the code will always use unaligned memory access. + * Align check is automatically disabled on x86, x64 & arm64, + * which are platforms known to offer good unaligned memory accesses performance. + * + * This option does not affect XXH3 (only XXH32 and XXH64). + */ +# define XXH_FORCE_ALIGN_CHECK 0 + +/*! + * @def XXH_NO_INLINE_HINTS + * @brief When non-zero, sets all functions to `static`. + * + * By default, xxHash tries to force the compiler to inline almost all internal + * functions. + * + * This can usually improve performance due to reduced jumping and improved + * constant folding, but significantly increases the size of the binary which + * might not be favorable. + * + * Additionally, sometimes the forced inlining can be detrimental to performance, + * depending on the architecture. + * + * XXH_NO_INLINE_HINTS marks all internal functions as static, giving the + * compiler full control on whether to inline or not. + * + * When not optimizing (-O0), optimizing for size (-Os, -Oz), or using + * -fno-inline with GCC or Clang, this will automatically be defined. + */ +# define XXH_NO_INLINE_HINTS 0 + +/*! + * @def XXH32_ENDJMP + * @brief Whether to use a jump for `XXH32_finalize`. + * + * For performance, `XXH32_finalize` uses multiple branches in the finalizer. + * This is generally preferable for performance, + * but depending on exact architecture, a jmp may be preferable. + * + * This setting is only possibly making a difference for very small inputs. + */ +# define XXH32_ENDJMP 0 + +/*! + * @internal + * @brief Redefines old internal names. + * + * For compatibility with code that uses xxHash's internals before the names + * were changed to improve namespacing. There is no other reason to use this. + */ +# define XXH_OLD_NAMES +# undef XXH_OLD_NAMES /* don't actually use, it is ugly. */ +#endif /* XXH_DOXYGEN */ +/*! + * @} + */ + +#ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ + /* prefer __packed__ structures (method 1) for gcc on armv7+ and mips */ +# if !defined(__clang__) && \ +( \ + (defined(__INTEL_COMPILER) && !defined(_WIN32)) || \ + ( \ + defined(__GNUC__) && ( \ + (defined(__ARM_ARCH) && __ARM_ARCH >= 7) || \ + ( \ + defined(__mips__) && \ + (__mips <= 5 || __mips_isa_rev < 6) && \ + (!defined(__mips16) || defined(__mips_mips16e2)) \ + ) \ + ) \ + ) \ +) +# define XXH_FORCE_MEMORY_ACCESS 1 +# endif +#endif + +#ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */ +# if defined(__i386) || defined(__x86_64__) || defined(__aarch64__) \ + || defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM64) /* visual */ +# define XXH_FORCE_ALIGN_CHECK 0 +# else +# define XXH_FORCE_ALIGN_CHECK 1 +# endif +#endif + +#ifndef XXH_NO_INLINE_HINTS +# if defined(__OPTIMIZE_SIZE__) /* -Os, -Oz */ \ + || defined(__NO_INLINE__) /* -O0, -fno-inline */ +# define XXH_NO_INLINE_HINTS 1 +# else +# define XXH_NO_INLINE_HINTS 0 +# endif +#endif + +#ifndef XXH32_ENDJMP +/* generally preferable for performance */ +# define XXH32_ENDJMP 0 +#endif + +/*! + * @defgroup impl Implementation + * @{ + */ + + +/* ************************************* +* Includes & Memory related functions +***************************************/ +/* Modify the local functions below should you wish to use some other memory routines */ +/* for ZSTD_malloc(), ZSTD_free() */ +#define ZSTD_DEPS_NEED_MALLOC +#include "zstd_deps.h" /* size_t, ZSTD_malloc, ZSTD_free, ZSTD_memcpy */ +static void* XXH_malloc(size_t s) { return ZSTD_malloc(s); } +static void XXH_free (void* p) { ZSTD_free(p); } +static void* XXH_memcpy(void* dest, const void* src, size_t size) { return ZSTD_memcpy(dest,src,size); } + + +/* ************************************* +* Compiler Specific Options +***************************************/ +#ifdef _MSC_VER /* Visual Studio warning fix */ +# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ +#endif + +#if XXH_NO_INLINE_HINTS /* disable inlining hints */ +# if defined(__GNUC__) || defined(__clang__) +# define XXH_FORCE_INLINE static __attribute__((unused)) +# else +# define XXH_FORCE_INLINE static +# endif +# define XXH_NO_INLINE static +/* enable inlining hints */ +#elif defined(__GNUC__) || defined(__clang__) +# define XXH_FORCE_INLINE static __inline__ __attribute__((always_inline, unused)) +# define XXH_NO_INLINE static __attribute__((noinline)) +#elif defined(_MSC_VER) /* Visual Studio */ +# define XXH_FORCE_INLINE static __forceinline +# define XXH_NO_INLINE static __declspec(noinline) +#elif defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) /* C99 */ +# define XXH_FORCE_INLINE static inline +# define XXH_NO_INLINE static +#else +# define XXH_FORCE_INLINE static +# define XXH_NO_INLINE static +#endif + + + +/* ************************************* +* Debug +***************************************/ +/*! + * @ingroup tuning + * @def XXH_DEBUGLEVEL + * @brief Sets the debugging level. + * + * XXH_DEBUGLEVEL is expected to be defined externally, typically via the + * compiler's command line options. The value must be a number. + */ +#ifndef XXH_DEBUGLEVEL +# ifdef DEBUGLEVEL /* backwards compat */ +# define XXH_DEBUGLEVEL DEBUGLEVEL +# else +# define XXH_DEBUGLEVEL 0 +# endif +#endif + +#if (XXH_DEBUGLEVEL>=1) +# include /* note: can still be disabled with NDEBUG */ +# define XXH_ASSERT(c) assert(c) +#else +# define XXH_ASSERT(c) ((void)0) +#endif + +/* note: use after variable declarations */ +#ifndef XXH_STATIC_ASSERT +# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* C11 */ +# include +# define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { static_assert((c),m); } while(0) +# elif defined(__cplusplus) && (__cplusplus >= 201103L) /* C++11 */ +# define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { static_assert((c),m); } while(0) +# else +# define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { struct xxh_sa { char x[(c) ? 1 : -1]; }; } while(0) +# endif +# define XXH_STATIC_ASSERT(c) XXH_STATIC_ASSERT_WITH_MESSAGE((c),#c) +#endif + +/*! + * @internal + * @def XXH_COMPILER_GUARD(var) + * @brief Used to prevent unwanted optimizations for @p var. + * + * It uses an empty GCC inline assembly statement with a register constraint + * which forces @p var into a general purpose register (e.g. eax, ebx, ecx + * on x86) and marks it as modified. + * + * This is used in a few places to avoid unwanted autovectorization (e.g. + * XXH32_round()). All vectorization we want is explicit via intrinsics, + * and _usually_ isn't wanted elsewhere. + * + * We also use it to prevent unwanted constant folding for AArch64 in + * XXH3_initCustomSecret_scalar(). + */ +#if defined(__GNUC__) || defined(__clang__) +# define XXH_COMPILER_GUARD(var) __asm__ __volatile__("" : "+r" (var)) +#else +# define XXH_COMPILER_GUARD(var) ((void)0) +#endif + +/* ************************************* +* Basic Types +***************************************/ +#if !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) +# include + typedef uint8_t xxh_u8; +#else + typedef unsigned char xxh_u8; +#endif +typedef XXH32_hash_t xxh_u32; + +#ifdef XXH_OLD_NAMES +# define BYTE xxh_u8 +# define U8 xxh_u8 +# define U32 xxh_u32 +#endif + +/* *** Memory access *** */ + +/*! + * @internal + * @fn xxh_u32 XXH_read32(const void* ptr) + * @brief Reads an unaligned 32-bit integer from @p ptr in native endianness. + * + * Affected by @ref XXH_FORCE_MEMORY_ACCESS. + * + * @param ptr The pointer to read from. + * @return The 32-bit native endian integer from the bytes at @p ptr. + */ + +/*! + * @internal + * @fn xxh_u32 XXH_readLE32(const void* ptr) + * @brief Reads an unaligned 32-bit little endian integer from @p ptr. + * + * Affected by @ref XXH_FORCE_MEMORY_ACCESS. + * + * @param ptr The pointer to read from. + * @return The 32-bit little endian integer from the bytes at @p ptr. + */ + +/*! + * @internal + * @fn xxh_u32 XXH_readBE32(const void* ptr) + * @brief Reads an unaligned 32-bit big endian integer from @p ptr. + * + * Affected by @ref XXH_FORCE_MEMORY_ACCESS. + * + * @param ptr The pointer to read from. + * @return The 32-bit big endian integer from the bytes at @p ptr. + */ + +/*! + * @internal + * @fn xxh_u32 XXH_readLE32_align(const void* ptr, XXH_alignment align) + * @brief Like @ref XXH_readLE32(), but has an option for aligned reads. + * + * Affected by @ref XXH_FORCE_MEMORY_ACCESS. + * Note that when @ref XXH_FORCE_ALIGN_CHECK == 0, the @p align parameter is + * always @ref XXH_alignment::XXH_unaligned. + * + * @param ptr The pointer to read from. + * @param align Whether @p ptr is aligned. + * @pre + * If @p align == @ref XXH_alignment::XXH_aligned, @p ptr must be 4 byte + * aligned. + * @return The 32-bit little endian integer from the bytes at @p ptr. + */ + +#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) +/* + * Manual byteshift. Best for old compilers which don't inline memcpy. + * We actually directly use XXH_readLE32 and XXH_readBE32. + */ +#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2)) + +/* + * Force direct memory access. Only works on CPU which support unaligned memory + * access in hardware. + */ +static xxh_u32 XXH_read32(const void* memPtr) { return *(const xxh_u32*) memPtr; } + +#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1)) + +/* + * __pack instructions are safer but compiler specific, hence potentially + * problematic for some compilers. + * + * Currently only defined for GCC and ICC. + */ +#ifdef XXH_OLD_NAMES +typedef union { xxh_u32 u32; } __attribute__((packed)) unalign; +#endif +static xxh_u32 XXH_read32(const void* ptr) +{ + typedef union { xxh_u32 u32; } __attribute__((packed)) xxh_unalign; + return ((const xxh_unalign*)ptr)->u32; +} + +#else + +/* + * Portable and safe solution. Generally efficient. + * see: https://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html + */ +static xxh_u32 XXH_read32(const void* memPtr) +{ + xxh_u32 val; + XXH_memcpy(&val, memPtr, sizeof(val)); + return val; +} + +#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ + + +/* *** Endianness *** */ + +/*! + * @ingroup tuning + * @def XXH_CPU_LITTLE_ENDIAN + * @brief Whether the target is little endian. + * + * Defined to 1 if the target is little endian, or 0 if it is big endian. + * It can be defined externally, for example on the compiler command line. + * + * If it is not defined, + * a runtime check (which is usually constant folded) is used instead. + * + * @note + * This is not necessarily defined to an integer constant. + * + * @see XXH_isLittleEndian() for the runtime check. + */ +#ifndef XXH_CPU_LITTLE_ENDIAN +/* + * Try to detect endianness automatically, to avoid the nonstandard behavior + * in `XXH_isLittleEndian()` + */ +# if defined(_WIN32) /* Windows is always little endian */ \ + || defined(__LITTLE_ENDIAN__) \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +# define XXH_CPU_LITTLE_ENDIAN 1 +# elif defined(__BIG_ENDIAN__) \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +# define XXH_CPU_LITTLE_ENDIAN 0 +# else +/*! + * @internal + * @brief Runtime check for @ref XXH_CPU_LITTLE_ENDIAN. + * + * Most compilers will constant fold this. + */ +static int XXH_isLittleEndian(void) +{ + /* + * Portable and well-defined behavior. + * Don't use static: it is detrimental to performance. + */ + const union { xxh_u32 u; xxh_u8 c[4]; } one = { 1 }; + return one.c[0]; +} +# define XXH_CPU_LITTLE_ENDIAN XXH_isLittleEndian() +# endif +#endif + + + + +/* **************************************** +* Compiler-specific Functions and Macros +******************************************/ +#define XXH_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) + +#ifdef __has_builtin +# define XXH_HAS_BUILTIN(x) __has_builtin(x) +#else +# define XXH_HAS_BUILTIN(x) 0 +#endif + +/*! + * @internal + * @def XXH_rotl32(x,r) + * @brief 32-bit rotate left. + * + * @param x The 32-bit integer to be rotated. + * @param r The number of bits to rotate. + * @pre + * @p r > 0 && @p r < 32 + * @note + * @p x and @p r may be evaluated multiple times. + * @return The rotated result. + */ +#if !defined(NO_CLANG_BUILTIN) && XXH_HAS_BUILTIN(__builtin_rotateleft32) \ + && XXH_HAS_BUILTIN(__builtin_rotateleft64) +# define XXH_rotl32 __builtin_rotateleft32 +# define XXH_rotl64 __builtin_rotateleft64 +/* Note: although _rotl exists for minGW (GCC under windows), performance seems poor */ +#elif defined(_MSC_VER) +# define XXH_rotl32(x,r) _rotl(x,r) +# define XXH_rotl64(x,r) _rotl64(x,r) +#else +# define XXH_rotl32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) +# define XXH_rotl64(x,r) (((x) << (r)) | ((x) >> (64 - (r)))) +#endif + +/*! + * @internal + * @fn xxh_u32 XXH_swap32(xxh_u32 x) + * @brief A 32-bit byteswap. + * + * @param x The 32-bit integer to byteswap. + * @return @p x, byteswapped. + */ +#if defined(_MSC_VER) /* Visual Studio */ +# define XXH_swap32 _byteswap_ulong +#elif XXH_GCC_VERSION >= 403 +# define XXH_swap32 __builtin_bswap32 +#else +static xxh_u32 XXH_swap32 (xxh_u32 x) +{ + return ((x << 24) & 0xff000000 ) | + ((x << 8) & 0x00ff0000 ) | + ((x >> 8) & 0x0000ff00 ) | + ((x >> 24) & 0x000000ff ); +} +#endif + + +/* *************************** +* Memory reads +*****************************/ + +/*! + * @internal + * @brief Enum to indicate whether a pointer is aligned. + */ +typedef enum { + XXH_aligned, /*!< Aligned */ + XXH_unaligned /*!< Possibly unaligned */ +} XXH_alignment; + +/* + * XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load. + * + * This is ideal for older compilers which don't inline memcpy. + */ +#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) + +XXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void* memPtr) +{ + const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; + return bytePtr[0] + | ((xxh_u32)bytePtr[1] << 8) + | ((xxh_u32)bytePtr[2] << 16) + | ((xxh_u32)bytePtr[3] << 24); +} + +XXH_FORCE_INLINE xxh_u32 XXH_readBE32(const void* memPtr) +{ + const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; + return bytePtr[3] + | ((xxh_u32)bytePtr[2] << 8) + | ((xxh_u32)bytePtr[1] << 16) + | ((xxh_u32)bytePtr[0] << 24); +} + +#else +XXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr)); +} + +static xxh_u32 XXH_readBE32(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr); +} +#endif + +XXH_FORCE_INLINE xxh_u32 +XXH_readLE32_align(const void* ptr, XXH_alignment align) +{ + if (align==XXH_unaligned) { + return XXH_readLE32(ptr); + } else { + return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u32*)ptr : XXH_swap32(*(const xxh_u32*)ptr); + } +} + + +/* ************************************* +* Misc +***************************************/ +/*! @ingroup public */ +XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; } + + +/* ******************************************************************* +* 32-bit hash functions +*********************************************************************/ +/*! + * @} + * @defgroup xxh32_impl XXH32 implementation + * @ingroup impl + * @{ + */ + /* #define instead of static const, to be used as initializers */ +#define XXH_PRIME32_1 0x9E3779B1U /*!< 0b10011110001101110111100110110001 */ +#define XXH_PRIME32_2 0x85EBCA77U /*!< 0b10000101111010111100101001110111 */ +#define XXH_PRIME32_3 0xC2B2AE3DU /*!< 0b11000010101100101010111000111101 */ +#define XXH_PRIME32_4 0x27D4EB2FU /*!< 0b00100111110101001110101100101111 */ +#define XXH_PRIME32_5 0x165667B1U /*!< 0b00010110010101100110011110110001 */ + +#ifdef XXH_OLD_NAMES +# define PRIME32_1 XXH_PRIME32_1 +# define PRIME32_2 XXH_PRIME32_2 +# define PRIME32_3 XXH_PRIME32_3 +# define PRIME32_4 XXH_PRIME32_4 +# define PRIME32_5 XXH_PRIME32_5 +#endif + +/*! + * @internal + * @brief Normal stripe processing routine. + * + * This shuffles the bits so that any bit from @p input impacts several bits in + * @p acc. + * + * @param acc The accumulator lane. + * @param input The stripe of input to mix. + * @return The mixed accumulator lane. + */ +static xxh_u32 XXH32_round(xxh_u32 acc, xxh_u32 input) +{ + acc += input * XXH_PRIME32_2; + acc = XXH_rotl32(acc, 13); + acc *= XXH_PRIME32_1; +#if (defined(__SSE4_1__) || defined(__aarch64__)) && !defined(XXH_ENABLE_AUTOVECTORIZE) + /* + * UGLY HACK: + * A compiler fence is the only thing that prevents GCC and Clang from + * autovectorizing the XXH32 loop (pragmas and attributes don't work for some + * reason) without globally disabling SSE4.1. + * + * The reason we want to avoid vectorization is because despite working on + * 4 integers at a time, there are multiple factors slowing XXH32 down on + * SSE4: + * - There's a ridiculous amount of lag from pmulld (10 cycles of latency on + * newer chips!) making it slightly slower to multiply four integers at + * once compared to four integers independently. Even when pmulld was + * fastest, Sandy/Ivy Bridge, it is still not worth it to go into SSE + * just to multiply unless doing a long operation. + * + * - Four instructions are required to rotate, + * movqda tmp, v // not required with VEX encoding + * pslld tmp, 13 // tmp <<= 13 + * psrld v, 19 // x >>= 19 + * por v, tmp // x |= tmp + * compared to one for scalar: + * roll v, 13 // reliably fast across the board + * shldl v, v, 13 // Sandy Bridge and later prefer this for some reason + * + * - Instruction level parallelism is actually more beneficial here because + * the SIMD actually serializes this operation: While v1 is rotating, v2 + * can load data, while v3 can multiply. SSE forces them to operate + * together. + * + * This is also enabled on AArch64, as Clang autovectorizes it incorrectly + * and it is pointless writing a NEON implementation that is basically the + * same speed as scalar for XXH32. + */ + XXH_COMPILER_GUARD(acc); +#endif + return acc; +} + +/*! + * @internal + * @brief Mixes all bits to finalize the hash. + * + * The final mix ensures that all input bits have a chance to impact any bit in + * the output digest, resulting in an unbiased distribution. + * + * @param h32 The hash to avalanche. + * @return The avalanched hash. + */ +static xxh_u32 XXH32_avalanche(xxh_u32 h32) +{ + h32 ^= h32 >> 15; + h32 *= XXH_PRIME32_2; + h32 ^= h32 >> 13; + h32 *= XXH_PRIME32_3; + h32 ^= h32 >> 16; + return(h32); +} + +#define XXH_get32bits(p) XXH_readLE32_align(p, align) + +/*! + * @internal + * @brief Processes the last 0-15 bytes of @p ptr. + * + * There may be up to 15 bytes remaining to consume from the input. + * This final stage will digest them to ensure that all input bytes are present + * in the final mix. + * + * @param h32 The hash to finalize. + * @param ptr The pointer to the remaining input. + * @param len The remaining length, modulo 16. + * @param align Whether @p ptr is aligned. + * @return The finalized hash. + */ +static xxh_u32 +XXH32_finalize(xxh_u32 h32, const xxh_u8* ptr, size_t len, XXH_alignment align) +{ +#define XXH_PROCESS1 do { \ + h32 += (*ptr++) * XXH_PRIME32_5; \ + h32 = XXH_rotl32(h32, 11) * XXH_PRIME32_1; \ +} while (0) + +#define XXH_PROCESS4 do { \ + h32 += XXH_get32bits(ptr) * XXH_PRIME32_3; \ + ptr += 4; \ + h32 = XXH_rotl32(h32, 17) * XXH_PRIME32_4; \ +} while (0) + + if (ptr==NULL) XXH_ASSERT(len == 0); + + /* Compact rerolled version; generally faster */ + if (!XXH32_ENDJMP) { + len &= 15; + while (len >= 4) { + XXH_PROCESS4; + len -= 4; + } + while (len > 0) { + XXH_PROCESS1; + --len; + } + return XXH32_avalanche(h32); + } else { + switch(len&15) /* or switch(bEnd - p) */ { + case 12: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 8: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 4: XXH_PROCESS4; + return XXH32_avalanche(h32); + + case 13: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 9: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 5: XXH_PROCESS4; + XXH_PROCESS1; + return XXH32_avalanche(h32); + + case 14: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 10: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 6: XXH_PROCESS4; + XXH_PROCESS1; + XXH_PROCESS1; + return XXH32_avalanche(h32); + + case 15: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 11: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 7: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 3: XXH_PROCESS1; + XXH_FALLTHROUGH; + case 2: XXH_PROCESS1; + XXH_FALLTHROUGH; + case 1: XXH_PROCESS1; + XXH_FALLTHROUGH; + case 0: return XXH32_avalanche(h32); + } + XXH_ASSERT(0); + return h32; /* reaching this point is deemed impossible */ + } +} + +#ifdef XXH_OLD_NAMES +# define PROCESS1 XXH_PROCESS1 +# define PROCESS4 XXH_PROCESS4 +#else +# undef XXH_PROCESS1 +# undef XXH_PROCESS4 +#endif + +/*! + * @internal + * @brief The implementation for @ref XXH32(). + * + * @param input , len , seed Directly passed from @ref XXH32(). + * @param align Whether @p input is aligned. + * @return The calculated hash. + */ +XXH_FORCE_INLINE xxh_u32 +XXH32_endian_align(const xxh_u8* input, size_t len, xxh_u32 seed, XXH_alignment align) +{ + xxh_u32 h32; + + if (input==NULL) XXH_ASSERT(len == 0); + + if (len>=16) { + const xxh_u8* const bEnd = input + len; + const xxh_u8* const limit = bEnd - 15; + xxh_u32 v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2; + xxh_u32 v2 = seed + XXH_PRIME32_2; + xxh_u32 v3 = seed + 0; + xxh_u32 v4 = seed - XXH_PRIME32_1; + + do { + v1 = XXH32_round(v1, XXH_get32bits(input)); input += 4; + v2 = XXH32_round(v2, XXH_get32bits(input)); input += 4; + v3 = XXH32_round(v3, XXH_get32bits(input)); input += 4; + v4 = XXH32_round(v4, XXH_get32bits(input)); input += 4; + } while (input < limit); + + h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18); + } else { + h32 = seed + XXH_PRIME32_5; + } + + h32 += (xxh_u32)len; + + return XXH32_finalize(h32, input, len&15, align); +} + +/*! @ingroup xxh32_family */ +XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t len, XXH32_hash_t seed) +{ +#if 0 + /* Simple version, good for code maintenance, but unfortunately slow for small inputs */ + XXH32_state_t state; + XXH32_reset(&state, seed); + XXH32_update(&state, (const xxh_u8*)input, len); + return XXH32_digest(&state); +#else + if (XXH_FORCE_ALIGN_CHECK) { + if ((((size_t)input) & 3) == 0) { /* Input is 4-bytes aligned, leverage the speed benefit */ + return XXH32_endian_align((const xxh_u8*)input, len, seed, XXH_aligned); + } } + + return XXH32_endian_align((const xxh_u8*)input, len, seed, XXH_unaligned); +#endif +} + + + +/******* Hash streaming *******/ +/*! + * @ingroup xxh32_family + */ +XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void) +{ + return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t)); +} +/*! @ingroup xxh32_family */ +XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr) +{ + XXH_free(statePtr); + return XXH_OK; +} + +/*! @ingroup xxh32_family */ +XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState) +{ + XXH_memcpy(dstState, srcState, sizeof(*dstState)); +} + +/*! @ingroup xxh32_family */ +XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, XXH32_hash_t seed) +{ + XXH_ASSERT(statePtr != NULL); + memset(statePtr, 0, sizeof(*statePtr)); + statePtr->v[0] = seed + XXH_PRIME32_1 + XXH_PRIME32_2; + statePtr->v[1] = seed + XXH_PRIME32_2; + statePtr->v[2] = seed + 0; + statePtr->v[3] = seed - XXH_PRIME32_1; + return XXH_OK; +} + + +/*! @ingroup xxh32_family */ +XXH_PUBLIC_API XXH_errorcode +XXH32_update(XXH32_state_t* state, const void* input, size_t len) +{ + if (input==NULL) { + XXH_ASSERT(len == 0); + return XXH_OK; + } + + { const xxh_u8* p = (const xxh_u8*)input; + const xxh_u8* const bEnd = p + len; + + state->total_len_32 += (XXH32_hash_t)len; + state->large_len |= (XXH32_hash_t)((len>=16) | (state->total_len_32>=16)); + + if (state->memsize + len < 16) { /* fill in tmp buffer */ + XXH_memcpy((xxh_u8*)(state->mem32) + state->memsize, input, len); + state->memsize += (XXH32_hash_t)len; + return XXH_OK; + } + + if (state->memsize) { /* some data left from previous update */ + XXH_memcpy((xxh_u8*)(state->mem32) + state->memsize, input, 16-state->memsize); + { const xxh_u32* p32 = state->mem32; + state->v[0] = XXH32_round(state->v[0], XXH_readLE32(p32)); p32++; + state->v[1] = XXH32_round(state->v[1], XXH_readLE32(p32)); p32++; + state->v[2] = XXH32_round(state->v[2], XXH_readLE32(p32)); p32++; + state->v[3] = XXH32_round(state->v[3], XXH_readLE32(p32)); + } + p += 16-state->memsize; + state->memsize = 0; + } + + if (p <= bEnd-16) { + const xxh_u8* const limit = bEnd - 16; + + do { + state->v[0] = XXH32_round(state->v[0], XXH_readLE32(p)); p+=4; + state->v[1] = XXH32_round(state->v[1], XXH_readLE32(p)); p+=4; + state->v[2] = XXH32_round(state->v[2], XXH_readLE32(p)); p+=4; + state->v[3] = XXH32_round(state->v[3], XXH_readLE32(p)); p+=4; + } while (p<=limit); + + } + + if (p < bEnd) { + XXH_memcpy(state->mem32, p, (size_t)(bEnd-p)); + state->memsize = (unsigned)(bEnd-p); + } + } + + return XXH_OK; +} + + +/*! @ingroup xxh32_family */ +XXH_PUBLIC_API XXH32_hash_t XXH32_digest(const XXH32_state_t* state) +{ + xxh_u32 h32; + + if (state->large_len) { + h32 = XXH_rotl32(state->v[0], 1) + + XXH_rotl32(state->v[1], 7) + + XXH_rotl32(state->v[2], 12) + + XXH_rotl32(state->v[3], 18); + } else { + h32 = state->v[2] /* == seed */ + XXH_PRIME32_5; + } + + h32 += state->total_len_32; + + return XXH32_finalize(h32, (const xxh_u8*)state->mem32, state->memsize, XXH_aligned); +} + + +/******* Canonical representation *******/ + +/*! + * @ingroup xxh32_family + * The default return values from XXH functions are unsigned 32 and 64 bit + * integers. + * + * The canonical representation uses big endian convention, the same convention + * as human-readable numbers (large digits first). + * + * This way, hash values can be written into a file or buffer, remaining + * comparable across different systems. + * + * The following functions allow transformation of hash values to and from their + * canonical format. + */ +XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash) +{ + /* XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t)); */ + if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash); + XXH_memcpy(dst, &hash, sizeof(*dst)); +} +/*! @ingroup xxh32_family */ +XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src) +{ + return XXH_readBE32(src); +} + + +#ifndef XXH_NO_LONG_LONG + +/* ******************************************************************* +* 64-bit hash functions +*********************************************************************/ +/*! + * @} + * @ingroup impl + * @{ + */ +/******* Memory access *******/ + +typedef XXH64_hash_t xxh_u64; + +#ifdef XXH_OLD_NAMES +# define U64 xxh_u64 +#endif + +#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) +/* + * Manual byteshift. Best for old compilers which don't inline memcpy. + * We actually directly use XXH_readLE64 and XXH_readBE64. + */ +#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2)) + +/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */ +static xxh_u64 XXH_read64(const void* memPtr) +{ + return *(const xxh_u64*) memPtr; +} + +#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1)) + +/* + * __pack instructions are safer, but compiler specific, hence potentially + * problematic for some compilers. + * + * Currently only defined for GCC and ICC. + */ +#ifdef XXH_OLD_NAMES +typedef union { xxh_u32 u32; xxh_u64 u64; } __attribute__((packed)) unalign64; +#endif +static xxh_u64 XXH_read64(const void* ptr) +{ + typedef union { xxh_u32 u32; xxh_u64 u64; } __attribute__((packed)) xxh_unalign64; + return ((const xxh_unalign64*)ptr)->u64; +} + +#else + +/* + * Portable and safe solution. Generally efficient. + * see: https://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html + */ +static xxh_u64 XXH_read64(const void* memPtr) +{ + xxh_u64 val; + XXH_memcpy(&val, memPtr, sizeof(val)); + return val; +} + +#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ + +#if defined(_MSC_VER) /* Visual Studio */ +# define XXH_swap64 _byteswap_uint64 +#elif XXH_GCC_VERSION >= 403 +# define XXH_swap64 __builtin_bswap64 +#else +static xxh_u64 XXH_swap64(xxh_u64 x) +{ + return ((x << 56) & 0xff00000000000000ULL) | + ((x << 40) & 0x00ff000000000000ULL) | + ((x << 24) & 0x0000ff0000000000ULL) | + ((x << 8) & 0x000000ff00000000ULL) | + ((x >> 8) & 0x00000000ff000000ULL) | + ((x >> 24) & 0x0000000000ff0000ULL) | + ((x >> 40) & 0x000000000000ff00ULL) | + ((x >> 56) & 0x00000000000000ffULL); +} +#endif + + +/* XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load. */ +#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) + +XXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void* memPtr) +{ + const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; + return bytePtr[0] + | ((xxh_u64)bytePtr[1] << 8) + | ((xxh_u64)bytePtr[2] << 16) + | ((xxh_u64)bytePtr[3] << 24) + | ((xxh_u64)bytePtr[4] << 32) + | ((xxh_u64)bytePtr[5] << 40) + | ((xxh_u64)bytePtr[6] << 48) + | ((xxh_u64)bytePtr[7] << 56); +} + +XXH_FORCE_INLINE xxh_u64 XXH_readBE64(const void* memPtr) +{ + const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; + return bytePtr[7] + | ((xxh_u64)bytePtr[6] << 8) + | ((xxh_u64)bytePtr[5] << 16) + | ((xxh_u64)bytePtr[4] << 24) + | ((xxh_u64)bytePtr[3] << 32) + | ((xxh_u64)bytePtr[2] << 40) + | ((xxh_u64)bytePtr[1] << 48) + | ((xxh_u64)bytePtr[0] << 56); +} + +#else +XXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr)); +} + +static xxh_u64 XXH_readBE64(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr); +} +#endif + +XXH_FORCE_INLINE xxh_u64 +XXH_readLE64_align(const void* ptr, XXH_alignment align) +{ + if (align==XXH_unaligned) + return XXH_readLE64(ptr); + else + return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u64*)ptr : XXH_swap64(*(const xxh_u64*)ptr); +} + + +/******* xxh64 *******/ +/*! + * @} + * @defgroup xxh64_impl XXH64 implementation + * @ingroup impl + * @{ + */ +/* #define rather that static const, to be used as initializers */ +#define XXH_PRIME64_1 0x9E3779B185EBCA87ULL /*!< 0b1001111000110111011110011011000110000101111010111100101010000111 */ +#define XXH_PRIME64_2 0xC2B2AE3D27D4EB4FULL /*!< 0b1100001010110010101011100011110100100111110101001110101101001111 */ +#define XXH_PRIME64_3 0x165667B19E3779F9ULL /*!< 0b0001011001010110011001111011000110011110001101110111100111111001 */ +#define XXH_PRIME64_4 0x85EBCA77C2B2AE63ULL /*!< 0b1000010111101011110010100111011111000010101100101010111001100011 */ +#define XXH_PRIME64_5 0x27D4EB2F165667C5ULL /*!< 0b0010011111010100111010110010111100010110010101100110011111000101 */ + +#ifdef XXH_OLD_NAMES +# define PRIME64_1 XXH_PRIME64_1 +# define PRIME64_2 XXH_PRIME64_2 +# define PRIME64_3 XXH_PRIME64_3 +# define PRIME64_4 XXH_PRIME64_4 +# define PRIME64_5 XXH_PRIME64_5 +#endif + +static xxh_u64 XXH64_round(xxh_u64 acc, xxh_u64 input) +{ + acc += input * XXH_PRIME64_2; + acc = XXH_rotl64(acc, 31); + acc *= XXH_PRIME64_1; + return acc; +} + +static xxh_u64 XXH64_mergeRound(xxh_u64 acc, xxh_u64 val) +{ + val = XXH64_round(0, val); + acc ^= val; + acc = acc * XXH_PRIME64_1 + XXH_PRIME64_4; + return acc; +} + +static xxh_u64 XXH64_avalanche(xxh_u64 h64) +{ + h64 ^= h64 >> 33; + h64 *= XXH_PRIME64_2; + h64 ^= h64 >> 29; + h64 *= XXH_PRIME64_3; + h64 ^= h64 >> 32; + return h64; +} + + +#define XXH_get64bits(p) XXH_readLE64_align(p, align) + +static xxh_u64 +XXH64_finalize(xxh_u64 h64, const xxh_u8* ptr, size_t len, XXH_alignment align) +{ + if (ptr==NULL) XXH_ASSERT(len == 0); + len &= 31; + while (len >= 8) { + xxh_u64 const k1 = XXH64_round(0, XXH_get64bits(ptr)); + ptr += 8; + h64 ^= k1; + h64 = XXH_rotl64(h64,27) * XXH_PRIME64_1 + XXH_PRIME64_4; + len -= 8; + } + if (len >= 4) { + h64 ^= (xxh_u64)(XXH_get32bits(ptr)) * XXH_PRIME64_1; + ptr += 4; + h64 = XXH_rotl64(h64, 23) * XXH_PRIME64_2 + XXH_PRIME64_3; + len -= 4; + } + while (len > 0) { + h64 ^= (*ptr++) * XXH_PRIME64_5; + h64 = XXH_rotl64(h64, 11) * XXH_PRIME64_1; + --len; + } + return XXH64_avalanche(h64); +} + +#ifdef XXH_OLD_NAMES +# define PROCESS1_64 XXH_PROCESS1_64 +# define PROCESS4_64 XXH_PROCESS4_64 +# define PROCESS8_64 XXH_PROCESS8_64 +#else +# undef XXH_PROCESS1_64 +# undef XXH_PROCESS4_64 +# undef XXH_PROCESS8_64 +#endif + +XXH_FORCE_INLINE xxh_u64 +XXH64_endian_align(const xxh_u8* input, size_t len, xxh_u64 seed, XXH_alignment align) +{ + xxh_u64 h64; + if (input==NULL) XXH_ASSERT(len == 0); + + if (len>=32) { + const xxh_u8* const bEnd = input + len; + const xxh_u8* const limit = bEnd - 31; + xxh_u64 v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2; + xxh_u64 v2 = seed + XXH_PRIME64_2; + xxh_u64 v3 = seed + 0; + xxh_u64 v4 = seed - XXH_PRIME64_1; + + do { + v1 = XXH64_round(v1, XXH_get64bits(input)); input+=8; + v2 = XXH64_round(v2, XXH_get64bits(input)); input+=8; + v3 = XXH64_round(v3, XXH_get64bits(input)); input+=8; + v4 = XXH64_round(v4, XXH_get64bits(input)); input+=8; + } while (inputv[0] = seed + XXH_PRIME64_1 + XXH_PRIME64_2; + statePtr->v[1] = seed + XXH_PRIME64_2; + statePtr->v[2] = seed + 0; + statePtr->v[3] = seed - XXH_PRIME64_1; + return XXH_OK; +} + +/*! @ingroup xxh64_family */ +XXH_PUBLIC_API XXH_errorcode +XXH64_update (XXH64_state_t* state, const void* input, size_t len) +{ + if (input==NULL) { + XXH_ASSERT(len == 0); + return XXH_OK; + } + + { const xxh_u8* p = (const xxh_u8*)input; + const xxh_u8* const bEnd = p + len; + + state->total_len += len; + + if (state->memsize + len < 32) { /* fill in tmp buffer */ + XXH_memcpy(((xxh_u8*)state->mem64) + state->memsize, input, len); + state->memsize += (xxh_u32)len; + return XXH_OK; + } + + if (state->memsize) { /* tmp buffer is full */ + XXH_memcpy(((xxh_u8*)state->mem64) + state->memsize, input, 32-state->memsize); + state->v[0] = XXH64_round(state->v[0], XXH_readLE64(state->mem64+0)); + state->v[1] = XXH64_round(state->v[1], XXH_readLE64(state->mem64+1)); + state->v[2] = XXH64_round(state->v[2], XXH_readLE64(state->mem64+2)); + state->v[3] = XXH64_round(state->v[3], XXH_readLE64(state->mem64+3)); + p += 32 - state->memsize; + state->memsize = 0; + } + + if (p+32 <= bEnd) { + const xxh_u8* const limit = bEnd - 32; + + do { + state->v[0] = XXH64_round(state->v[0], XXH_readLE64(p)); p+=8; + state->v[1] = XXH64_round(state->v[1], XXH_readLE64(p)); p+=8; + state->v[2] = XXH64_round(state->v[2], XXH_readLE64(p)); p+=8; + state->v[3] = XXH64_round(state->v[3], XXH_readLE64(p)); p+=8; + } while (p<=limit); + + } + + if (p < bEnd) { + XXH_memcpy(state->mem64, p, (size_t)(bEnd-p)); + state->memsize = (unsigned)(bEnd-p); + } + } + + return XXH_OK; +} + + +/*! @ingroup xxh64_family */ +XXH_PUBLIC_API XXH64_hash_t XXH64_digest(const XXH64_state_t* state) +{ + xxh_u64 h64; + + if (state->total_len >= 32) { + h64 = XXH_rotl64(state->v[0], 1) + XXH_rotl64(state->v[1], 7) + XXH_rotl64(state->v[2], 12) + XXH_rotl64(state->v[3], 18); + h64 = XXH64_mergeRound(h64, state->v[0]); + h64 = XXH64_mergeRound(h64, state->v[1]); + h64 = XXH64_mergeRound(h64, state->v[2]); + h64 = XXH64_mergeRound(h64, state->v[3]); + } else { + h64 = state->v[2] /*seed*/ + XXH_PRIME64_5; + } + + h64 += (xxh_u64) state->total_len; + + return XXH64_finalize(h64, (const xxh_u8*)state->mem64, (size_t)state->total_len, XXH_aligned); +} + + +/******* Canonical representation *******/ + +/*! @ingroup xxh64_family */ +XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash) +{ + /* XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t)); */ + if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash); + XXH_memcpy(dst, &hash, sizeof(*dst)); +} + +/*! @ingroup xxh64_family */ +XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src) +{ + return XXH_readBE64(src); +} + +#ifndef XXH_NO_XXH3 + +/* ********************************************************************* +* XXH3 +* New generation hash designed for speed on small keys and vectorization +************************************************************************ */ +/*! + * @} + * @defgroup xxh3_impl XXH3 implementation + * @ingroup impl + * @{ + */ + +/* === Compiler specifics === */ + +#if ((defined(sun) || defined(__sun)) && __cplusplus) /* Solaris includes __STDC_VERSION__ with C++. Tested with GCC 5.5 */ +# define XXH_RESTRICT /* disable */ +#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* >= C99 */ +# define XXH_RESTRICT restrict +#else +/* Note: it might be useful to define __restrict or __restrict__ for some C++ compilers */ +# define XXH_RESTRICT /* disable */ +#endif + +#if (defined(__GNUC__) && (__GNUC__ >= 3)) \ + || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) \ + || defined(__clang__) +# define XXH_likely(x) __builtin_expect(x, 1) +# define XXH_unlikely(x) __builtin_expect(x, 0) +#else +# define XXH_likely(x) (x) +# define XXH_unlikely(x) (x) +#endif + +#if defined(__GNUC__) || defined(__clang__) +# if defined(__ARM_NEON__) || defined(__ARM_NEON) \ + || defined(__aarch64__) || defined(_M_ARM) \ + || defined(_M_ARM64) || defined(_M_ARM64EC) +# define inline __inline__ /* circumvent a clang bug */ +# include +# undef inline +# elif defined(__AVX2__) +# include +# elif defined(__SSE2__) +# include +# endif +#endif + +#if defined(_MSC_VER) +# include +#endif + +/* + * One goal of XXH3 is to make it fast on both 32-bit and 64-bit, while + * remaining a true 64-bit/128-bit hash function. + * + * This is done by prioritizing a subset of 64-bit operations that can be + * emulated without too many steps on the average 32-bit machine. + * + * For example, these two lines seem similar, and run equally fast on 64-bit: + * + * xxh_u64 x; + * x ^= (x >> 47); // good + * x ^= (x >> 13); // bad + * + * However, to a 32-bit machine, there is a major difference. + * + * x ^= (x >> 47) looks like this: + * + * x.lo ^= (x.hi >> (47 - 32)); + * + * while x ^= (x >> 13) looks like this: + * + * // note: funnel shifts are not usually cheap. + * x.lo ^= (x.lo >> 13) | (x.hi << (32 - 13)); + * x.hi ^= (x.hi >> 13); + * + * The first one is significantly faster than the second, simply because the + * shift is larger than 32. This means: + * - All the bits we need are in the upper 32 bits, so we can ignore the lower + * 32 bits in the shift. + * - The shift result will always fit in the lower 32 bits, and therefore, + * we can ignore the upper 32 bits in the xor. + * + * Thanks to this optimization, XXH3 only requires these features to be efficient: + * + * - Usable unaligned access + * - A 32-bit or 64-bit ALU + * - If 32-bit, a decent ADC instruction + * - A 32 or 64-bit multiply with a 64-bit result + * - For the 128-bit variant, a decent byteswap helps short inputs. + * + * The first two are already required by XXH32, and almost all 32-bit and 64-bit + * platforms which can run XXH32 can run XXH3 efficiently. + * + * Thumb-1, the classic 16-bit only subset of ARM's instruction set, is one + * notable exception. + * + * First of all, Thumb-1 lacks support for the UMULL instruction which + * performs the important long multiply. This means numerous __aeabi_lmul + * calls. + * + * Second of all, the 8 functional registers are just not enough. + * Setup for __aeabi_lmul, byteshift loads, pointers, and all arithmetic need + * Lo registers, and this shuffling results in thousands more MOVs than A32. + * + * A32 and T32 don't have this limitation. They can access all 14 registers, + * do a 32->64 multiply with UMULL, and the flexible operand allowing free + * shifts is helpful, too. + * + * Therefore, we do a quick sanity check. + * + * If compiling Thumb-1 for a target which supports ARM instructions, we will + * emit a warning, as it is not a "sane" platform to compile for. + * + * Usually, if this happens, it is because of an accident and you probably need + * to specify -march, as you likely meant to compile for a newer architecture. + * + * Credit: large sections of the vectorial and asm source code paths + * have been contributed by @easyaspi314 + */ +#if defined(__thumb__) && !defined(__thumb2__) && defined(__ARM_ARCH_ISA_ARM) +# warning "XXH3 is highly inefficient without ARM or Thumb-2." +#endif + +/* ========================================== + * Vectorization detection + * ========================================== */ + +#ifdef XXH_DOXYGEN +/*! + * @ingroup tuning + * @brief Overrides the vectorization implementation chosen for XXH3. + * + * Can be defined to 0 to disable SIMD or any of the values mentioned in + * @ref XXH_VECTOR_TYPE. + * + * If this is not defined, it uses predefined macros to determine the best + * implementation. + */ +# define XXH_VECTOR XXH_SCALAR +/*! + * @ingroup tuning + * @brief Possible values for @ref XXH_VECTOR. + * + * Note that these are actually implemented as macros. + * + * If this is not defined, it is detected automatically. + * @ref XXH_X86DISPATCH overrides this. + */ +enum XXH_VECTOR_TYPE /* fake enum */ { + XXH_SCALAR = 0, /*!< Portable scalar version */ + XXH_SSE2 = 1, /*!< + * SSE2 for Pentium 4, Opteron, all x86_64. + * + * @note SSE2 is also guaranteed on Windows 10, macOS, and + * Android x86. + */ + XXH_AVX2 = 2, /*!< AVX2 for Haswell and Bulldozer */ + XXH_AVX512 = 3, /*!< AVX512 for Skylake and Icelake */ + XXH_NEON = 4, /*!< NEON for most ARMv7-A and all AArch64 */ + XXH_VSX = 5, /*!< VSX and ZVector for POWER8/z13 (64-bit) */ +}; +/*! + * @ingroup tuning + * @brief Selects the minimum alignment for XXH3's accumulators. + * + * When using SIMD, this should match the alignment required for said vector + * type, so, for example, 32 for AVX2. + * + * Default: Auto detected. + */ +# define XXH_ACC_ALIGN 8 +#endif + +/* Actual definition */ +#ifndef XXH_DOXYGEN +# define XXH_SCALAR 0 +# define XXH_SSE2 1 +# define XXH_AVX2 2 +# define XXH_AVX512 3 +# define XXH_NEON 4 +# define XXH_VSX 5 +#endif + +#ifndef XXH_VECTOR /* can be defined on command line */ +# if ( \ + defined(__ARM_NEON__) || defined(__ARM_NEON) /* gcc */ \ + || defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) /* msvc */ \ + ) && ( \ + defined(_WIN32) || defined(__LITTLE_ENDIAN__) /* little endian only */ \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) \ + ) +# define XXH_VECTOR XXH_NEON +# elif defined(__AVX512F__) +# define XXH_VECTOR XXH_AVX512 +# elif defined(__AVX2__) +# define XXH_VECTOR XXH_AVX2 +# elif defined(__SSE2__) || defined(_M_AMD64) || defined(_M_X64) || (defined(_M_IX86_FP) && (_M_IX86_FP == 2)) +# define XXH_VECTOR XXH_SSE2 +# elif (defined(__PPC64__) && defined(__POWER8_VECTOR__)) \ + || (defined(__s390x__) && defined(__VEC__)) \ + && defined(__GNUC__) /* TODO: IBM XL */ +# define XXH_VECTOR XXH_VSX +# else +# define XXH_VECTOR XXH_SCALAR +# endif +#endif + +/* + * Controls the alignment of the accumulator, + * for compatibility with aligned vector loads, which are usually faster. + */ +#ifndef XXH_ACC_ALIGN +# if defined(XXH_X86DISPATCH) +# define XXH_ACC_ALIGN 64 /* for compatibility with avx512 */ +# elif XXH_VECTOR == XXH_SCALAR /* scalar */ +# define XXH_ACC_ALIGN 8 +# elif XXH_VECTOR == XXH_SSE2 /* sse2 */ +# define XXH_ACC_ALIGN 16 +# elif XXH_VECTOR == XXH_AVX2 /* avx2 */ +# define XXH_ACC_ALIGN 32 +# elif XXH_VECTOR == XXH_NEON /* neon */ +# define XXH_ACC_ALIGN 16 +# elif XXH_VECTOR == XXH_VSX /* vsx */ +# define XXH_ACC_ALIGN 16 +# elif XXH_VECTOR == XXH_AVX512 /* avx512 */ +# define XXH_ACC_ALIGN 64 +# endif +#endif + +#if defined(XXH_X86DISPATCH) || XXH_VECTOR == XXH_SSE2 \ + || XXH_VECTOR == XXH_AVX2 || XXH_VECTOR == XXH_AVX512 +# define XXH_SEC_ALIGN XXH_ACC_ALIGN +#else +# define XXH_SEC_ALIGN 8 +#endif + +/* + * UGLY HACK: + * GCC usually generates the best code with -O3 for xxHash. + * + * However, when targeting AVX2, it is overzealous in its unrolling resulting + * in code roughly 3/4 the speed of Clang. + * + * There are other issues, such as GCC splitting _mm256_loadu_si256 into + * _mm_loadu_si128 + _mm256_inserti128_si256. This is an optimization which + * only applies to Sandy and Ivy Bridge... which don't even support AVX2. + * + * That is why when compiling the AVX2 version, it is recommended to use either + * -O2 -mavx2 -march=haswell + * or + * -O2 -mavx2 -mno-avx256-split-unaligned-load + * for decent performance, or to use Clang instead. + * + * Fortunately, we can control the first one with a pragma that forces GCC into + * -O2, but the other one we can't control without "failed to inline always + * inline function due to target mismatch" warnings. + */ +#if XXH_VECTOR == XXH_AVX2 /* AVX2 */ \ + && defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \ + && defined(__OPTIMIZE__) && !defined(__OPTIMIZE_SIZE__) /* respect -O0 and -Os */ +# pragma GCC push_options +# pragma GCC optimize("-O2") +#endif + + +#if XXH_VECTOR == XXH_NEON +/* + * NEON's setup for vmlal_u32 is a little more complicated than it is on + * SSE2, AVX2, and VSX. + * + * While PMULUDQ and VMULEUW both perform a mask, VMLAL.U32 performs an upcast. + * + * To do the same operation, the 128-bit 'Q' register needs to be split into + * two 64-bit 'D' registers, performing this operation:: + * + * [ a | b ] + * | '---------. .--------' | + * | x | + * | .---------' '--------. | + * [ a & 0xFFFFFFFF | b & 0xFFFFFFFF ],[ a >> 32 | b >> 32 ] + * + * Due to significant changes in aarch64, the fastest method for aarch64 is + * completely different than the fastest method for ARMv7-A. + * + * ARMv7-A treats D registers as unions overlaying Q registers, so modifying + * D11 will modify the high half of Q5. This is similar to how modifying AH + * will only affect bits 8-15 of AX on x86. + * + * VZIP takes two registers, and puts even lanes in one register and odd lanes + * in the other. + * + * On ARMv7-A, this strangely modifies both parameters in place instead of + * taking the usual 3-operand form. + * + * Therefore, if we want to do this, we can simply use a D-form VZIP.32 on the + * lower and upper halves of the Q register to end up with the high and low + * halves where we want - all in one instruction. + * + * vzip.32 d10, d11 @ d10 = { d10[0], d11[0] }; d11 = { d10[1], d11[1] } + * + * Unfortunately we need inline assembly for this: Instructions modifying two + * registers at once is not possible in GCC or Clang's IR, and they have to + * create a copy. + * + * aarch64 requires a different approach. + * + * In order to make it easier to write a decent compiler for aarch64, many + * quirks were removed, such as conditional execution. + * + * NEON was also affected by this. + * + * aarch64 cannot access the high bits of a Q-form register, and writes to a + * D-form register zero the high bits, similar to how writes to W-form scalar + * registers (or DWORD registers on x86_64) work. + * + * The formerly free vget_high intrinsics now require a vext (with a few + * exceptions) + * + * Additionally, VZIP was replaced by ZIP1 and ZIP2, which are the equivalent + * of PUNPCKL* and PUNPCKH* in SSE, respectively, in order to only modify one + * operand. + * + * The equivalent of the VZIP.32 on the lower and upper halves would be this + * mess: + * + * ext v2.4s, v0.4s, v0.4s, #2 // v2 = { v0[2], v0[3], v0[0], v0[1] } + * zip1 v1.2s, v0.2s, v2.2s // v1 = { v0[0], v2[0] } + * zip2 v0.2s, v0.2s, v1.2s // v0 = { v0[1], v2[1] } + * + * Instead, we use a literal downcast, vmovn_u64 (XTN), and vshrn_n_u64 (SHRN): + * + * shrn v1.2s, v0.2d, #32 // v1 = (uint32x2_t)(v0 >> 32); + * xtn v0.2s, v0.2d // v0 = (uint32x2_t)(v0 & 0xFFFFFFFF); + * + * This is available on ARMv7-A, but is less efficient than a single VZIP.32. + */ + +/*! + * Function-like macro: + * void XXH_SPLIT_IN_PLACE(uint64x2_t &in, uint32x2_t &outLo, uint32x2_t &outHi) + * { + * outLo = (uint32x2_t)(in & 0xFFFFFFFF); + * outHi = (uint32x2_t)(in >> 32); + * in = UNDEFINED; + * } + */ +# if !defined(XXH_NO_VZIP_HACK) /* define to disable */ \ + && (defined(__GNUC__) || defined(__clang__)) \ + && (defined(__arm__) || defined(__thumb__) || defined(_M_ARM)) +# define XXH_SPLIT_IN_PLACE(in, outLo, outHi) \ + do { \ + /* Undocumented GCC/Clang operand modifier: %e0 = lower D half, %f0 = upper D half */ \ + /* https://github.com/gcc-mirror/gcc/blob/38cf91e5/gcc/config/arm/arm.c#L22486 */ \ + /* https://github.com/llvm-mirror/llvm/blob/2c4ca683/lib/Target/ARM/ARMAsmPrinter.cpp#L399 */ \ + __asm__("vzip.32 %e0, %f0" : "+w" (in)); \ + (outLo) = vget_low_u32 (vreinterpretq_u32_u64(in)); \ + (outHi) = vget_high_u32(vreinterpretq_u32_u64(in)); \ + } while (0) +# else +# define XXH_SPLIT_IN_PLACE(in, outLo, outHi) \ + do { \ + (outLo) = vmovn_u64 (in); \ + (outHi) = vshrn_n_u64 ((in), 32); \ + } while (0) +# endif + +/*! + * @ingroup tuning + * @brief Controls the NEON to scalar ratio for XXH3 + * + * On AArch64 when not optimizing for size, XXH3 will run 6 lanes using NEON and + * 2 lanes on scalar by default. + * + * This can be set to 2, 4, 6, or 8. ARMv7 will default to all 8 NEON lanes, as the + * emulated 64-bit arithmetic is too slow. + * + * Modern ARM CPUs are _very_ sensitive to how their pipelines are used. + * + * For example, the Cortex-A73 can dispatch 3 micro-ops per cycle, but it can't + * have more than 2 NEON (F0/F1) micro-ops. If you are only using NEON instructions, + * you are only using 2/3 of the CPU bandwidth. + * + * This is even more noticeable on the more advanced cores like the A76 which + * can dispatch 8 micro-ops per cycle, but still only 2 NEON micro-ops at once. + * + * Therefore, @ref XXH3_NEON_LANES lanes will be processed using NEON, and the + * remaining lanes will use scalar instructions. This improves the bandwidth + * and also gives the integer pipelines something to do besides twiddling loop + * counters and pointers. + * + * This change benefits CPUs with large micro-op buffers without negatively affecting + * other CPUs: + * + * | Chipset | Dispatch type | NEON only | 6:2 hybrid | Diff. | + * |:----------------------|:--------------------|----------:|-----------:|------:| + * | Snapdragon 730 (A76) | 2 NEON/8 micro-ops | 8.8 GB/s | 10.1 GB/s | ~16% | + * | Snapdragon 835 (A73) | 2 NEON/3 micro-ops | 5.1 GB/s | 5.3 GB/s | ~5% | + * | Marvell PXA1928 (A53) | In-order dual-issue | 1.9 GB/s | 1.9 GB/s | 0% | + * + * It also seems to fix some bad codegen on GCC, making it almost as fast as clang. + * + * @see XXH3_accumulate_512_neon() + */ +# ifndef XXH3_NEON_LANES +# if (defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64) || defined(_M_ARM64EC)) \ + && !defined(__OPTIMIZE_SIZE__) +# define XXH3_NEON_LANES 6 +# else +# define XXH3_NEON_LANES XXH_ACC_NB +# endif +# endif +#endif /* XXH_VECTOR == XXH_NEON */ + +/* + * VSX and Z Vector helpers. + * + * This is very messy, and any pull requests to clean this up are welcome. + * + * There are a lot of problems with supporting VSX and s390x, due to + * inconsistent intrinsics, spotty coverage, and multiple endiannesses. + */ +#if XXH_VECTOR == XXH_VSX +# if defined(__s390x__) +# include +# else +/* gcc's altivec.h can have the unwanted consequence to unconditionally + * #define bool, vector, and pixel keywords, + * with bad consequences for programs already using these keywords for other purposes. + * The paragraph defining these macros is skipped when __APPLE_ALTIVEC__ is defined. + * __APPLE_ALTIVEC__ is _generally_ defined automatically by the compiler, + * but it seems that, in some cases, it isn't. + * Force the build macro to be defined, so that keywords are not altered. + */ +# if defined(__GNUC__) && !defined(__APPLE_ALTIVEC__) +# define __APPLE_ALTIVEC__ +# endif +# include +# endif + +typedef __vector unsigned long long xxh_u64x2; +typedef __vector unsigned char xxh_u8x16; +typedef __vector unsigned xxh_u32x4; + +# ifndef XXH_VSX_BE +# if defined(__BIG_ENDIAN__) \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +# define XXH_VSX_BE 1 +# elif defined(__VEC_ELEMENT_REG_ORDER__) && __VEC_ELEMENT_REG_ORDER__ == __ORDER_BIG_ENDIAN__ +# warning "-maltivec=be is not recommended. Please use native endianness." +# define XXH_VSX_BE 1 +# else +# define XXH_VSX_BE 0 +# endif +# endif /* !defined(XXH_VSX_BE) */ + +# if XXH_VSX_BE +# if defined(__POWER9_VECTOR__) || (defined(__clang__) && defined(__s390x__)) +# define XXH_vec_revb vec_revb +# else +/*! + * A polyfill for POWER9's vec_revb(). + */ +XXH_FORCE_INLINE xxh_u64x2 XXH_vec_revb(xxh_u64x2 val) +{ + xxh_u8x16 const vByteSwap = { 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, + 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08 }; + return vec_perm(val, val, vByteSwap); +} +# endif +# endif /* XXH_VSX_BE */ + +/*! + * Performs an unaligned vector load and byte swaps it on big endian. + */ +XXH_FORCE_INLINE xxh_u64x2 XXH_vec_loadu(const void *ptr) +{ + xxh_u64x2 ret; + XXH_memcpy(&ret, ptr, sizeof(xxh_u64x2)); +# if XXH_VSX_BE + ret = XXH_vec_revb(ret); +# endif + return ret; +} + +/* + * vec_mulo and vec_mule are very problematic intrinsics on PowerPC + * + * These intrinsics weren't added until GCC 8, despite existing for a while, + * and they are endian dependent. Also, their meaning swap depending on version. + * */ +# if defined(__s390x__) + /* s390x is always big endian, no issue on this platform */ +# define XXH_vec_mulo vec_mulo +# define XXH_vec_mule vec_mule +# elif defined(__clang__) && XXH_HAS_BUILTIN(__builtin_altivec_vmuleuw) +/* Clang has a better way to control this, we can just use the builtin which doesn't swap. */ +# define XXH_vec_mulo __builtin_altivec_vmulouw +# define XXH_vec_mule __builtin_altivec_vmuleuw +# else +/* gcc needs inline assembly */ +/* Adapted from https://github.com/google/highwayhash/blob/master/highwayhash/hh_vsx.h. */ +XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mulo(xxh_u32x4 a, xxh_u32x4 b) +{ + xxh_u64x2 result; + __asm__("vmulouw %0, %1, %2" : "=v" (result) : "v" (a), "v" (b)); + return result; +} +XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mule(xxh_u32x4 a, xxh_u32x4 b) +{ + xxh_u64x2 result; + __asm__("vmuleuw %0, %1, %2" : "=v" (result) : "v" (a), "v" (b)); + return result; +} +# endif /* XXH_vec_mulo, XXH_vec_mule */ +#endif /* XXH_VECTOR == XXH_VSX */ + + +/* prefetch + * can be disabled, by declaring XXH_NO_PREFETCH build macro */ +#if defined(XXH_NO_PREFETCH) +# define XXH_PREFETCH(ptr) (void)(ptr) /* disabled */ +#else +# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) /* _mm_prefetch() not defined outside of x86/x64 */ +# include /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */ +# define XXH_PREFETCH(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0) +# elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) ) +# define XXH_PREFETCH(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */) +# else +# define XXH_PREFETCH(ptr) (void)(ptr) /* disabled */ +# endif +#endif /* XXH_NO_PREFETCH */ + + +/* ========================================== + * XXH3 default settings + * ========================================== */ + +#define XXH_SECRET_DEFAULT_SIZE 192 /* minimum XXH3_SECRET_SIZE_MIN */ + +#if (XXH_SECRET_DEFAULT_SIZE < XXH3_SECRET_SIZE_MIN) +# error "default keyset is not large enough" +#endif + +/*! Pseudorandom secret taken directly from FARSH. */ +XXH_ALIGN(64) static const xxh_u8 XXH3_kSecret[XXH_SECRET_DEFAULT_SIZE] = { + 0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c, + 0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f, + 0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21, + 0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0, 0x35, 0x90, 0xe6, 0x81, 0x3a, 0x26, 0x4c, + 0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb, 0x88, 0xd0, 0x65, 0x8b, 0x1b, 0x53, 0x2e, 0xa3, + 0x71, 0x64, 0x48, 0x97, 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac, 0xd8, + 0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7, 0xc7, 0x0b, 0x4f, 0x1d, + 0x8a, 0x51, 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31, 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64, + 0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb, + 0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e, + 0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce, + 0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e, +}; + + +#ifdef XXH_OLD_NAMES +# define kSecret XXH3_kSecret +#endif + +#ifdef XXH_DOXYGEN +/*! + * @brief Calculates a 32-bit to 64-bit long multiply. + * + * Implemented as a macro. + * + * Wraps `__emulu` on MSVC x86 because it tends to call `__allmul` when it doesn't + * need to (but it shouldn't need to anyways, it is about 7 instructions to do + * a 64x64 multiply...). Since we know that this will _always_ emit `MULL`, we + * use that instead of the normal method. + * + * If you are compiling for platforms like Thumb-1 and don't have a better option, + * you may also want to write your own long multiply routine here. + * + * @param x, y Numbers to be multiplied + * @return 64-bit product of the low 32 bits of @p x and @p y. + */ +XXH_FORCE_INLINE xxh_u64 +XXH_mult32to64(xxh_u64 x, xxh_u64 y) +{ + return (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF); +} +#elif defined(_MSC_VER) && defined(_M_IX86) +# define XXH_mult32to64(x, y) __emulu((unsigned)(x), (unsigned)(y)) +#else +/* + * Downcast + upcast is usually better than masking on older compilers like + * GCC 4.2 (especially 32-bit ones), all without affecting newer compilers. + * + * The other method, (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF), will AND both operands + * and perform a full 64x64 multiply -- entirely redundant on 32-bit. + */ +# define XXH_mult32to64(x, y) ((xxh_u64)(xxh_u32)(x) * (xxh_u64)(xxh_u32)(y)) +#endif + +/*! + * @brief Calculates a 64->128-bit long multiply. + * + * Uses `__uint128_t` and `_umul128` if available, otherwise uses a scalar + * version. + * + * @param lhs , rhs The 64-bit integers to be multiplied + * @return The 128-bit result represented in an @ref XXH128_hash_t. + */ +static XXH128_hash_t +XXH_mult64to128(xxh_u64 lhs, xxh_u64 rhs) +{ + /* + * GCC/Clang __uint128_t method. + * + * On most 64-bit targets, GCC and Clang define a __uint128_t type. + * This is usually the best way as it usually uses a native long 64-bit + * multiply, such as MULQ on x86_64 or MUL + UMULH on aarch64. + * + * Usually. + * + * Despite being a 32-bit platform, Clang (and emscripten) define this type + * despite not having the arithmetic for it. This results in a laggy + * compiler builtin call which calculates a full 128-bit multiply. + * In that case it is best to use the portable one. + * https://github.com/Cyan4973/xxHash/issues/211#issuecomment-515575677 + */ +#if (defined(__GNUC__) || defined(__clang__)) && !defined(__wasm__) \ + && defined(__SIZEOF_INT128__) \ + || (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128) + + __uint128_t const product = (__uint128_t)lhs * (__uint128_t)rhs; + XXH128_hash_t r128; + r128.low64 = (xxh_u64)(product); + r128.high64 = (xxh_u64)(product >> 64); + return r128; + + /* + * MSVC for x64's _umul128 method. + * + * xxh_u64 _umul128(xxh_u64 Multiplier, xxh_u64 Multiplicand, xxh_u64 *HighProduct); + * + * This compiles to single operand MUL on x64. + */ +#elif (defined(_M_X64) || defined(_M_IA64)) && !defined(_M_ARM64EC) + +#ifndef _MSC_VER +# pragma intrinsic(_umul128) +#endif + xxh_u64 product_high; + xxh_u64 const product_low = _umul128(lhs, rhs, &product_high); + XXH128_hash_t r128; + r128.low64 = product_low; + r128.high64 = product_high; + return r128; + + /* + * MSVC for ARM64's __umulh method. + * + * This compiles to the same MUL + UMULH as GCC/Clang's __uint128_t method. + */ +#elif defined(_M_ARM64) || defined(_M_ARM64EC) + +#ifndef _MSC_VER +# pragma intrinsic(__umulh) +#endif + XXH128_hash_t r128; + r128.low64 = lhs * rhs; + r128.high64 = __umulh(lhs, rhs); + return r128; + +#else + /* + * Portable scalar method. Optimized for 32-bit and 64-bit ALUs. + * + * This is a fast and simple grade school multiply, which is shown below + * with base 10 arithmetic instead of base 0x100000000. + * + * 9 3 // D2 lhs = 93 + * x 7 5 // D2 rhs = 75 + * ---------- + * 1 5 // D2 lo_lo = (93 % 10) * (75 % 10) = 15 + * 4 5 | // D2 hi_lo = (93 / 10) * (75 % 10) = 45 + * 2 1 | // D2 lo_hi = (93 % 10) * (75 / 10) = 21 + * + 6 3 | | // D2 hi_hi = (93 / 10) * (75 / 10) = 63 + * --------- + * 2 7 | // D2 cross = (15 / 10) + (45 % 10) + 21 = 27 + * + 6 7 | | // D2 upper = (27 / 10) + (45 / 10) + 63 = 67 + * --------- + * 6 9 7 5 // D4 res = (27 * 10) + (15 % 10) + (67 * 100) = 6975 + * + * The reasons for adding the products like this are: + * 1. It avoids manual carry tracking. Just like how + * (9 * 9) + 9 + 9 = 99, the same applies with this for UINT64_MAX. + * This avoids a lot of complexity. + * + * 2. It hints for, and on Clang, compiles to, the powerful UMAAL + * instruction available in ARM's Digital Signal Processing extension + * in 32-bit ARMv6 and later, which is shown below: + * + * void UMAAL(xxh_u32 *RdLo, xxh_u32 *RdHi, xxh_u32 Rn, xxh_u32 Rm) + * { + * xxh_u64 product = (xxh_u64)*RdLo * (xxh_u64)*RdHi + Rn + Rm; + * *RdLo = (xxh_u32)(product & 0xFFFFFFFF); + * *RdHi = (xxh_u32)(product >> 32); + * } + * + * This instruction was designed for efficient long multiplication, and + * allows this to be calculated in only 4 instructions at speeds + * comparable to some 64-bit ALUs. + * + * 3. It isn't terrible on other platforms. Usually this will be a couple + * of 32-bit ADD/ADCs. + */ + + /* First calculate all of the cross products. */ + xxh_u64 const lo_lo = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs & 0xFFFFFFFF); + xxh_u64 const hi_lo = XXH_mult32to64(lhs >> 32, rhs & 0xFFFFFFFF); + xxh_u64 const lo_hi = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs >> 32); + xxh_u64 const hi_hi = XXH_mult32to64(lhs >> 32, rhs >> 32); + + /* Now add the products together. These will never overflow. */ + xxh_u64 const cross = (lo_lo >> 32) + (hi_lo & 0xFFFFFFFF) + lo_hi; + xxh_u64 const upper = (hi_lo >> 32) + (cross >> 32) + hi_hi; + xxh_u64 const lower = (cross << 32) | (lo_lo & 0xFFFFFFFF); + + XXH128_hash_t r128; + r128.low64 = lower; + r128.high64 = upper; + return r128; +#endif +} + +/*! + * @brief Calculates a 64-bit to 128-bit multiply, then XOR folds it. + * + * The reason for the separate function is to prevent passing too many structs + * around by value. This will hopefully inline the multiply, but we don't force it. + * + * @param lhs , rhs The 64-bit integers to multiply + * @return The low 64 bits of the product XOR'd by the high 64 bits. + * @see XXH_mult64to128() + */ +static xxh_u64 +XXH3_mul128_fold64(xxh_u64 lhs, xxh_u64 rhs) +{ + XXH128_hash_t product = XXH_mult64to128(lhs, rhs); + return product.low64 ^ product.high64; +} + +/*! Seems to produce slightly better code on GCC for some reason. */ +XXH_FORCE_INLINE xxh_u64 XXH_xorshift64(xxh_u64 v64, int shift) +{ + XXH_ASSERT(0 <= shift && shift < 64); + return v64 ^ (v64 >> shift); +} + +/* + * This is a fast avalanche stage, + * suitable when input bits are already partially mixed + */ +static XXH64_hash_t XXH3_avalanche(xxh_u64 h64) +{ + h64 = XXH_xorshift64(h64, 37); + h64 *= 0x165667919E3779F9ULL; + h64 = XXH_xorshift64(h64, 32); + return h64; +} + +/* + * This is a stronger avalanche, + * inspired by Pelle Evensen's rrmxmx + * preferable when input has not been previously mixed + */ +static XXH64_hash_t XXH3_rrmxmx(xxh_u64 h64, xxh_u64 len) +{ + /* this mix is inspired by Pelle Evensen's rrmxmx */ + h64 ^= XXH_rotl64(h64, 49) ^ XXH_rotl64(h64, 24); + h64 *= 0x9FB21C651E98DF25ULL; + h64 ^= (h64 >> 35) + len ; + h64 *= 0x9FB21C651E98DF25ULL; + return XXH_xorshift64(h64, 28); +} + + +/* ========================================== + * Short keys + * ========================================== + * One of the shortcomings of XXH32 and XXH64 was that their performance was + * sub-optimal on short lengths. It used an iterative algorithm which strongly + * favored lengths that were a multiple of 4 or 8. + * + * Instead of iterating over individual inputs, we use a set of single shot + * functions which piece together a range of lengths and operate in constant time. + * + * Additionally, the number of multiplies has been significantly reduced. This + * reduces latency, especially when emulating 64-bit multiplies on 32-bit. + * + * Depending on the platform, this may or may not be faster than XXH32, but it + * is almost guaranteed to be faster than XXH64. + */ + +/* + * At very short lengths, there isn't enough input to fully hide secrets, or use + * the entire secret. + * + * There is also only a limited amount of mixing we can do before significantly + * impacting performance. + * + * Therefore, we use different sections of the secret and always mix two secret + * samples with an XOR. This should have no effect on performance on the + * seedless or withSeed variants because everything _should_ be constant folded + * by modern compilers. + * + * The XOR mixing hides individual parts of the secret and increases entropy. + * + * This adds an extra layer of strength for custom secrets. + */ +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_1to3_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(1 <= len && len <= 3); + XXH_ASSERT(secret != NULL); + /* + * len = 1: combined = { input[0], 0x01, input[0], input[0] } + * len = 2: combined = { input[1], 0x02, input[0], input[1] } + * len = 3: combined = { input[2], 0x03, input[0], input[1] } + */ + { xxh_u8 const c1 = input[0]; + xxh_u8 const c2 = input[len >> 1]; + xxh_u8 const c3 = input[len - 1]; + xxh_u32 const combined = ((xxh_u32)c1 << 16) | ((xxh_u32)c2 << 24) + | ((xxh_u32)c3 << 0) | ((xxh_u32)len << 8); + xxh_u64 const bitflip = (XXH_readLE32(secret) ^ XXH_readLE32(secret+4)) + seed; + xxh_u64 const keyed = (xxh_u64)combined ^ bitflip; + return XXH64_avalanche(keyed); + } +} + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_4to8_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(4 <= len && len <= 8); + seed ^= (xxh_u64)XXH_swap32((xxh_u32)seed) << 32; + { xxh_u32 const input1 = XXH_readLE32(input); + xxh_u32 const input2 = XXH_readLE32(input + len - 4); + xxh_u64 const bitflip = (XXH_readLE64(secret+8) ^ XXH_readLE64(secret+16)) - seed; + xxh_u64 const input64 = input2 + (((xxh_u64)input1) << 32); + xxh_u64 const keyed = input64 ^ bitflip; + return XXH3_rrmxmx(keyed, len); + } +} + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_9to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(9 <= len && len <= 16); + { xxh_u64 const bitflip1 = (XXH_readLE64(secret+24) ^ XXH_readLE64(secret+32)) + seed; + xxh_u64 const bitflip2 = (XXH_readLE64(secret+40) ^ XXH_readLE64(secret+48)) - seed; + xxh_u64 const input_lo = XXH_readLE64(input) ^ bitflip1; + xxh_u64 const input_hi = XXH_readLE64(input + len - 8) ^ bitflip2; + xxh_u64 const acc = len + + XXH_swap64(input_lo) + input_hi + + XXH3_mul128_fold64(input_lo, input_hi); + return XXH3_avalanche(acc); + } +} + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_0to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(len <= 16); + { if (XXH_likely(len > 8)) return XXH3_len_9to16_64b(input, len, secret, seed); + if (XXH_likely(len >= 4)) return XXH3_len_4to8_64b(input, len, secret, seed); + if (len) return XXH3_len_1to3_64b(input, len, secret, seed); + return XXH64_avalanche(seed ^ (XXH_readLE64(secret+56) ^ XXH_readLE64(secret+64))); + } +} + +/* + * DISCLAIMER: There are known *seed-dependent* multicollisions here due to + * multiplication by zero, affecting hashes of lengths 17 to 240. + * + * However, they are very unlikely. + * + * Keep this in mind when using the unseeded XXH3_64bits() variant: As with all + * unseeded non-cryptographic hashes, it does not attempt to defend itself + * against specially crafted inputs, only random inputs. + * + * Compared to classic UMAC where a 1 in 2^31 chance of 4 consecutive bytes + * cancelling out the secret is taken an arbitrary number of times (addressed + * in XXH3_accumulate_512), this collision is very unlikely with random inputs + * and/or proper seeding: + * + * This only has a 1 in 2^63 chance of 8 consecutive bytes cancelling out, in a + * function that is only called up to 16 times per hash with up to 240 bytes of + * input. + * + * This is not too bad for a non-cryptographic hash function, especially with + * only 64 bit outputs. + * + * The 128-bit variant (which trades some speed for strength) is NOT affected + * by this, although it is always a good idea to use a proper seed if you care + * about strength. + */ +XXH_FORCE_INLINE xxh_u64 XXH3_mix16B(const xxh_u8* XXH_RESTRICT input, + const xxh_u8* XXH_RESTRICT secret, xxh_u64 seed64) +{ +#if defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \ + && defined(__i386__) && defined(__SSE2__) /* x86 + SSE2 */ \ + && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable like XXH32 hack */ + /* + * UGLY HACK: + * GCC for x86 tends to autovectorize the 128-bit multiply, resulting in + * slower code. + * + * By forcing seed64 into a register, we disrupt the cost model and + * cause it to scalarize. See `XXH32_round()` + * + * FIXME: Clang's output is still _much_ faster -- On an AMD Ryzen 3600, + * XXH3_64bits @ len=240 runs at 4.6 GB/s with Clang 9, but 3.3 GB/s on + * GCC 9.2, despite both emitting scalar code. + * + * GCC generates much better scalar code than Clang for the rest of XXH3, + * which is why finding a more optimal codepath is an interest. + */ + XXH_COMPILER_GUARD(seed64); +#endif + { xxh_u64 const input_lo = XXH_readLE64(input); + xxh_u64 const input_hi = XXH_readLE64(input+8); + return XXH3_mul128_fold64( + input_lo ^ (XXH_readLE64(secret) + seed64), + input_hi ^ (XXH_readLE64(secret+8) - seed64) + ); + } +} + +/* For mid range keys, XXH3 uses a Mum-hash variant. */ +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_17to128_64b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(16 < len && len <= 128); + + { xxh_u64 acc = len * XXH_PRIME64_1; + if (len > 32) { + if (len > 64) { + if (len > 96) { + acc += XXH3_mix16B(input+48, secret+96, seed); + acc += XXH3_mix16B(input+len-64, secret+112, seed); + } + acc += XXH3_mix16B(input+32, secret+64, seed); + acc += XXH3_mix16B(input+len-48, secret+80, seed); + } + acc += XXH3_mix16B(input+16, secret+32, seed); + acc += XXH3_mix16B(input+len-32, secret+48, seed); + } + acc += XXH3_mix16B(input+0, secret+0, seed); + acc += XXH3_mix16B(input+len-16, secret+16, seed); + + return XXH3_avalanche(acc); + } +} + +#define XXH3_MIDSIZE_MAX 240 + +XXH_NO_INLINE XXH64_hash_t +XXH3_len_129to240_64b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX); + + #define XXH3_MIDSIZE_STARTOFFSET 3 + #define XXH3_MIDSIZE_LASTOFFSET 17 + + { xxh_u64 acc = len * XXH_PRIME64_1; + int const nbRounds = (int)len / 16; + int i; + for (i=0; i<8; i++) { + acc += XXH3_mix16B(input+(16*i), secret+(16*i), seed); + } + acc = XXH3_avalanche(acc); + XXH_ASSERT(nbRounds >= 8); +#if defined(__clang__) /* Clang */ \ + && (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \ + && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable */ + /* + * UGLY HACK: + * Clang for ARMv7-A tries to vectorize this loop, similar to GCC x86. + * In everywhere else, it uses scalar code. + * + * For 64->128-bit multiplies, even if the NEON was 100% optimal, it + * would still be slower than UMAAL (see XXH_mult64to128). + * + * Unfortunately, Clang doesn't handle the long multiplies properly and + * converts them to the nonexistent "vmulq_u64" intrinsic, which is then + * scalarized into an ugly mess of VMOV.32 instructions. + * + * This mess is difficult to avoid without turning autovectorization + * off completely, but they are usually relatively minor and/or not + * worth it to fix. + * + * This loop is the easiest to fix, as unlike XXH32, this pragma + * _actually works_ because it is a loop vectorization instead of an + * SLP vectorization. + */ + #pragma clang loop vectorize(disable) +#endif + for (i=8 ; i < nbRounds; i++) { + acc += XXH3_mix16B(input+(16*i), secret+(16*(i-8)) + XXH3_MIDSIZE_STARTOFFSET, seed); + } + /* last bytes */ + acc += XXH3_mix16B(input + len - 16, secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET, seed); + return XXH3_avalanche(acc); + } +} + + +/* ======= Long Keys ======= */ + +#define XXH_STRIPE_LEN 64 +#define XXH_SECRET_CONSUME_RATE 8 /* nb of secret bytes consumed at each accumulation */ +#define XXH_ACC_NB (XXH_STRIPE_LEN / sizeof(xxh_u64)) + +#ifdef XXH_OLD_NAMES +# define STRIPE_LEN XXH_STRIPE_LEN +# define ACC_NB XXH_ACC_NB +#endif + +XXH_FORCE_INLINE void XXH_writeLE64(void* dst, xxh_u64 v64) +{ + if (!XXH_CPU_LITTLE_ENDIAN) v64 = XXH_swap64(v64); + XXH_memcpy(dst, &v64, sizeof(v64)); +} + +/* Several intrinsic functions below are supposed to accept __int64 as argument, + * as documented in https://software.intel.com/sites/landingpage/IntrinsicsGuide/ . + * However, several environments do not define __int64 type, + * requiring a workaround. + */ +#if !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) + typedef int64_t xxh_i64; +#else + /* the following type must have a width of 64-bit */ + typedef long long xxh_i64; +#endif + + +/* + * XXH3_accumulate_512 is the tightest loop for long inputs, and it is the most optimized. + * + * It is a hardened version of UMAC, based off of FARSH's implementation. + * + * This was chosen because it adapts quite well to 32-bit, 64-bit, and SIMD + * implementations, and it is ridiculously fast. + * + * We harden it by mixing the original input to the accumulators as well as the product. + * + * This means that in the (relatively likely) case of a multiply by zero, the + * original input is preserved. + * + * On 128-bit inputs, we swap 64-bit pairs when we add the input to improve + * cross-pollination, as otherwise the upper and lower halves would be + * essentially independent. + * + * This doesn't matter on 64-bit hashes since they all get merged together in + * the end, so we skip the extra step. + * + * Both XXH3_64bits and XXH3_128bits use this subroutine. + */ + +#if (XXH_VECTOR == XXH_AVX512) \ + || (defined(XXH_DISPATCH_AVX512) && XXH_DISPATCH_AVX512 != 0) + +#ifndef XXH_TARGET_AVX512 +# define XXH_TARGET_AVX512 /* disable attribute target */ +#endif + +XXH_FORCE_INLINE XXH_TARGET_AVX512 void +XXH3_accumulate_512_avx512(void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + __m512i* const xacc = (__m512i *) acc; + XXH_ASSERT((((size_t)acc) & 63) == 0); + XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i)); + + { + /* data_vec = input[0]; */ + __m512i const data_vec = _mm512_loadu_si512 (input); + /* key_vec = secret[0]; */ + __m512i const key_vec = _mm512_loadu_si512 (secret); + /* data_key = data_vec ^ key_vec; */ + __m512i const data_key = _mm512_xor_si512 (data_vec, key_vec); + /* data_key_lo = data_key >> 32; */ + __m512i const data_key_lo = _mm512_shuffle_epi32 (data_key, (_MM_PERM_ENUM)_MM_SHUFFLE(0, 3, 0, 1)); + /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ + __m512i const product = _mm512_mul_epu32 (data_key, data_key_lo); + /* xacc[0] += swap(data_vec); */ + __m512i const data_swap = _mm512_shuffle_epi32(data_vec, (_MM_PERM_ENUM)_MM_SHUFFLE(1, 0, 3, 2)); + __m512i const sum = _mm512_add_epi64(*xacc, data_swap); + /* xacc[0] += product; */ + *xacc = _mm512_add_epi64(product, sum); + } +} + +/* + * XXH3_scrambleAcc: Scrambles the accumulators to improve mixing. + * + * Multiplication isn't perfect, as explained by Google in HighwayHash: + * + * // Multiplication mixes/scrambles bytes 0-7 of the 64-bit result to + * // varying degrees. In descending order of goodness, bytes + * // 3 4 2 5 1 6 0 7 have quality 228 224 164 160 100 96 36 32. + * // As expected, the upper and lower bytes are much worse. + * + * Source: https://github.com/google/highwayhash/blob/0aaf66b/highwayhash/hh_avx2.h#L291 + * + * Since our algorithm uses a pseudorandom secret to add some variance into the + * mix, we don't need to (or want to) mix as often or as much as HighwayHash does. + * + * This isn't as tight as XXH3_accumulate, but still written in SIMD to avoid + * extraction. + * + * Both XXH3_64bits and XXH3_128bits use this subroutine. + */ + +XXH_FORCE_INLINE XXH_TARGET_AVX512 void +XXH3_scrambleAcc_avx512(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 63) == 0); + XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i)); + { __m512i* const xacc = (__m512i*) acc; + const __m512i prime32 = _mm512_set1_epi32((int)XXH_PRIME32_1); + + /* xacc[0] ^= (xacc[0] >> 47) */ + __m512i const acc_vec = *xacc; + __m512i const shifted = _mm512_srli_epi64 (acc_vec, 47); + __m512i const data_vec = _mm512_xor_si512 (acc_vec, shifted); + /* xacc[0] ^= secret; */ + __m512i const key_vec = _mm512_loadu_si512 (secret); + __m512i const data_key = _mm512_xor_si512 (data_vec, key_vec); + + /* xacc[0] *= XXH_PRIME32_1; */ + __m512i const data_key_hi = _mm512_shuffle_epi32 (data_key, (_MM_PERM_ENUM)_MM_SHUFFLE(0, 3, 0, 1)); + __m512i const prod_lo = _mm512_mul_epu32 (data_key, prime32); + __m512i const prod_hi = _mm512_mul_epu32 (data_key_hi, prime32); + *xacc = _mm512_add_epi64(prod_lo, _mm512_slli_epi64(prod_hi, 32)); + } +} + +XXH_FORCE_INLINE XXH_TARGET_AVX512 void +XXH3_initCustomSecret_avx512(void* XXH_RESTRICT customSecret, xxh_u64 seed64) +{ + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 63) == 0); + XXH_STATIC_ASSERT(XXH_SEC_ALIGN == 64); + XXH_ASSERT(((size_t)customSecret & 63) == 0); + (void)(&XXH_writeLE64); + { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m512i); + __m512i const seed = _mm512_mask_set1_epi64(_mm512_set1_epi64((xxh_i64)seed64), 0xAA, (xxh_i64)(0U - seed64)); + + const __m512i* const src = (const __m512i*) ((const void*) XXH3_kSecret); + __m512i* const dest = ( __m512i*) customSecret; + int i; + XXH_ASSERT(((size_t)src & 63) == 0); /* control alignment */ + XXH_ASSERT(((size_t)dest & 63) == 0); + for (i=0; i < nbRounds; ++i) { + /* GCC has a bug, _mm512_stream_load_si512 accepts 'void*', not 'void const*', + * this will warn "discards 'const' qualifier". */ + union { + const __m512i* cp; + void* p; + } remote_const_void; + remote_const_void.cp = src + i; + dest[i] = _mm512_add_epi64(_mm512_stream_load_si512(remote_const_void.p), seed); + } } +} + +#endif + +#if (XXH_VECTOR == XXH_AVX2) \ + || (defined(XXH_DISPATCH_AVX2) && XXH_DISPATCH_AVX2 != 0) + +#ifndef XXH_TARGET_AVX2 +# define XXH_TARGET_AVX2 /* disable attribute target */ +#endif + +XXH_FORCE_INLINE XXH_TARGET_AVX2 void +XXH3_accumulate_512_avx2( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 31) == 0); + { __m256i* const xacc = (__m256i *) acc; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ + const __m256i* const xinput = (const __m256i *) input; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ + const __m256i* const xsecret = (const __m256i *) secret; + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(__m256i); i++) { + /* data_vec = xinput[i]; */ + __m256i const data_vec = _mm256_loadu_si256 (xinput+i); + /* key_vec = xsecret[i]; */ + __m256i const key_vec = _mm256_loadu_si256 (xsecret+i); + /* data_key = data_vec ^ key_vec; */ + __m256i const data_key = _mm256_xor_si256 (data_vec, key_vec); + /* data_key_lo = data_key >> 32; */ + __m256i const data_key_lo = _mm256_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); + /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ + __m256i const product = _mm256_mul_epu32 (data_key, data_key_lo); + /* xacc[i] += swap(data_vec); */ + __m256i const data_swap = _mm256_shuffle_epi32(data_vec, _MM_SHUFFLE(1, 0, 3, 2)); + __m256i const sum = _mm256_add_epi64(xacc[i], data_swap); + /* xacc[i] += product; */ + xacc[i] = _mm256_add_epi64(product, sum); + } } +} + +XXH_FORCE_INLINE XXH_TARGET_AVX2 void +XXH3_scrambleAcc_avx2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 31) == 0); + { __m256i* const xacc = (__m256i*) acc; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ + const __m256i* const xsecret = (const __m256i *) secret; + const __m256i prime32 = _mm256_set1_epi32((int)XXH_PRIME32_1); + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(__m256i); i++) { + /* xacc[i] ^= (xacc[i] >> 47) */ + __m256i const acc_vec = xacc[i]; + __m256i const shifted = _mm256_srli_epi64 (acc_vec, 47); + __m256i const data_vec = _mm256_xor_si256 (acc_vec, shifted); + /* xacc[i] ^= xsecret; */ + __m256i const key_vec = _mm256_loadu_si256 (xsecret+i); + __m256i const data_key = _mm256_xor_si256 (data_vec, key_vec); + + /* xacc[i] *= XXH_PRIME32_1; */ + __m256i const data_key_hi = _mm256_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); + __m256i const prod_lo = _mm256_mul_epu32 (data_key, prime32); + __m256i const prod_hi = _mm256_mul_epu32 (data_key_hi, prime32); + xacc[i] = _mm256_add_epi64(prod_lo, _mm256_slli_epi64(prod_hi, 32)); + } + } +} + +XXH_FORCE_INLINE XXH_TARGET_AVX2 void XXH3_initCustomSecret_avx2(void* XXH_RESTRICT customSecret, xxh_u64 seed64) +{ + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 31) == 0); + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE / sizeof(__m256i)) == 6); + XXH_STATIC_ASSERT(XXH_SEC_ALIGN <= 64); + (void)(&XXH_writeLE64); + XXH_PREFETCH(customSecret); + { __m256i const seed = _mm256_set_epi64x((xxh_i64)(0U - seed64), (xxh_i64)seed64, (xxh_i64)(0U - seed64), (xxh_i64)seed64); + + const __m256i* const src = (const __m256i*) ((const void*) XXH3_kSecret); + __m256i* dest = ( __m256i*) customSecret; + +# if defined(__GNUC__) || defined(__clang__) + /* + * On GCC & Clang, marking 'dest' as modified will cause the compiler: + * - do not extract the secret from sse registers in the internal loop + * - use less common registers, and avoid pushing these reg into stack + */ + XXH_COMPILER_GUARD(dest); +# endif + XXH_ASSERT(((size_t)src & 31) == 0); /* control alignment */ + XXH_ASSERT(((size_t)dest & 31) == 0); + + /* GCC -O2 need unroll loop manually */ + dest[0] = _mm256_add_epi64(_mm256_stream_load_si256(src+0), seed); + dest[1] = _mm256_add_epi64(_mm256_stream_load_si256(src+1), seed); + dest[2] = _mm256_add_epi64(_mm256_stream_load_si256(src+2), seed); + dest[3] = _mm256_add_epi64(_mm256_stream_load_si256(src+3), seed); + dest[4] = _mm256_add_epi64(_mm256_stream_load_si256(src+4), seed); + dest[5] = _mm256_add_epi64(_mm256_stream_load_si256(src+5), seed); + } +} + +#endif + +/* x86dispatch always generates SSE2 */ +#if (XXH_VECTOR == XXH_SSE2) || defined(XXH_X86DISPATCH) + +#ifndef XXH_TARGET_SSE2 +# define XXH_TARGET_SSE2 /* disable attribute target */ +#endif + +XXH_FORCE_INLINE XXH_TARGET_SSE2 void +XXH3_accumulate_512_sse2( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + /* SSE2 is just a half-scale version of the AVX2 version. */ + XXH_ASSERT((((size_t)acc) & 15) == 0); + { __m128i* const xacc = (__m128i *) acc; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ + const __m128i* const xinput = (const __m128i *) input; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ + const __m128i* const xsecret = (const __m128i *) secret; + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(__m128i); i++) { + /* data_vec = xinput[i]; */ + __m128i const data_vec = _mm_loadu_si128 (xinput+i); + /* key_vec = xsecret[i]; */ + __m128i const key_vec = _mm_loadu_si128 (xsecret+i); + /* data_key = data_vec ^ key_vec; */ + __m128i const data_key = _mm_xor_si128 (data_vec, key_vec); + /* data_key_lo = data_key >> 32; */ + __m128i const data_key_lo = _mm_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); + /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ + __m128i const product = _mm_mul_epu32 (data_key, data_key_lo); + /* xacc[i] += swap(data_vec); */ + __m128i const data_swap = _mm_shuffle_epi32(data_vec, _MM_SHUFFLE(1,0,3,2)); + __m128i const sum = _mm_add_epi64(xacc[i], data_swap); + /* xacc[i] += product; */ + xacc[i] = _mm_add_epi64(product, sum); + } } +} + +XXH_FORCE_INLINE XXH_TARGET_SSE2 void +XXH3_scrambleAcc_sse2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + { __m128i* const xacc = (__m128i*) acc; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ + const __m128i* const xsecret = (const __m128i *) secret; + const __m128i prime32 = _mm_set1_epi32((int)XXH_PRIME32_1); + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(__m128i); i++) { + /* xacc[i] ^= (xacc[i] >> 47) */ + __m128i const acc_vec = xacc[i]; + __m128i const shifted = _mm_srli_epi64 (acc_vec, 47); + __m128i const data_vec = _mm_xor_si128 (acc_vec, shifted); + /* xacc[i] ^= xsecret[i]; */ + __m128i const key_vec = _mm_loadu_si128 (xsecret+i); + __m128i const data_key = _mm_xor_si128 (data_vec, key_vec); + + /* xacc[i] *= XXH_PRIME32_1; */ + __m128i const data_key_hi = _mm_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); + __m128i const prod_lo = _mm_mul_epu32 (data_key, prime32); + __m128i const prod_hi = _mm_mul_epu32 (data_key_hi, prime32); + xacc[i] = _mm_add_epi64(prod_lo, _mm_slli_epi64(prod_hi, 32)); + } + } +} + +XXH_FORCE_INLINE XXH_TARGET_SSE2 void XXH3_initCustomSecret_sse2(void* XXH_RESTRICT customSecret, xxh_u64 seed64) +{ + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0); + (void)(&XXH_writeLE64); + { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m128i); + +# if defined(_MSC_VER) && defined(_M_IX86) && _MSC_VER < 1900 + /* MSVC 32bit mode does not support _mm_set_epi64x before 2015 */ + XXH_ALIGN(16) const xxh_i64 seed64x2[2] = { (xxh_i64)seed64, (xxh_i64)(0U - seed64) }; + __m128i const seed = _mm_load_si128((__m128i const*)seed64x2); +# else + __m128i const seed = _mm_set_epi64x((xxh_i64)(0U - seed64), (xxh_i64)seed64); +# endif + int i; + + const void* const src16 = XXH3_kSecret; + __m128i* dst16 = (__m128i*) customSecret; +# if defined(__GNUC__) || defined(__clang__) + /* + * On GCC & Clang, marking 'dest' as modified will cause the compiler: + * - do not extract the secret from sse registers in the internal loop + * - use less common registers, and avoid pushing these reg into stack + */ + XXH_COMPILER_GUARD(dst16); +# endif + XXH_ASSERT(((size_t)src16 & 15) == 0); /* control alignment */ + XXH_ASSERT(((size_t)dst16 & 15) == 0); + + for (i=0; i < nbRounds; ++i) { + dst16[i] = _mm_add_epi64(_mm_load_si128((const __m128i *)src16+i), seed); + } } +} + +#endif + +#if (XXH_VECTOR == XXH_NEON) + +/* forward declarations for the scalar routines */ +XXH_FORCE_INLINE void +XXH3_scalarRound(void* XXH_RESTRICT acc, void const* XXH_RESTRICT input, + void const* XXH_RESTRICT secret, size_t lane); + +XXH_FORCE_INLINE void +XXH3_scalarScrambleRound(void* XXH_RESTRICT acc, + void const* XXH_RESTRICT secret, size_t lane); + +/*! + * @internal + * @brief The bulk processing loop for NEON. + * + * The NEON code path is actually partially scalar when running on AArch64. This + * is to optimize the pipelining and can have up to 15% speedup depending on the + * CPU, and it also mitigates some GCC codegen issues. + * + * @see XXH3_NEON_LANES for configuring this and details about this optimization. + */ +XXH_FORCE_INLINE void +XXH3_accumulate_512_neon( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + XXH_STATIC_ASSERT(XXH3_NEON_LANES > 0 && XXH3_NEON_LANES <= XXH_ACC_NB && XXH3_NEON_LANES % 2 == 0); + { + uint64x2_t* const xacc = (uint64x2_t *) acc; + /* We don't use a uint32x4_t pointer because it causes bus errors on ARMv7. */ + uint8_t const* const xinput = (const uint8_t *) input; + uint8_t const* const xsecret = (const uint8_t *) secret; + + size_t i; + /* NEON for the first few lanes (these loops are normally interleaved) */ + for (i=0; i < XXH3_NEON_LANES / 2; i++) { + /* data_vec = xinput[i]; */ + uint8x16_t data_vec = vld1q_u8(xinput + (i * 16)); + /* key_vec = xsecret[i]; */ + uint8x16_t key_vec = vld1q_u8(xsecret + (i * 16)); + uint64x2_t data_key; + uint32x2_t data_key_lo, data_key_hi; + /* xacc[i] += swap(data_vec); */ + uint64x2_t const data64 = vreinterpretq_u64_u8(data_vec); + uint64x2_t const swapped = vextq_u64(data64, data64, 1); + xacc[i] = vaddq_u64 (xacc[i], swapped); + /* data_key = data_vec ^ key_vec; */ + data_key = vreinterpretq_u64_u8(veorq_u8(data_vec, key_vec)); + /* data_key_lo = (uint32x2_t) (data_key & 0xFFFFFFFF); + * data_key_hi = (uint32x2_t) (data_key >> 32); + * data_key = UNDEFINED; */ + XXH_SPLIT_IN_PLACE(data_key, data_key_lo, data_key_hi); + /* xacc[i] += (uint64x2_t) data_key_lo * (uint64x2_t) data_key_hi; */ + xacc[i] = vmlal_u32 (xacc[i], data_key_lo, data_key_hi); + + } + /* Scalar for the remainder. This may be a zero iteration loop. */ + for (i = XXH3_NEON_LANES; i < XXH_ACC_NB; i++) { + XXH3_scalarRound(acc, input, secret, i); + } + } +} + +XXH_FORCE_INLINE void +XXH3_scrambleAcc_neon(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + + { uint64x2_t* xacc = (uint64x2_t*) acc; + uint8_t const* xsecret = (uint8_t const*) secret; + uint32x2_t prime = vdup_n_u32 (XXH_PRIME32_1); + + size_t i; + /* NEON for the first few lanes (these loops are normally interleaved) */ + for (i=0; i < XXH3_NEON_LANES / 2; i++) { + /* xacc[i] ^= (xacc[i] >> 47); */ + uint64x2_t acc_vec = xacc[i]; + uint64x2_t shifted = vshrq_n_u64 (acc_vec, 47); + uint64x2_t data_vec = veorq_u64 (acc_vec, shifted); + + /* xacc[i] ^= xsecret[i]; */ + uint8x16_t key_vec = vld1q_u8 (xsecret + (i * 16)); + uint64x2_t data_key = veorq_u64 (data_vec, vreinterpretq_u64_u8(key_vec)); + + /* xacc[i] *= XXH_PRIME32_1 */ + uint32x2_t data_key_lo, data_key_hi; + /* data_key_lo = (uint32x2_t) (xacc[i] & 0xFFFFFFFF); + * data_key_hi = (uint32x2_t) (xacc[i] >> 32); + * xacc[i] = UNDEFINED; */ + XXH_SPLIT_IN_PLACE(data_key, data_key_lo, data_key_hi); + { /* + * prod_hi = (data_key >> 32) * XXH_PRIME32_1; + * + * Avoid vmul_u32 + vshll_n_u32 since Clang 6 and 7 will + * incorrectly "optimize" this: + * tmp = vmul_u32(vmovn_u64(a), vmovn_u64(b)); + * shifted = vshll_n_u32(tmp, 32); + * to this: + * tmp = "vmulq_u64"(a, b); // no such thing! + * shifted = vshlq_n_u64(tmp, 32); + * + * However, unlike SSE, Clang lacks a 64-bit multiply routine + * for NEON, and it scalarizes two 64-bit multiplies instead. + * + * vmull_u32 has the same timing as vmul_u32, and it avoids + * this bug completely. + * See https://bugs.llvm.org/show_bug.cgi?id=39967 + */ + uint64x2_t prod_hi = vmull_u32 (data_key_hi, prime); + /* xacc[i] = prod_hi << 32; */ + xacc[i] = vshlq_n_u64(prod_hi, 32); + /* xacc[i] += (prod_hi & 0xFFFFFFFF) * XXH_PRIME32_1; */ + xacc[i] = vmlal_u32(xacc[i], data_key_lo, prime); + } + } + /* Scalar for the remainder. This may be a zero iteration loop. */ + for (i = XXH3_NEON_LANES; i < XXH_ACC_NB; i++) { + XXH3_scalarScrambleRound(acc, secret, i); + } + } +} + +#endif + +#if (XXH_VECTOR == XXH_VSX) + +XXH_FORCE_INLINE void +XXH3_accumulate_512_vsx( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + /* presumed aligned */ + unsigned int* const xacc = (unsigned int*) acc; + xxh_u64x2 const* const xinput = (xxh_u64x2 const*) input; /* no alignment restriction */ + xxh_u64x2 const* const xsecret = (xxh_u64x2 const*) secret; /* no alignment restriction */ + xxh_u64x2 const v32 = { 32, 32 }; + size_t i; + for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) { + /* data_vec = xinput[i]; */ + xxh_u64x2 const data_vec = XXH_vec_loadu(xinput + i); + /* key_vec = xsecret[i]; */ + xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + i); + xxh_u64x2 const data_key = data_vec ^ key_vec; + /* shuffled = (data_key << 32) | (data_key >> 32); */ + xxh_u32x4 const shuffled = (xxh_u32x4)vec_rl(data_key, v32); + /* product = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)shuffled & 0xFFFFFFFF); */ + xxh_u64x2 const product = XXH_vec_mulo((xxh_u32x4)data_key, shuffled); + /* acc_vec = xacc[i]; */ + xxh_u64x2 acc_vec = (xxh_u64x2)vec_xl(0, xacc + 4 * i); + acc_vec += product; + + /* swap high and low halves */ +#ifdef __s390x__ + acc_vec += vec_permi(data_vec, data_vec, 2); +#else + acc_vec += vec_xxpermdi(data_vec, data_vec, 2); +#endif + /* xacc[i] = acc_vec; */ + vec_xst((xxh_u32x4)acc_vec, 0, xacc + 4 * i); + } +} + +XXH_FORCE_INLINE void +XXH3_scrambleAcc_vsx(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + + { xxh_u64x2* const xacc = (xxh_u64x2*) acc; + const xxh_u64x2* const xsecret = (const xxh_u64x2*) secret; + /* constants */ + xxh_u64x2 const v32 = { 32, 32 }; + xxh_u64x2 const v47 = { 47, 47 }; + xxh_u32x4 const prime = { XXH_PRIME32_1, XXH_PRIME32_1, XXH_PRIME32_1, XXH_PRIME32_1 }; + size_t i; + for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) { + /* xacc[i] ^= (xacc[i] >> 47); */ + xxh_u64x2 const acc_vec = xacc[i]; + xxh_u64x2 const data_vec = acc_vec ^ (acc_vec >> v47); + + /* xacc[i] ^= xsecret[i]; */ + xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + i); + xxh_u64x2 const data_key = data_vec ^ key_vec; + + /* xacc[i] *= XXH_PRIME32_1 */ + /* prod_lo = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)prime & 0xFFFFFFFF); */ + xxh_u64x2 const prod_even = XXH_vec_mule((xxh_u32x4)data_key, prime); + /* prod_hi = ((xxh_u64x2)data_key >> 32) * ((xxh_u64x2)prime >> 32); */ + xxh_u64x2 const prod_odd = XXH_vec_mulo((xxh_u32x4)data_key, prime); + xacc[i] = prod_odd + (prod_even << v32); + } } +} + +#endif + +/* scalar variants - universal */ + +/*! + * @internal + * @brief Scalar round for @ref XXH3_accumulate_512_scalar(). + * + * This is extracted to its own function because the NEON path uses a combination + * of NEON and scalar. + */ +XXH_FORCE_INLINE void +XXH3_scalarRound(void* XXH_RESTRICT acc, + void const* XXH_RESTRICT input, + void const* XXH_RESTRICT secret, + size_t lane) +{ + xxh_u64* xacc = (xxh_u64*) acc; + xxh_u8 const* xinput = (xxh_u8 const*) input; + xxh_u8 const* xsecret = (xxh_u8 const*) secret; + XXH_ASSERT(lane < XXH_ACC_NB); + XXH_ASSERT(((size_t)acc & (XXH_ACC_ALIGN-1)) == 0); + { + xxh_u64 const data_val = XXH_readLE64(xinput + lane * 8); + xxh_u64 const data_key = data_val ^ XXH_readLE64(xsecret + lane * 8); + xacc[lane ^ 1] += data_val; /* swap adjacent lanes */ + xacc[lane] += XXH_mult32to64(data_key & 0xFFFFFFFF, data_key >> 32); + } +} + +/*! + * @internal + * @brief Processes a 64 byte block of data using the scalar path. + */ +XXH_FORCE_INLINE void +XXH3_accumulate_512_scalar(void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + size_t i; + for (i=0; i < XXH_ACC_NB; i++) { + XXH3_scalarRound(acc, input, secret, i); + } +} + +/*! + * @internal + * @brief Scalar scramble step for @ref XXH3_scrambleAcc_scalar(). + * + * This is extracted to its own function because the NEON path uses a combination + * of NEON and scalar. + */ +XXH_FORCE_INLINE void +XXH3_scalarScrambleRound(void* XXH_RESTRICT acc, + void const* XXH_RESTRICT secret, + size_t lane) +{ + xxh_u64* const xacc = (xxh_u64*) acc; /* presumed aligned */ + const xxh_u8* const xsecret = (const xxh_u8*) secret; /* no alignment restriction */ + XXH_ASSERT((((size_t)acc) & (XXH_ACC_ALIGN-1)) == 0); + XXH_ASSERT(lane < XXH_ACC_NB); + { + xxh_u64 const key64 = XXH_readLE64(xsecret + lane * 8); + xxh_u64 acc64 = xacc[lane]; + acc64 = XXH_xorshift64(acc64, 47); + acc64 ^= key64; + acc64 *= XXH_PRIME32_1; + xacc[lane] = acc64; + } +} + +/*! + * @internal + * @brief Scrambles the accumulators after a large chunk has been read + */ +XXH_FORCE_INLINE void +XXH3_scrambleAcc_scalar(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + size_t i; + for (i=0; i < XXH_ACC_NB; i++) { + XXH3_scalarScrambleRound(acc, secret, i); + } +} + +XXH_FORCE_INLINE void +XXH3_initCustomSecret_scalar(void* XXH_RESTRICT customSecret, xxh_u64 seed64) +{ + /* + * We need a separate pointer for the hack below, + * which requires a non-const pointer. + * Any decent compiler will optimize this out otherwise. + */ + const xxh_u8* kSecretPtr = XXH3_kSecret; + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0); + +#if defined(__clang__) && defined(__aarch64__) + /* + * UGLY HACK: + * Clang generates a bunch of MOV/MOVK pairs for aarch64, and they are + * placed sequentially, in order, at the top of the unrolled loop. + * + * While MOVK is great for generating constants (2 cycles for a 64-bit + * constant compared to 4 cycles for LDR), it fights for bandwidth with + * the arithmetic instructions. + * + * I L S + * MOVK + * MOVK + * MOVK + * MOVK + * ADD + * SUB STR + * STR + * By forcing loads from memory (as the asm line causes Clang to assume + * that XXH3_kSecretPtr has been changed), the pipelines are used more + * efficiently: + * I L S + * LDR + * ADD LDR + * SUB STR + * STR + * + * See XXH3_NEON_LANES for details on the pipsline. + * + * XXH3_64bits_withSeed, len == 256, Snapdragon 835 + * without hack: 2654.4 MB/s + * with hack: 3202.9 MB/s + */ + XXH_COMPILER_GUARD(kSecretPtr); +#endif + /* + * Note: in debug mode, this overrides the asm optimization + * and Clang will emit MOVK chains again. + */ + XXH_ASSERT(kSecretPtr == XXH3_kSecret); + + { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / 16; + int i; + for (i=0; i < nbRounds; i++) { + /* + * The asm hack causes Clang to assume that kSecretPtr aliases with + * customSecret, and on aarch64, this prevented LDP from merging two + * loads together for free. Putting the loads together before the stores + * properly generates LDP. + */ + xxh_u64 lo = XXH_readLE64(kSecretPtr + 16*i) + seed64; + xxh_u64 hi = XXH_readLE64(kSecretPtr + 16*i + 8) - seed64; + XXH_writeLE64((xxh_u8*)customSecret + 16*i, lo); + XXH_writeLE64((xxh_u8*)customSecret + 16*i + 8, hi); + } } +} + + +typedef void (*XXH3_f_accumulate_512)(void* XXH_RESTRICT, const void*, const void*); +typedef void (*XXH3_f_scrambleAcc)(void* XXH_RESTRICT, const void*); +typedef void (*XXH3_f_initCustomSecret)(void* XXH_RESTRICT, xxh_u64); + + +#if (XXH_VECTOR == XXH_AVX512) + +#define XXH3_accumulate_512 XXH3_accumulate_512_avx512 +#define XXH3_scrambleAcc XXH3_scrambleAcc_avx512 +#define XXH3_initCustomSecret XXH3_initCustomSecret_avx512 + +#elif (XXH_VECTOR == XXH_AVX2) + +#define XXH3_accumulate_512 XXH3_accumulate_512_avx2 +#define XXH3_scrambleAcc XXH3_scrambleAcc_avx2 +#define XXH3_initCustomSecret XXH3_initCustomSecret_avx2 + +#elif (XXH_VECTOR == XXH_SSE2) + +#define XXH3_accumulate_512 XXH3_accumulate_512_sse2 +#define XXH3_scrambleAcc XXH3_scrambleAcc_sse2 +#define XXH3_initCustomSecret XXH3_initCustomSecret_sse2 + +#elif (XXH_VECTOR == XXH_NEON) + +#define XXH3_accumulate_512 XXH3_accumulate_512_neon +#define XXH3_scrambleAcc XXH3_scrambleAcc_neon +#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar + +#elif (XXH_VECTOR == XXH_VSX) + +#define XXH3_accumulate_512 XXH3_accumulate_512_vsx +#define XXH3_scrambleAcc XXH3_scrambleAcc_vsx +#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar + +#else /* scalar */ + +#define XXH3_accumulate_512 XXH3_accumulate_512_scalar +#define XXH3_scrambleAcc XXH3_scrambleAcc_scalar +#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar + +#endif + + + +#ifndef XXH_PREFETCH_DIST +# ifdef __clang__ +# define XXH_PREFETCH_DIST 320 +# else +# if (XXH_VECTOR == XXH_AVX512) +# define XXH_PREFETCH_DIST 512 +# else +# define XXH_PREFETCH_DIST 384 +# endif +# endif /* __clang__ */ +#endif /* XXH_PREFETCH_DIST */ + +/* + * XXH3_accumulate() + * Loops over XXH3_accumulate_512(). + * Assumption: nbStripes will not overflow the secret size + */ +XXH_FORCE_INLINE void +XXH3_accumulate( xxh_u64* XXH_RESTRICT acc, + const xxh_u8* XXH_RESTRICT input, + const xxh_u8* XXH_RESTRICT secret, + size_t nbStripes, + XXH3_f_accumulate_512 f_acc512) +{ + size_t n; + for (n = 0; n < nbStripes; n++ ) { + const xxh_u8* const in = input + n*XXH_STRIPE_LEN; + XXH_PREFETCH(in + XXH_PREFETCH_DIST); + f_acc512(acc, + in, + secret + n*XXH_SECRET_CONSUME_RATE); + } +} + +XXH_FORCE_INLINE void +XXH3_hashLong_internal_loop(xxh_u64* XXH_RESTRICT acc, + const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + size_t const nbStripesPerBlock = (secretSize - XXH_STRIPE_LEN) / XXH_SECRET_CONSUME_RATE; + size_t const block_len = XXH_STRIPE_LEN * nbStripesPerBlock; + size_t const nb_blocks = (len - 1) / block_len; + + size_t n; + + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); + + for (n = 0; n < nb_blocks; n++) { + XXH3_accumulate(acc, input + n*block_len, secret, nbStripesPerBlock, f_acc512); + f_scramble(acc, secret + secretSize - XXH_STRIPE_LEN); + } + + /* last partial block */ + XXH_ASSERT(len > XXH_STRIPE_LEN); + { size_t const nbStripes = ((len - 1) - (block_len * nb_blocks)) / XXH_STRIPE_LEN; + XXH_ASSERT(nbStripes <= (secretSize / XXH_SECRET_CONSUME_RATE)); + XXH3_accumulate(acc, input + nb_blocks*block_len, secret, nbStripes, f_acc512); + + /* last stripe */ + { const xxh_u8* const p = input + len - XXH_STRIPE_LEN; +#define XXH_SECRET_LASTACC_START 7 /* not aligned on 8, last secret is different from acc & scrambler */ + f_acc512(acc, p, secret + secretSize - XXH_STRIPE_LEN - XXH_SECRET_LASTACC_START); + } } +} + +XXH_FORCE_INLINE xxh_u64 +XXH3_mix2Accs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret) +{ + return XXH3_mul128_fold64( + acc[0] ^ XXH_readLE64(secret), + acc[1] ^ XXH_readLE64(secret+8) ); +} + +static XXH64_hash_t +XXH3_mergeAccs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret, xxh_u64 start) +{ + xxh_u64 result64 = start; + size_t i = 0; + + for (i = 0; i < 4; i++) { + result64 += XXH3_mix2Accs(acc+2*i, secret + 16*i); +#if defined(__clang__) /* Clang */ \ + && (defined(__arm__) || defined(__thumb__)) /* ARMv7 */ \ + && (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \ + && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable */ + /* + * UGLY HACK: + * Prevent autovectorization on Clang ARMv7-a. Exact same problem as + * the one in XXH3_len_129to240_64b. Speeds up shorter keys > 240b. + * XXH3_64bits, len == 256, Snapdragon 835: + * without hack: 2063.7 MB/s + * with hack: 2560.7 MB/s + */ + XXH_COMPILER_GUARD(result64); +#endif + } + + return XXH3_avalanche(result64); +} + +#define XXH3_INIT_ACC { XXH_PRIME32_3, XXH_PRIME64_1, XXH_PRIME64_2, XXH_PRIME64_3, \ + XXH_PRIME64_4, XXH_PRIME32_2, XXH_PRIME64_5, XXH_PRIME32_1 } + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_hashLong_64b_internal(const void* XXH_RESTRICT input, size_t len, + const void* XXH_RESTRICT secret, size_t secretSize, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC; + + XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, (const xxh_u8*)secret, secretSize, f_acc512, f_scramble); + + /* converge into final hash */ + XXH_STATIC_ASSERT(sizeof(acc) == 64); + /* do not align on 8, so that the secret is different from the accumulator */ +#define XXH_SECRET_MERGEACCS_START 11 + XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); + return XXH3_mergeAccs(acc, (const xxh_u8*)secret + XXH_SECRET_MERGEACCS_START, (xxh_u64)len * XXH_PRIME64_1); +} + +/* + * It's important for performance to transmit secret's size (when it's static) + * so that the compiler can properly optimize the vectorized loop. + * This makes a big performance difference for "medium" keys (<1 KB) when using AVX instruction set. + */ +XXH_FORCE_INLINE XXH64_hash_t +XXH3_hashLong_64b_withSecret(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen) +{ + (void)seed64; + return XXH3_hashLong_64b_internal(input, len, secret, secretLen, XXH3_accumulate_512, XXH3_scrambleAcc); +} + +/* + * It's preferable for performance that XXH3_hashLong is not inlined, + * as it results in a smaller function for small data, easier to the instruction cache. + * Note that inside this no_inline function, we do inline the internal loop, + * and provide a statically defined secret size to allow optimization of vector loop. + */ +XXH_NO_INLINE XXH64_hash_t +XXH3_hashLong_64b_default(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen) +{ + (void)seed64; (void)secret; (void)secretLen; + return XXH3_hashLong_64b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_accumulate_512, XXH3_scrambleAcc); +} + +/* + * XXH3_hashLong_64b_withSeed(): + * Generate a custom key based on alteration of default XXH3_kSecret with the seed, + * and then use this key for long mode hashing. + * + * This operation is decently fast but nonetheless costs a little bit of time. + * Try to avoid it whenever possible (typically when seed==0). + * + * It's important for performance that XXH3_hashLong is not inlined. Not sure + * why (uop cache maybe?), but the difference is large and easily measurable. + */ +XXH_FORCE_INLINE XXH64_hash_t +XXH3_hashLong_64b_withSeed_internal(const void* input, size_t len, + XXH64_hash_t seed, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble, + XXH3_f_initCustomSecret f_initSec) +{ + if (seed == 0) + return XXH3_hashLong_64b_internal(input, len, + XXH3_kSecret, sizeof(XXH3_kSecret), + f_acc512, f_scramble); + { XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE]; + f_initSec(secret, seed); + return XXH3_hashLong_64b_internal(input, len, secret, sizeof(secret), + f_acc512, f_scramble); + } +} + +/* + * It's important for performance that XXH3_hashLong is not inlined. + */ +XXH_NO_INLINE XXH64_hash_t +XXH3_hashLong_64b_withSeed(const void* input, size_t len, + XXH64_hash_t seed, const xxh_u8* secret, size_t secretLen) +{ + (void)secret; (void)secretLen; + return XXH3_hashLong_64b_withSeed_internal(input, len, seed, + XXH3_accumulate_512, XXH3_scrambleAcc, XXH3_initCustomSecret); +} + + +typedef XXH64_hash_t (*XXH3_hashLong64_f)(const void* XXH_RESTRICT, size_t, + XXH64_hash_t, const xxh_u8* XXH_RESTRICT, size_t); + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_64bits_internal(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen, + XXH3_hashLong64_f f_hashLong) +{ + XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN); + /* + * If an action is to be taken if `secretLen` condition is not respected, + * it should be done here. + * For now, it's a contract pre-condition. + * Adding a check and a branch here would cost performance at every hash. + * Also, note that function signature doesn't offer room to return an error. + */ + if (len <= 16) + return XXH3_len_0to16_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, seed64); + if (len <= 128) + return XXH3_len_17to128_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); + if (len <= XXH3_MIDSIZE_MAX) + return XXH3_len_129to240_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); + return f_hashLong(input, len, seed64, (const xxh_u8*)secret, secretLen); +} + + +/* === Public entry point === */ + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits(const void* input, size_t len) +{ + return XXH3_64bits_internal(input, len, 0, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_default); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH64_hash_t +XXH3_64bits_withSecret(const void* input, size_t len, const void* secret, size_t secretSize) +{ + return XXH3_64bits_internal(input, len, 0, secret, secretSize, XXH3_hashLong_64b_withSecret); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH64_hash_t +XXH3_64bits_withSeed(const void* input, size_t len, XXH64_hash_t seed) +{ + return XXH3_64bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_withSeed); +} + +XXH_PUBLIC_API XXH64_hash_t +XXH3_64bits_withSecretandSeed(const void* input, size_t len, const void* secret, size_t secretSize, XXH64_hash_t seed) +{ + if (len <= XXH3_MIDSIZE_MAX) + return XXH3_64bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), NULL); + return XXH3_hashLong_64b_withSecret(input, len, seed, (const xxh_u8*)secret, secretSize); +} + + +/* === XXH3 streaming === */ + +/* + * Malloc's a pointer that is always aligned to align. + * + * This must be freed with `XXH_alignedFree()`. + * + * malloc typically guarantees 16 byte alignment on 64-bit systems and 8 byte + * alignment on 32-bit. This isn't enough for the 32 byte aligned loads in AVX2 + * or on 32-bit, the 16 byte aligned loads in SSE2 and NEON. + * + * This underalignment previously caused a rather obvious crash which went + * completely unnoticed due to XXH3_createState() not actually being tested. + * Credit to RedSpah for noticing this bug. + * + * The alignment is done manually: Functions like posix_memalign or _mm_malloc + * are avoided: To maintain portability, we would have to write a fallback + * like this anyways, and besides, testing for the existence of library + * functions without relying on external build tools is impossible. + * + * The method is simple: Overallocate, manually align, and store the offset + * to the original behind the returned pointer. + * + * Align must be a power of 2 and 8 <= align <= 128. + */ +static void* XXH_alignedMalloc(size_t s, size_t align) +{ + XXH_ASSERT(align <= 128 && align >= 8); /* range check */ + XXH_ASSERT((align & (align-1)) == 0); /* power of 2 */ + XXH_ASSERT(s != 0 && s < (s + align)); /* empty/overflow */ + { /* Overallocate to make room for manual realignment and an offset byte */ + xxh_u8* base = (xxh_u8*)XXH_malloc(s + align); + if (base != NULL) { + /* + * Get the offset needed to align this pointer. + * + * Even if the returned pointer is aligned, there will always be + * at least one byte to store the offset to the original pointer. + */ + size_t offset = align - ((size_t)base & (align - 1)); /* base % align */ + /* Add the offset for the now-aligned pointer */ + xxh_u8* ptr = base + offset; + + XXH_ASSERT((size_t)ptr % align == 0); + + /* Store the offset immediately before the returned pointer. */ + ptr[-1] = (xxh_u8)offset; + return ptr; + } + return NULL; + } +} +/* + * Frees an aligned pointer allocated by XXH_alignedMalloc(). Don't pass + * normal malloc'd pointers, XXH_alignedMalloc has a specific data layout. + */ +static void XXH_alignedFree(void* p) +{ + if (p != NULL) { + xxh_u8* ptr = (xxh_u8*)p; + /* Get the offset byte we added in XXH_malloc. */ + xxh_u8 offset = ptr[-1]; + /* Free the original malloc'd pointer */ + xxh_u8* base = ptr - offset; + XXH_free(base); + } +} +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH3_state_t* XXH3_createState(void) +{ + XXH3_state_t* const state = (XXH3_state_t*)XXH_alignedMalloc(sizeof(XXH3_state_t), 64); + if (state==NULL) return NULL; + XXH3_INITSTATE(state); + return state; +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr) +{ + XXH_alignedFree(statePtr); + return XXH_OK; +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API void +XXH3_copyState(XXH3_state_t* dst_state, const XXH3_state_t* src_state) +{ + XXH_memcpy(dst_state, src_state, sizeof(*dst_state)); +} + +static void +XXH3_reset_internal(XXH3_state_t* statePtr, + XXH64_hash_t seed, + const void* secret, size_t secretSize) +{ + size_t const initStart = offsetof(XXH3_state_t, bufferedSize); + size_t const initLength = offsetof(XXH3_state_t, nbStripesPerBlock) - initStart; + XXH_ASSERT(offsetof(XXH3_state_t, nbStripesPerBlock) > initStart); + XXH_ASSERT(statePtr != NULL); + /* set members from bufferedSize to nbStripesPerBlock (excluded) to 0 */ + memset((char*)statePtr + initStart, 0, initLength); + statePtr->acc[0] = XXH_PRIME32_3; + statePtr->acc[1] = XXH_PRIME64_1; + statePtr->acc[2] = XXH_PRIME64_2; + statePtr->acc[3] = XXH_PRIME64_3; + statePtr->acc[4] = XXH_PRIME64_4; + statePtr->acc[5] = XXH_PRIME32_2; + statePtr->acc[6] = XXH_PRIME64_5; + statePtr->acc[7] = XXH_PRIME32_1; + statePtr->seed = seed; + statePtr->useSeed = (seed != 0); + statePtr->extSecret = (const unsigned char*)secret; + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); + statePtr->secretLimit = secretSize - XXH_STRIPE_LEN; + statePtr->nbStripesPerBlock = statePtr->secretLimit / XXH_SECRET_CONSUME_RATE; +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset(XXH3_state_t* statePtr) +{ + if (statePtr == NULL) return XXH_ERROR; + XXH3_reset_internal(statePtr, 0, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE); + return XXH_OK; +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize) +{ + if (statePtr == NULL) return XXH_ERROR; + XXH3_reset_internal(statePtr, 0, secret, secretSize); + if (secret == NULL) return XXH_ERROR; + if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; + return XXH_OK; +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed) +{ + if (statePtr == NULL) return XXH_ERROR; + if (seed==0) return XXH3_64bits_reset(statePtr); + if ((seed != statePtr->seed) || (statePtr->extSecret != NULL)) + XXH3_initCustomSecret(statePtr->customSecret, seed); + XXH3_reset_internal(statePtr, seed, NULL, XXH_SECRET_DEFAULT_SIZE); + return XXH_OK; +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset_withSecretandSeed(XXH3_state_t* statePtr, const void* secret, size_t secretSize, XXH64_hash_t seed64) +{ + if (statePtr == NULL) return XXH_ERROR; + if (secret == NULL) return XXH_ERROR; + if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; + XXH3_reset_internal(statePtr, seed64, secret, secretSize); + statePtr->useSeed = 1; /* always, even if seed64==0 */ + return XXH_OK; +} + +/* Note : when XXH3_consumeStripes() is invoked, + * there must be a guarantee that at least one more byte must be consumed from input + * so that the function can blindly consume all stripes using the "normal" secret segment */ +XXH_FORCE_INLINE void +XXH3_consumeStripes(xxh_u64* XXH_RESTRICT acc, + size_t* XXH_RESTRICT nbStripesSoFarPtr, size_t nbStripesPerBlock, + const xxh_u8* XXH_RESTRICT input, size_t nbStripes, + const xxh_u8* XXH_RESTRICT secret, size_t secretLimit, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + XXH_ASSERT(nbStripes <= nbStripesPerBlock); /* can handle max 1 scramble per invocation */ + XXH_ASSERT(*nbStripesSoFarPtr < nbStripesPerBlock); + if (nbStripesPerBlock - *nbStripesSoFarPtr <= nbStripes) { + /* need a scrambling operation */ + size_t const nbStripesToEndofBlock = nbStripesPerBlock - *nbStripesSoFarPtr; + size_t const nbStripesAfterBlock = nbStripes - nbStripesToEndofBlock; + XXH3_accumulate(acc, input, secret + nbStripesSoFarPtr[0] * XXH_SECRET_CONSUME_RATE, nbStripesToEndofBlock, f_acc512); + f_scramble(acc, secret + secretLimit); + XXH3_accumulate(acc, input + nbStripesToEndofBlock * XXH_STRIPE_LEN, secret, nbStripesAfterBlock, f_acc512); + *nbStripesSoFarPtr = nbStripesAfterBlock; + } else { + XXH3_accumulate(acc, input, secret + nbStripesSoFarPtr[0] * XXH_SECRET_CONSUME_RATE, nbStripes, f_acc512); + *nbStripesSoFarPtr += nbStripes; + } +} + +#ifndef XXH3_STREAM_USE_STACK +# ifndef __clang__ /* clang doesn't need additional stack space */ +# define XXH3_STREAM_USE_STACK 1 +# endif +#endif +/* + * Both XXH3_64bits_update and XXH3_128bits_update use this routine. + */ +XXH_FORCE_INLINE XXH_errorcode +XXH3_update(XXH3_state_t* XXH_RESTRICT const state, + const xxh_u8* XXH_RESTRICT input, size_t len, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + if (input==NULL) { + XXH_ASSERT(len == 0); + return XXH_OK; + } + + XXH_ASSERT(state != NULL); + { const xxh_u8* const bEnd = input + len; + const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; +#if defined(XXH3_STREAM_USE_STACK) && XXH3_STREAM_USE_STACK >= 1 + /* For some reason, gcc and MSVC seem to suffer greatly + * when operating accumulators directly into state. + * Operating into stack space seems to enable proper optimization. + * clang, on the other hand, doesn't seem to need this trick */ + XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[8]; memcpy(acc, state->acc, sizeof(acc)); +#else + xxh_u64* XXH_RESTRICT const acc = state->acc; +#endif + state->totalLen += len; + XXH_ASSERT(state->bufferedSize <= XXH3_INTERNALBUFFER_SIZE); + + /* small input : just fill in tmp buffer */ + if (state->bufferedSize + len <= XXH3_INTERNALBUFFER_SIZE) { + XXH_memcpy(state->buffer + state->bufferedSize, input, len); + state->bufferedSize += (XXH32_hash_t)len; + return XXH_OK; + } + + /* total input is now > XXH3_INTERNALBUFFER_SIZE */ + #define XXH3_INTERNALBUFFER_STRIPES (XXH3_INTERNALBUFFER_SIZE / XXH_STRIPE_LEN) + XXH_STATIC_ASSERT(XXH3_INTERNALBUFFER_SIZE % XXH_STRIPE_LEN == 0); /* clean multiple */ + + /* + * Internal buffer is partially filled (always, except at beginning) + * Complete it, then consume it. + */ + if (state->bufferedSize) { + size_t const loadSize = XXH3_INTERNALBUFFER_SIZE - state->bufferedSize; + XXH_memcpy(state->buffer + state->bufferedSize, input, loadSize); + input += loadSize; + XXH3_consumeStripes(acc, + &state->nbStripesSoFar, state->nbStripesPerBlock, + state->buffer, XXH3_INTERNALBUFFER_STRIPES, + secret, state->secretLimit, + f_acc512, f_scramble); + state->bufferedSize = 0; + } + XXH_ASSERT(input < bEnd); + + /* large input to consume : ingest per full block */ + if ((size_t)(bEnd - input) > state->nbStripesPerBlock * XXH_STRIPE_LEN) { + size_t nbStripes = (size_t)(bEnd - 1 - input) / XXH_STRIPE_LEN; + XXH_ASSERT(state->nbStripesPerBlock >= state->nbStripesSoFar); + /* join to current block's end */ + { size_t const nbStripesToEnd = state->nbStripesPerBlock - state->nbStripesSoFar; + XXH_ASSERT(nbStripesToEnd <= nbStripes); + XXH3_accumulate(acc, input, secret + state->nbStripesSoFar * XXH_SECRET_CONSUME_RATE, nbStripesToEnd, f_acc512); + f_scramble(acc, secret + state->secretLimit); + state->nbStripesSoFar = 0; + input += nbStripesToEnd * XXH_STRIPE_LEN; + nbStripes -= nbStripesToEnd; + } + /* consume per entire blocks */ + while(nbStripes >= state->nbStripesPerBlock) { + XXH3_accumulate(acc, input, secret, state->nbStripesPerBlock, f_acc512); + f_scramble(acc, secret + state->secretLimit); + input += state->nbStripesPerBlock * XXH_STRIPE_LEN; + nbStripes -= state->nbStripesPerBlock; + } + /* consume last partial block */ + XXH3_accumulate(acc, input, secret, nbStripes, f_acc512); + input += nbStripes * XXH_STRIPE_LEN; + XXH_ASSERT(input < bEnd); /* at least some bytes left */ + state->nbStripesSoFar = nbStripes; + /* buffer predecessor of last partial stripe */ + XXH_memcpy(state->buffer + sizeof(state->buffer) - XXH_STRIPE_LEN, input - XXH_STRIPE_LEN, XXH_STRIPE_LEN); + XXH_ASSERT(bEnd - input <= XXH_STRIPE_LEN); + } else { + /* content to consume <= block size */ + /* Consume input by a multiple of internal buffer size */ + if (bEnd - input > XXH3_INTERNALBUFFER_SIZE) { + const xxh_u8* const limit = bEnd - XXH3_INTERNALBUFFER_SIZE; + do { + XXH3_consumeStripes(acc, + &state->nbStripesSoFar, state->nbStripesPerBlock, + input, XXH3_INTERNALBUFFER_STRIPES, + secret, state->secretLimit, + f_acc512, f_scramble); + input += XXH3_INTERNALBUFFER_SIZE; + } while (inputbuffer + sizeof(state->buffer) - XXH_STRIPE_LEN, input - XXH_STRIPE_LEN, XXH_STRIPE_LEN); + } + } + + /* Some remaining input (always) : buffer it */ + XXH_ASSERT(input < bEnd); + XXH_ASSERT(bEnd - input <= XXH3_INTERNALBUFFER_SIZE); + XXH_ASSERT(state->bufferedSize == 0); + XXH_memcpy(state->buffer, input, (size_t)(bEnd-input)); + state->bufferedSize = (XXH32_hash_t)(bEnd-input); +#if defined(XXH3_STREAM_USE_STACK) && XXH3_STREAM_USE_STACK >= 1 + /* save stack accumulators into state */ + memcpy(state->acc, acc, sizeof(acc)); +#endif + } + + return XXH_OK; +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_update(XXH3_state_t* state, const void* input, size_t len) +{ + return XXH3_update(state, (const xxh_u8*)input, len, + XXH3_accumulate_512, XXH3_scrambleAcc); +} + + +XXH_FORCE_INLINE void +XXH3_digest_long (XXH64_hash_t* acc, + const XXH3_state_t* state, + const unsigned char* secret) +{ + /* + * Digest on a local copy. This way, the state remains unaltered, and it can + * continue ingesting more input afterwards. + */ + XXH_memcpy(acc, state->acc, sizeof(state->acc)); + if (state->bufferedSize >= XXH_STRIPE_LEN) { + size_t const nbStripes = (state->bufferedSize - 1) / XXH_STRIPE_LEN; + size_t nbStripesSoFar = state->nbStripesSoFar; + XXH3_consumeStripes(acc, + &nbStripesSoFar, state->nbStripesPerBlock, + state->buffer, nbStripes, + secret, state->secretLimit, + XXH3_accumulate_512, XXH3_scrambleAcc); + /* last stripe */ + XXH3_accumulate_512(acc, + state->buffer + state->bufferedSize - XXH_STRIPE_LEN, + secret + state->secretLimit - XXH_SECRET_LASTACC_START); + } else { /* bufferedSize < XXH_STRIPE_LEN */ + xxh_u8 lastStripe[XXH_STRIPE_LEN]; + size_t const catchupSize = XXH_STRIPE_LEN - state->bufferedSize; + XXH_ASSERT(state->bufferedSize > 0); /* there is always some input buffered */ + XXH_memcpy(lastStripe, state->buffer + sizeof(state->buffer) - catchupSize, catchupSize); + XXH_memcpy(lastStripe + catchupSize, state->buffer, state->bufferedSize); + XXH3_accumulate_512(acc, + lastStripe, + secret + state->secretLimit - XXH_SECRET_LASTACC_START); + } +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest (const XXH3_state_t* state) +{ + const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; + if (state->totalLen > XXH3_MIDSIZE_MAX) { + XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB]; + XXH3_digest_long(acc, state, secret); + return XXH3_mergeAccs(acc, + secret + XXH_SECRET_MERGEACCS_START, + (xxh_u64)state->totalLen * XXH_PRIME64_1); + } + /* totalLen <= XXH3_MIDSIZE_MAX: digesting a short input */ + if (state->useSeed) + return XXH3_64bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed); + return XXH3_64bits_withSecret(state->buffer, (size_t)(state->totalLen), + secret, state->secretLimit + XXH_STRIPE_LEN); +} + + + +/* ========================================== + * XXH3 128 bits (a.k.a XXH128) + * ========================================== + * XXH3's 128-bit variant has better mixing and strength than the 64-bit variant, + * even without counting the significantly larger output size. + * + * For example, extra steps are taken to avoid the seed-dependent collisions + * in 17-240 byte inputs (See XXH3_mix16B and XXH128_mix32B). + * + * This strength naturally comes at the cost of some speed, especially on short + * lengths. Note that longer hashes are about as fast as the 64-bit version + * due to it using only a slight modification of the 64-bit loop. + * + * XXH128 is also more oriented towards 64-bit machines. It is still extremely + * fast for a _128-bit_ hash on 32-bit (it usually clears XXH64). + */ + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_1to3_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + /* A doubled version of 1to3_64b with different constants. */ + XXH_ASSERT(input != NULL); + XXH_ASSERT(1 <= len && len <= 3); + XXH_ASSERT(secret != NULL); + /* + * len = 1: combinedl = { input[0], 0x01, input[0], input[0] } + * len = 2: combinedl = { input[1], 0x02, input[0], input[1] } + * len = 3: combinedl = { input[2], 0x03, input[0], input[1] } + */ + { xxh_u8 const c1 = input[0]; + xxh_u8 const c2 = input[len >> 1]; + xxh_u8 const c3 = input[len - 1]; + xxh_u32 const combinedl = ((xxh_u32)c1 <<16) | ((xxh_u32)c2 << 24) + | ((xxh_u32)c3 << 0) | ((xxh_u32)len << 8); + xxh_u32 const combinedh = XXH_rotl32(XXH_swap32(combinedl), 13); + xxh_u64 const bitflipl = (XXH_readLE32(secret) ^ XXH_readLE32(secret+4)) + seed; + xxh_u64 const bitfliph = (XXH_readLE32(secret+8) ^ XXH_readLE32(secret+12)) - seed; + xxh_u64 const keyed_lo = (xxh_u64)combinedl ^ bitflipl; + xxh_u64 const keyed_hi = (xxh_u64)combinedh ^ bitfliph; + XXH128_hash_t h128; + h128.low64 = XXH64_avalanche(keyed_lo); + h128.high64 = XXH64_avalanche(keyed_hi); + return h128; + } +} + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_4to8_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(4 <= len && len <= 8); + seed ^= (xxh_u64)XXH_swap32((xxh_u32)seed) << 32; + { xxh_u32 const input_lo = XXH_readLE32(input); + xxh_u32 const input_hi = XXH_readLE32(input + len - 4); + xxh_u64 const input_64 = input_lo + ((xxh_u64)input_hi << 32); + xxh_u64 const bitflip = (XXH_readLE64(secret+16) ^ XXH_readLE64(secret+24)) + seed; + xxh_u64 const keyed = input_64 ^ bitflip; + + /* Shift len to the left to ensure it is even, this avoids even multiplies. */ + XXH128_hash_t m128 = XXH_mult64to128(keyed, XXH_PRIME64_1 + (len << 2)); + + m128.high64 += (m128.low64 << 1); + m128.low64 ^= (m128.high64 >> 3); + + m128.low64 = XXH_xorshift64(m128.low64, 35); + m128.low64 *= 0x9FB21C651E98DF25ULL; + m128.low64 = XXH_xorshift64(m128.low64, 28); + m128.high64 = XXH3_avalanche(m128.high64); + return m128; + } +} + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_9to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(9 <= len && len <= 16); + { xxh_u64 const bitflipl = (XXH_readLE64(secret+32) ^ XXH_readLE64(secret+40)) - seed; + xxh_u64 const bitfliph = (XXH_readLE64(secret+48) ^ XXH_readLE64(secret+56)) + seed; + xxh_u64 const input_lo = XXH_readLE64(input); + xxh_u64 input_hi = XXH_readLE64(input + len - 8); + XXH128_hash_t m128 = XXH_mult64to128(input_lo ^ input_hi ^ bitflipl, XXH_PRIME64_1); + /* + * Put len in the middle of m128 to ensure that the length gets mixed to + * both the low and high bits in the 128x64 multiply below. + */ + m128.low64 += (xxh_u64)(len - 1) << 54; + input_hi ^= bitfliph; + /* + * Add the high 32 bits of input_hi to the high 32 bits of m128, then + * add the long product of the low 32 bits of input_hi and XXH_PRIME32_2 to + * the high 64 bits of m128. + * + * The best approach to this operation is different on 32-bit and 64-bit. + */ + if (sizeof(void *) < sizeof(xxh_u64)) { /* 32-bit */ + /* + * 32-bit optimized version, which is more readable. + * + * On 32-bit, it removes an ADC and delays a dependency between the two + * halves of m128.high64, but it generates an extra mask on 64-bit. + */ + m128.high64 += (input_hi & 0xFFFFFFFF00000000ULL) + XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2); + } else { + /* + * 64-bit optimized (albeit more confusing) version. + * + * Uses some properties of addition and multiplication to remove the mask: + * + * Let: + * a = input_hi.lo = (input_hi & 0x00000000FFFFFFFF) + * b = input_hi.hi = (input_hi & 0xFFFFFFFF00000000) + * c = XXH_PRIME32_2 + * + * a + (b * c) + * Inverse Property: x + y - x == y + * a + (b * (1 + c - 1)) + * Distributive Property: x * (y + z) == (x * y) + (x * z) + * a + (b * 1) + (b * (c - 1)) + * Identity Property: x * 1 == x + * a + b + (b * (c - 1)) + * + * Substitute a, b, and c: + * input_hi.hi + input_hi.lo + ((xxh_u64)input_hi.lo * (XXH_PRIME32_2 - 1)) + * + * Since input_hi.hi + input_hi.lo == input_hi, we get this: + * input_hi + ((xxh_u64)input_hi.lo * (XXH_PRIME32_2 - 1)) + */ + m128.high64 += input_hi + XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2 - 1); + } + /* m128 ^= XXH_swap64(m128 >> 64); */ + m128.low64 ^= XXH_swap64(m128.high64); + + { /* 128x64 multiply: h128 = m128 * XXH_PRIME64_2; */ + XXH128_hash_t h128 = XXH_mult64to128(m128.low64, XXH_PRIME64_2); + h128.high64 += m128.high64 * XXH_PRIME64_2; + + h128.low64 = XXH3_avalanche(h128.low64); + h128.high64 = XXH3_avalanche(h128.high64); + return h128; + } } +} + +/* + * Assumption: `secret` size is >= XXH3_SECRET_SIZE_MIN + */ +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_0to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(len <= 16); + { if (len > 8) return XXH3_len_9to16_128b(input, len, secret, seed); + if (len >= 4) return XXH3_len_4to8_128b(input, len, secret, seed); + if (len) return XXH3_len_1to3_128b(input, len, secret, seed); + { XXH128_hash_t h128; + xxh_u64 const bitflipl = XXH_readLE64(secret+64) ^ XXH_readLE64(secret+72); + xxh_u64 const bitfliph = XXH_readLE64(secret+80) ^ XXH_readLE64(secret+88); + h128.low64 = XXH64_avalanche(seed ^ bitflipl); + h128.high64 = XXH64_avalanche( seed ^ bitfliph); + return h128; + } } +} + +/* + * A bit slower than XXH3_mix16B, but handles multiply by zero better. + */ +XXH_FORCE_INLINE XXH128_hash_t +XXH128_mix32B(XXH128_hash_t acc, const xxh_u8* input_1, const xxh_u8* input_2, + const xxh_u8* secret, XXH64_hash_t seed) +{ + acc.low64 += XXH3_mix16B (input_1, secret+0, seed); + acc.low64 ^= XXH_readLE64(input_2) + XXH_readLE64(input_2 + 8); + acc.high64 += XXH3_mix16B (input_2, secret+16, seed); + acc.high64 ^= XXH_readLE64(input_1) + XXH_readLE64(input_1 + 8); + return acc; +} + + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_17to128_128b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(16 < len && len <= 128); + + { XXH128_hash_t acc; + acc.low64 = len * XXH_PRIME64_1; + acc.high64 = 0; + if (len > 32) { + if (len > 64) { + if (len > 96) { + acc = XXH128_mix32B(acc, input+48, input+len-64, secret+96, seed); + } + acc = XXH128_mix32B(acc, input+32, input+len-48, secret+64, seed); + } + acc = XXH128_mix32B(acc, input+16, input+len-32, secret+32, seed); + } + acc = XXH128_mix32B(acc, input, input+len-16, secret, seed); + { XXH128_hash_t h128; + h128.low64 = acc.low64 + acc.high64; + h128.high64 = (acc.low64 * XXH_PRIME64_1) + + (acc.high64 * XXH_PRIME64_4) + + ((len - seed) * XXH_PRIME64_2); + h128.low64 = XXH3_avalanche(h128.low64); + h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64); + return h128; + } + } +} + +XXH_NO_INLINE XXH128_hash_t +XXH3_len_129to240_128b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX); + + { XXH128_hash_t acc; + int const nbRounds = (int)len / 32; + int i; + acc.low64 = len * XXH_PRIME64_1; + acc.high64 = 0; + for (i=0; i<4; i++) { + acc = XXH128_mix32B(acc, + input + (32 * i), + input + (32 * i) + 16, + secret + (32 * i), + seed); + } + acc.low64 = XXH3_avalanche(acc.low64); + acc.high64 = XXH3_avalanche(acc.high64); + XXH_ASSERT(nbRounds >= 4); + for (i=4 ; i < nbRounds; i++) { + acc = XXH128_mix32B(acc, + input + (32 * i), + input + (32 * i) + 16, + secret + XXH3_MIDSIZE_STARTOFFSET + (32 * (i - 4)), + seed); + } + /* last bytes */ + acc = XXH128_mix32B(acc, + input + len - 16, + input + len - 32, + secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET - 16, + 0ULL - seed); + + { XXH128_hash_t h128; + h128.low64 = acc.low64 + acc.high64; + h128.high64 = (acc.low64 * XXH_PRIME64_1) + + (acc.high64 * XXH_PRIME64_4) + + ((len - seed) * XXH_PRIME64_2); + h128.low64 = XXH3_avalanche(h128.low64); + h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64); + return h128; + } + } +} + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_hashLong_128b_internal(const void* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC; + + XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, secret, secretSize, f_acc512, f_scramble); + + /* converge into final hash */ + XXH_STATIC_ASSERT(sizeof(acc) == 64); + XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); + { XXH128_hash_t h128; + h128.low64 = XXH3_mergeAccs(acc, + secret + XXH_SECRET_MERGEACCS_START, + (xxh_u64)len * XXH_PRIME64_1); + h128.high64 = XXH3_mergeAccs(acc, + secret + secretSize + - sizeof(acc) - XXH_SECRET_MERGEACCS_START, + ~((xxh_u64)len * XXH_PRIME64_2)); + return h128; + } +} + +/* + * It's important for performance that XXH3_hashLong is not inlined. + */ +XXH_NO_INLINE XXH128_hash_t +XXH3_hashLong_128b_default(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, + const void* XXH_RESTRICT secret, size_t secretLen) +{ + (void)seed64; (void)secret; (void)secretLen; + return XXH3_hashLong_128b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), + XXH3_accumulate_512, XXH3_scrambleAcc); +} + +/* + * It's important for performance to pass @secretLen (when it's static) + * to the compiler, so that it can properly optimize the vectorized loop. + */ +XXH_FORCE_INLINE XXH128_hash_t +XXH3_hashLong_128b_withSecret(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, + const void* XXH_RESTRICT secret, size_t secretLen) +{ + (void)seed64; + return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, secretLen, + XXH3_accumulate_512, XXH3_scrambleAcc); +} + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_hashLong_128b_withSeed_internal(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble, + XXH3_f_initCustomSecret f_initSec) +{ + if (seed64 == 0) + return XXH3_hashLong_128b_internal(input, len, + XXH3_kSecret, sizeof(XXH3_kSecret), + f_acc512, f_scramble); + { XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE]; + f_initSec(secret, seed64); + return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, sizeof(secret), + f_acc512, f_scramble); + } +} + +/* + * It's important for performance that XXH3_hashLong is not inlined. + */ +XXH_NO_INLINE XXH128_hash_t +XXH3_hashLong_128b_withSeed(const void* input, size_t len, + XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen) +{ + (void)secret; (void)secretLen; + return XXH3_hashLong_128b_withSeed_internal(input, len, seed64, + XXH3_accumulate_512, XXH3_scrambleAcc, XXH3_initCustomSecret); +} + +typedef XXH128_hash_t (*XXH3_hashLong128_f)(const void* XXH_RESTRICT, size_t, + XXH64_hash_t, const void* XXH_RESTRICT, size_t); + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_128bits_internal(const void* input, size_t len, + XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen, + XXH3_hashLong128_f f_hl128) +{ + XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN); + /* + * If an action is to be taken if `secret` conditions are not respected, + * it should be done here. + * For now, it's a contract pre-condition. + * Adding a check and a branch here would cost performance at every hash. + */ + if (len <= 16) + return XXH3_len_0to16_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, seed64); + if (len <= 128) + return XXH3_len_17to128_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); + if (len <= XXH3_MIDSIZE_MAX) + return XXH3_len_129to240_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); + return f_hl128(input, len, seed64, secret, secretLen); +} + + +/* === Public XXH128 API === */ + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits(const void* input, size_t len) +{ + return XXH3_128bits_internal(input, len, 0, + XXH3_kSecret, sizeof(XXH3_kSecret), + XXH3_hashLong_128b_default); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH128_hash_t +XXH3_128bits_withSecret(const void* input, size_t len, const void* secret, size_t secretSize) +{ + return XXH3_128bits_internal(input, len, 0, + (const xxh_u8*)secret, secretSize, + XXH3_hashLong_128b_withSecret); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH128_hash_t +XXH3_128bits_withSeed(const void* input, size_t len, XXH64_hash_t seed) +{ + return XXH3_128bits_internal(input, len, seed, + XXH3_kSecret, sizeof(XXH3_kSecret), + XXH3_hashLong_128b_withSeed); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH128_hash_t +XXH3_128bits_withSecretandSeed(const void* input, size_t len, const void* secret, size_t secretSize, XXH64_hash_t seed) +{ + if (len <= XXH3_MIDSIZE_MAX) + return XXH3_128bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), NULL); + return XXH3_hashLong_128b_withSecret(input, len, seed, secret, secretSize); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH128_hash_t +XXH128(const void* input, size_t len, XXH64_hash_t seed) +{ + return XXH3_128bits_withSeed(input, len, seed); +} + + +/* === XXH3 128-bit streaming === */ + +/* + * All initialization and update functions are identical to 64-bit streaming variant. + * The only difference is the finalization routine. + */ + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset(XXH3_state_t* statePtr) +{ + return XXH3_64bits_reset(statePtr); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize) +{ + return XXH3_64bits_reset_withSecret(statePtr, secret, secretSize); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed) +{ + return XXH3_64bits_reset_withSeed(statePtr, seed); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset_withSecretandSeed(XXH3_state_t* statePtr, const void* secret, size_t secretSize, XXH64_hash_t seed) +{ + return XXH3_64bits_reset_withSecretandSeed(statePtr, secret, secretSize, seed); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_update(XXH3_state_t* state, const void* input, size_t len) +{ + return XXH3_update(state, (const xxh_u8*)input, len, + XXH3_accumulate_512, XXH3_scrambleAcc); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest (const XXH3_state_t* state) +{ + const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; + if (state->totalLen > XXH3_MIDSIZE_MAX) { + XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB]; + XXH3_digest_long(acc, state, secret); + XXH_ASSERT(state->secretLimit + XXH_STRIPE_LEN >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); + { XXH128_hash_t h128; + h128.low64 = XXH3_mergeAccs(acc, + secret + XXH_SECRET_MERGEACCS_START, + (xxh_u64)state->totalLen * XXH_PRIME64_1); + h128.high64 = XXH3_mergeAccs(acc, + secret + state->secretLimit + XXH_STRIPE_LEN + - sizeof(acc) - XXH_SECRET_MERGEACCS_START, + ~((xxh_u64)state->totalLen * XXH_PRIME64_2)); + return h128; + } + } + /* len <= XXH3_MIDSIZE_MAX : short code */ + if (state->seed) + return XXH3_128bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed); + return XXH3_128bits_withSecret(state->buffer, (size_t)(state->totalLen), + secret, state->secretLimit + XXH_STRIPE_LEN); +} + +/* 128-bit utility functions */ + +#include /* memcmp, memcpy */ + +/* return : 1 is equal, 0 if different */ +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2) +{ + /* note : XXH128_hash_t is compact, it has no padding byte */ + return !(memcmp(&h1, &h2, sizeof(h1))); +} + +/* This prototype is compatible with stdlib's qsort(). + * return : >0 if *h128_1 > *h128_2 + * <0 if *h128_1 < *h128_2 + * =0 if *h128_1 == *h128_2 */ +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API int XXH128_cmp(const void* h128_1, const void* h128_2) +{ + XXH128_hash_t const h1 = *(const XXH128_hash_t*)h128_1; + XXH128_hash_t const h2 = *(const XXH128_hash_t*)h128_2; + int const hcmp = (h1.high64 > h2.high64) - (h2.high64 > h1.high64); + /* note : bets that, in most cases, hash values are different */ + if (hcmp) return hcmp; + return (h1.low64 > h2.low64) - (h2.low64 > h1.low64); +} + + +/*====== Canonical representation ======*/ +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API void +XXH128_canonicalFromHash(XXH128_canonical_t* dst, XXH128_hash_t hash) +{ + XXH_STATIC_ASSERT(sizeof(XXH128_canonical_t) == sizeof(XXH128_hash_t)); + if (XXH_CPU_LITTLE_ENDIAN) { + hash.high64 = XXH_swap64(hash.high64); + hash.low64 = XXH_swap64(hash.low64); + } + XXH_memcpy(dst, &hash.high64, sizeof(hash.high64)); + XXH_memcpy((char*)dst + sizeof(hash.high64), &hash.low64, sizeof(hash.low64)); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH128_hash_t +XXH128_hashFromCanonical(const XXH128_canonical_t* src) +{ + XXH128_hash_t h; + h.high64 = XXH_readBE64(src); + h.low64 = XXH_readBE64(src->digest + 8); + return h; +} + + + +/* ========================================== + * Secret generators + * ========================================== + */ +#define XXH_MIN(x, y) (((x) > (y)) ? (y) : (x)) + +XXH_FORCE_INLINE void XXH3_combine16(void* dst, XXH128_hash_t h128) +{ + XXH_writeLE64( dst, XXH_readLE64(dst) ^ h128.low64 ); + XXH_writeLE64( (char*)dst+8, XXH_readLE64((char*)dst+8) ^ h128.high64 ); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_generateSecret(void* secretBuffer, size_t secretSize, const void* customSeed, size_t customSeedSize) +{ +#if (XXH_DEBUGLEVEL >= 1) + XXH_ASSERT(secretBuffer != NULL); + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); +#else + /* production mode, assert() are disabled */ + if (secretBuffer == NULL) return XXH_ERROR; + if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; +#endif + + if (customSeedSize == 0) { + customSeed = XXH3_kSecret; + customSeedSize = XXH_SECRET_DEFAULT_SIZE; + } +#if (XXH_DEBUGLEVEL >= 1) + XXH_ASSERT(customSeed != NULL); +#else + if (customSeed == NULL) return XXH_ERROR; +#endif + + /* Fill secretBuffer with a copy of customSeed - repeat as needed */ + { size_t pos = 0; + while (pos < secretSize) { + size_t const toCopy = XXH_MIN((secretSize - pos), customSeedSize); + memcpy((char*)secretBuffer + pos, customSeed, toCopy); + pos += toCopy; + } } + + { size_t const nbSeg16 = secretSize / 16; + size_t n; + XXH128_canonical_t scrambler; + XXH128_canonicalFromHash(&scrambler, XXH128(customSeed, customSeedSize, 0)); + for (n=0; n +#include +#include + +#if defined(__GNUC__) && __GNUC__ >= 4 +# define ZSTD_memcpy(d,s,l) __builtin_memcpy((d),(s),(l)) +# define ZSTD_memmove(d,s,l) __builtin_memmove((d),(s),(l)) +# define ZSTD_memset(p,v,l) __builtin_memset((p),(v),(l)) +#else +# define ZSTD_memcpy(d,s,l) memcpy((d),(s),(l)) +# define ZSTD_memmove(d,s,l) memmove((d),(s),(l)) +# define ZSTD_memset(p,v,l) memset((p),(v),(l)) +#endif + +#endif /* ZSTD_DEPS_COMMON */ + +/* Need: + * ZSTD_malloc() + * ZSTD_free() + * ZSTD_calloc() + */ +#ifdef ZSTD_DEPS_NEED_MALLOC +#ifndef ZSTD_DEPS_MALLOC +#define ZSTD_DEPS_MALLOC + +#include + +#define ZSTD_malloc(s) malloc(s) +#define ZSTD_calloc(n,s) calloc((n), (s)) +#define ZSTD_free(p) free((p)) + +#endif /* ZSTD_DEPS_MALLOC */ +#endif /* ZSTD_DEPS_NEED_MALLOC */ + +/* + * Provides 64-bit math support. + * Need: + * U64 ZSTD_div64(U64 dividend, U32 divisor) + */ +#ifdef ZSTD_DEPS_NEED_MATH64 +#ifndef ZSTD_DEPS_MATH64 +#define ZSTD_DEPS_MATH64 + +#define ZSTD_div64(dividend, divisor) ((dividend) / (divisor)) + +#endif /* ZSTD_DEPS_MATH64 */ +#endif /* ZSTD_DEPS_NEED_MATH64 */ + +/* Need: + * assert() + */ +#ifdef ZSTD_DEPS_NEED_ASSERT +#ifndef ZSTD_DEPS_ASSERT +#define ZSTD_DEPS_ASSERT + +#include + +#endif /* ZSTD_DEPS_ASSERT */ +#endif /* ZSTD_DEPS_NEED_ASSERT */ + +/* Need: + * ZSTD_DEBUG_PRINT() + */ +#ifdef ZSTD_DEPS_NEED_IO +#ifndef ZSTD_DEPS_IO +#define ZSTD_DEPS_IO + +#include +#define ZSTD_DEBUG_PRINT(...) fprintf(stderr, __VA_ARGS__) + +#endif /* ZSTD_DEPS_IO */ +#endif /* ZSTD_DEPS_NEED_IO */ + +/* Only requested when is known to be present. + * Need: + * intptr_t + */ +#ifdef ZSTD_DEPS_NEED_STDINT +#ifndef ZSTD_DEPS_STDINT +#define ZSTD_DEPS_STDINT + +#include + +#endif /* ZSTD_DEPS_STDINT */ +#endif /* ZSTD_DEPS_NEED_STDINT */ diff --git a/lib/zstd/lib/common/zstd_internal.h b/lib/zstd/lib/common/zstd_internal.h new file mode 100644 index 0000000..1f942f2 --- /dev/null +++ b/lib/zstd/lib/common/zstd_internal.h @@ -0,0 +1,392 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef ZSTD_CCOMMON_H_MODULE +#define ZSTD_CCOMMON_H_MODULE + +/* this module contains definitions which must be identical + * across compression, decompression and dictBuilder. + * It also contains a few functions useful to at least 2 of them + * and which benefit from being inlined */ + +/*-************************************* +* Dependencies +***************************************/ +#include "compiler.h" +#include "cpu.h" +#include "mem.h" +#include "debug.h" /* assert, DEBUGLOG, RAWLOG, g_debuglevel */ +#include "error_private.h" +#define ZSTD_STATIC_LINKING_ONLY +#include "../zstd.h" +#define FSE_STATIC_LINKING_ONLY +#include "fse.h" +#include "huf.h" +#ifndef XXH_STATIC_LINKING_ONLY +# define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */ +#endif +#include "xxhash.h" /* XXH_reset, update, digest */ +#ifndef ZSTD_NO_TRACE +# include "zstd_trace.h" +#else +# define ZSTD_TRACE 0 +#endif + +#if defined (__cplusplus) +extern "C" { +#endif + +/* ---- static assert (debug) --- */ +#define ZSTD_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) +#define ZSTD_isError ERR_isError /* for inlining */ +#define FSE_isError ERR_isError +#define HUF_isError ERR_isError + + +/*-************************************* +* shared macros +***************************************/ +#undef MIN +#undef MAX +#define MIN(a,b) ((a)<(b) ? (a) : (b)) +#define MAX(a,b) ((a)>(b) ? (a) : (b)) +#define BOUNDED(min,val,max) (MAX(min,MIN(val,max))) + + +/*-************************************* +* Common constants +***************************************/ +#define ZSTD_OPT_NUM (1<<12) + +#define ZSTD_REP_NUM 3 /* number of repcodes */ +static UNUSED_ATTR const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 }; + +#define KB *(1 <<10) +#define MB *(1 <<20) +#define GB *(1U<<30) + +#define BIT7 128 +#define BIT6 64 +#define BIT5 32 +#define BIT4 16 +#define BIT1 2 +#define BIT0 1 + +#define ZSTD_WINDOWLOG_ABSOLUTEMIN 10 +static UNUSED_ATTR const size_t ZSTD_fcs_fieldSize[4] = { 0, 2, 4, 8 }; +static UNUSED_ATTR const size_t ZSTD_did_fieldSize[4] = { 0, 1, 2, 4 }; + +#define ZSTD_FRAMEIDSIZE 4 /* magic number size */ + +#define ZSTD_BLOCKHEADERSIZE 3 /* C standard doesn't allow `static const` variable to be init using another `static const` variable */ +static UNUSED_ATTR const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE; +typedef enum { bt_raw, bt_rle, bt_compressed, bt_reserved } blockType_e; + +#define ZSTD_FRAMECHECKSUMSIZE 4 + +#define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */ +#define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */) /* for a non-null block */ +#define MIN_LITERALS_FOR_4_STREAMS 6 + +typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingType_e; + +#define LONGNBSEQ 0x7F00 + +#define MINMATCH 3 + +#define Litbits 8 +#define LitHufLog 11 +#define MaxLit ((1<= WILDCOPY_VECLEN || diff <= -WILDCOPY_VECLEN); + /* Separate out the first COPY16() call because the copy length is + * almost certain to be short, so the branches have different + * probabilities. Since it is almost certain to be short, only do + * one COPY16() in the first call. Then, do two calls per loop since + * at that point it is more likely to have a high trip count. + */ + ZSTD_copy16(op, ip); + if (16 >= length) return; + op += 16; + ip += 16; + do { + COPY16(op, ip); + COPY16(op, ip); + } + while (op < oend); + } +} + +MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize) +{ + size_t const length = MIN(dstCapacity, srcSize); + if (length > 0) { + ZSTD_memcpy(dst, src, length); + } + return length; +} + +/* define "workspace is too large" as this number of times larger than needed */ +#define ZSTD_WORKSPACETOOLARGE_FACTOR 3 + +/* when workspace is continuously too large + * during at least this number of times, + * context's memory usage is considered wasteful, + * because it's sized to handle a worst case scenario which rarely happens. + * In which case, resize it down to free some memory */ +#define ZSTD_WORKSPACETOOLARGE_MAXDURATION 128 + +/* Controls whether the input/output buffer is buffered or stable. */ +typedef enum { + ZSTD_bm_buffered = 0, /* Buffer the input/output */ + ZSTD_bm_stable = 1 /* ZSTD_inBuffer/ZSTD_outBuffer is stable */ +} ZSTD_bufferMode_e; + + +/*-******************************************* +* Private declarations +*********************************************/ +typedef struct seqDef_s { + U32 offBase; /* offBase == Offset + ZSTD_REP_NUM, or repcode 1,2,3 */ + U16 litLength; + U16 mlBase; /* mlBase == matchLength - MINMATCH */ +} seqDef; + +/* Controls whether seqStore has a single "long" litLength or matchLength. See seqStore_t. */ +typedef enum { + ZSTD_llt_none = 0, /* no longLengthType */ + ZSTD_llt_literalLength = 1, /* represents a long literal */ + ZSTD_llt_matchLength = 2 /* represents a long match */ +} ZSTD_longLengthType_e; + +typedef struct { + seqDef* sequencesStart; + seqDef* sequences; /* ptr to end of sequences */ + BYTE* litStart; + BYTE* lit; /* ptr to end of literals */ + BYTE* llCode; + BYTE* mlCode; + BYTE* ofCode; + size_t maxNbSeq; + size_t maxNbLit; + + /* longLengthPos and longLengthType to allow us to represent either a single litLength or matchLength + * in the seqStore that has a value larger than U16 (if it exists). To do so, we increment + * the existing value of the litLength or matchLength by 0x10000. + */ + ZSTD_longLengthType_e longLengthType; + U32 longLengthPos; /* Index of the sequence to apply long length modification to */ +} seqStore_t; + +typedef struct { + U32 litLength; + U32 matchLength; +} ZSTD_sequenceLength; + +/** + * Returns the ZSTD_sequenceLength for the given sequences. It handles the decoding of long sequences + * indicated by longLengthPos and longLengthType, and adds MINMATCH back to matchLength. + */ +MEM_STATIC ZSTD_sequenceLength ZSTD_getSequenceLength(seqStore_t const* seqStore, seqDef const* seq) +{ + ZSTD_sequenceLength seqLen; + seqLen.litLength = seq->litLength; + seqLen.matchLength = seq->mlBase + MINMATCH; + if (seqStore->longLengthPos == (U32)(seq - seqStore->sequencesStart)) { + if (seqStore->longLengthType == ZSTD_llt_literalLength) { + seqLen.litLength += 0x10000; + } + if (seqStore->longLengthType == ZSTD_llt_matchLength) { + seqLen.matchLength += 0x10000; + } + } + return seqLen; +} + +/** + * Contains the compressed frame size and an upper-bound for the decompressed frame size. + * Note: before using `compressedSize`, check for errors using ZSTD_isError(). + * similarly, before using `decompressedBound`, check for errors using: + * `decompressedBound != ZSTD_CONTENTSIZE_ERROR` + */ +typedef struct { + size_t nbBlocks; + size_t compressedSize; + unsigned long long decompressedBound; +} ZSTD_frameSizeInfo; /* decompress & legacy */ + +const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx); /* compress & dictBuilder */ +int ZSTD_seqToCodes(const seqStore_t* seqStorePtr); /* compress, dictBuilder, decodeCorpus (shouldn't get its definition from here) */ + + +/* ZSTD_invalidateRepCodes() : + * ensures next compression will not use repcodes from previous block. + * Note : only works with regular variant; + * do not use with extDict variant ! */ +void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx); /* zstdmt, adaptive_compression (shouldn't get this definition from here) */ + + +typedef struct { + blockType_e blockType; + U32 lastBlock; + U32 origSize; +} blockProperties_t; /* declared here for decompress and fullbench */ + +/*! ZSTD_getcBlockSize() : + * Provides the size of compressed block from block header `src` */ +/* Used by: decompress, fullbench (does not get its definition from here) */ +size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, + blockProperties_t* bpPtr); + +/*! ZSTD_decodeSeqHeaders() : + * decode sequence header from src */ +/* Used by: decompress, fullbench (does not get its definition from here) */ +size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, + const void* src, size_t srcSize); + +/** + * @returns true iff the CPU supports dynamic BMI2 dispatch. + */ +MEM_STATIC int ZSTD_cpuSupportsBmi2(void) +{ + ZSTD_cpuid_t cpuid = ZSTD_cpuid(); + return ZSTD_cpuid_bmi1(cpuid) && ZSTD_cpuid_bmi2(cpuid); +} + +#if defined (__cplusplus) +} +#endif + +#endif /* ZSTD_CCOMMON_H_MODULE */ diff --git a/lib/zstd/lib/common/zstd_trace.h b/lib/zstd/lib/common/zstd_trace.h new file mode 100644 index 0000000..da20534 --- /dev/null +++ b/lib/zstd/lib/common/zstd_trace.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef ZSTD_TRACE_H +#define ZSTD_TRACE_H + +#if defined (__cplusplus) +extern "C" { +#endif + +#include + +/* weak symbol support + * For now, enable conservatively: + * - Only GNUC + * - Only ELF + * - Only x86-64, i386 and aarch64 + * Also, explicitly disable on platforms known not to work so they aren't + * forgotten in the future. + */ +#if !defined(ZSTD_HAVE_WEAK_SYMBOLS) && \ + defined(__GNUC__) && defined(__ELF__) && \ + (defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86) || defined(__aarch64__)) && \ + !defined(__APPLE__) && !defined(_WIN32) && !defined(__MINGW32__) && \ + !defined(__CYGWIN__) && !defined(_AIX) +# define ZSTD_HAVE_WEAK_SYMBOLS 1 +#else +# define ZSTD_HAVE_WEAK_SYMBOLS 0 +#endif +#if ZSTD_HAVE_WEAK_SYMBOLS +# define ZSTD_WEAK_ATTR __attribute__((__weak__)) +#else +# define ZSTD_WEAK_ATTR +#endif + +/* Only enable tracing when weak symbols are available. */ +#ifndef ZSTD_TRACE +# define ZSTD_TRACE ZSTD_HAVE_WEAK_SYMBOLS +#endif + +#if ZSTD_TRACE + +struct ZSTD_CCtx_s; +struct ZSTD_DCtx_s; +struct ZSTD_CCtx_params_s; + +typedef struct { + /** + * ZSTD_VERSION_NUMBER + * + * This is guaranteed to be the first member of ZSTD_trace. + * Otherwise, this struct is not stable between versions. If + * the version number does not match your expectation, you + * should not interpret the rest of the struct. + */ + unsigned version; + /** + * Non-zero if streaming (de)compression is used. + */ + unsigned streaming; + /** + * The dictionary ID. + */ + unsigned dictionaryID; + /** + * Is the dictionary cold? + * Only set on decompression. + */ + unsigned dictionaryIsCold; + /** + * The dictionary size or zero if no dictionary. + */ + size_t dictionarySize; + /** + * The uncompressed size of the data. + */ + size_t uncompressedSize; + /** + * The compressed size of the data. + */ + size_t compressedSize; + /** + * The fully resolved CCtx parameters (NULL on decompression). + */ + struct ZSTD_CCtx_params_s const* params; + /** + * The ZSTD_CCtx pointer (NULL on decompression). + */ + struct ZSTD_CCtx_s const* cctx; + /** + * The ZSTD_DCtx pointer (NULL on compression). + */ + struct ZSTD_DCtx_s const* dctx; +} ZSTD_Trace; + +/** + * A tracing context. It must be 0 when tracing is disabled. + * Otherwise, any non-zero value returned by a tracing begin() + * function is presented to any subsequent calls to end(). + * + * Any non-zero value is treated as tracing is enabled and not + * interpreted by the library. + * + * Two possible uses are: + * * A timestamp for when the begin() function was called. + * * A unique key identifying the (de)compression, like the + * address of the [dc]ctx pointer if you need to track + * more information than just a timestamp. + */ +typedef unsigned long long ZSTD_TraceCtx; + +/** + * Trace the beginning of a compression call. + * @param cctx The dctx pointer for the compression. + * It can be used as a key to map begin() to end(). + * @returns Non-zero if tracing is enabled. The return value is + * passed to ZSTD_trace_compress_end(). + */ +ZSTD_WEAK_ATTR ZSTD_TraceCtx ZSTD_trace_compress_begin( + struct ZSTD_CCtx_s const* cctx); + +/** + * Trace the end of a compression call. + * @param ctx The return value of ZSTD_trace_compress_begin(). + * @param trace The zstd tracing info. + */ +ZSTD_WEAK_ATTR void ZSTD_trace_compress_end( + ZSTD_TraceCtx ctx, + ZSTD_Trace const* trace); + +/** + * Trace the beginning of a decompression call. + * @param dctx The dctx pointer for the decompression. + * It can be used as a key to map begin() to end(). + * @returns Non-zero if tracing is enabled. The return value is + * passed to ZSTD_trace_compress_end(). + */ +ZSTD_WEAK_ATTR ZSTD_TraceCtx ZSTD_trace_decompress_begin( + struct ZSTD_DCtx_s const* dctx); + +/** + * Trace the end of a decompression call. + * @param ctx The return value of ZSTD_trace_decompress_begin(). + * @param trace The zstd tracing info. + */ +ZSTD_WEAK_ATTR void ZSTD_trace_decompress_end( + ZSTD_TraceCtx ctx, + ZSTD_Trace const* trace); + +#endif /* ZSTD_TRACE */ + +#if defined (__cplusplus) +} +#endif + +#endif /* ZSTD_TRACE_H */ diff --git a/lib/zstd/lib/decompress/huf_decompress.c b/lib/zstd/lib/decompress/huf_decompress.c new file mode 100644 index 0000000..5b217ac --- /dev/null +++ b/lib/zstd/lib/decompress/huf_decompress.c @@ -0,0 +1,1882 @@ +/* ****************************************************************** + * huff0 huffman decoder, + * part of Finite State Entropy library + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * You can contact the author at : + * - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +****************************************************************** */ + +/* ************************************************************** +* Dependencies +****************************************************************/ +#include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memset */ +#include "../common/compiler.h" +#include "../common/bitstream.h" /* BIT_* */ +#include "../common/fse.h" /* to compress headers */ +#include "../common/huf.h" +#include "../common/error_private.h" +#include "../common/zstd_internal.h" +#include "../common/bits.h" /* ZSTD_highbit32, ZSTD_countTrailingZeros64 */ + +/* ************************************************************** +* Constants +****************************************************************/ + +#define HUF_DECODER_FAST_TABLELOG 11 + +/* ************************************************************** +* Macros +****************************************************************/ + +/* These two optional macros force the use one way or another of the two + * Huffman decompression implementations. You can't force in both directions + * at the same time. + */ +#if defined(HUF_FORCE_DECOMPRESS_X1) && \ + defined(HUF_FORCE_DECOMPRESS_X2) +#error "Cannot force the use of the X1 and X2 decoders at the same time!" +#endif + +/* When DYNAMIC_BMI2 is enabled, fast decoders are only called when bmi2 is + * supported at runtime, so we can add the BMI2 target attribute. + * When it is disabled, we will still get BMI2 if it is enabled statically. + */ +#if DYNAMIC_BMI2 +# define HUF_FAST_BMI2_ATTRS BMI2_TARGET_ATTRIBUTE +#else +# define HUF_FAST_BMI2_ATTRS +#endif + +#ifdef __cplusplus +# define HUF_EXTERN_C extern "C" +#else +# define HUF_EXTERN_C +#endif +#define HUF_ASM_DECL HUF_EXTERN_C + +#if DYNAMIC_BMI2 +# define HUF_NEED_BMI2_FUNCTION 1 +#else +# define HUF_NEED_BMI2_FUNCTION 0 +#endif + +/* ************************************************************** +* Error Management +****************************************************************/ +#define HUF_isError ERR_isError + + +/* ************************************************************** +* Byte alignment for workSpace management +****************************************************************/ +#define HUF_ALIGN(x, a) HUF_ALIGN_MASK((x), (a) - 1) +#define HUF_ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) + + +/* ************************************************************** +* BMI2 Variant Wrappers +****************************************************************/ +typedef size_t (*HUF_DecompressUsingDTableFn)(void *dst, size_t dstSize, + const void *cSrc, + size_t cSrcSize, + const HUF_DTable *DTable); + +#if DYNAMIC_BMI2 + +#define HUF_DGEN(fn) \ + \ + static size_t fn##_default( \ + void* dst, size_t dstSize, \ + const void* cSrc, size_t cSrcSize, \ + const HUF_DTable* DTable) \ + { \ + return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable); \ + } \ + \ + static BMI2_TARGET_ATTRIBUTE size_t fn##_bmi2( \ + void* dst, size_t dstSize, \ + const void* cSrc, size_t cSrcSize, \ + const HUF_DTable* DTable) \ + { \ + return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable); \ + } \ + \ + static size_t fn(void* dst, size_t dstSize, void const* cSrc, \ + size_t cSrcSize, HUF_DTable const* DTable, int flags) \ + { \ + if (flags & HUF_flags_bmi2) { \ + return fn##_bmi2(dst, dstSize, cSrc, cSrcSize, DTable); \ + } \ + return fn##_default(dst, dstSize, cSrc, cSrcSize, DTable); \ + } + +#else + +#define HUF_DGEN(fn) \ + static size_t fn(void* dst, size_t dstSize, void const* cSrc, \ + size_t cSrcSize, HUF_DTable const* DTable, int flags) \ + { \ + (void)flags; \ + return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable); \ + } + +#endif + + +/*-***************************/ +/* generic DTableDesc */ +/*-***************************/ +typedef struct { BYTE maxTableLog; BYTE tableType; BYTE tableLog; BYTE reserved; } DTableDesc; + +static DTableDesc HUF_getDTableDesc(const HUF_DTable* table) +{ + DTableDesc dtd; + ZSTD_memcpy(&dtd, table, sizeof(dtd)); + return dtd; +} + +static size_t HUF_initFastDStream(BYTE const* ip) { + BYTE const lastByte = ip[7]; + size_t const bitsConsumed = lastByte ? 8 - ZSTD_highbit32(lastByte) : 0; + size_t const value = MEM_readLEST(ip) | 1; + assert(bitsConsumed <= 8); + assert(sizeof(size_t) == 8); + return value << bitsConsumed; +} + + +/** + * The input/output arguments to the Huffman fast decoding loop: + * + * ip [in/out] - The input pointers, must be updated to reflect what is consumed. + * op [in/out] - The output pointers, must be updated to reflect what is written. + * bits [in/out] - The bitstream containers, must be updated to reflect the current state. + * dt [in] - The decoding table. + * ilimit [in] - The input limit, stop when any input pointer is below ilimit. + * oend [in] - The end of the output stream. op[3] must not cross oend. + * iend [in] - The end of each input stream. ip[i] may cross iend[i], + * as long as it is above ilimit, but that indicates corruption. + */ +typedef struct { + BYTE const* ip[4]; + BYTE* op[4]; + U64 bits[4]; + void const* dt; + BYTE const* ilimit; + BYTE* oend; + BYTE const* iend[4]; +} HUF_DecompressFastArgs; + +typedef void (*HUF_DecompressFastLoopFn)(HUF_DecompressFastArgs*); + +/** + * Initializes args for the fast decoding loop. + * @returns 1 on success + * 0 if the fallback implementation should be used. + * Or an error code on failure. + */ +static size_t HUF_DecompressFastArgs_init(HUF_DecompressFastArgs* args, void* dst, size_t dstSize, void const* src, size_t srcSize, const HUF_DTable* DTable) +{ + void const* dt = DTable + 1; + U32 const dtLog = HUF_getDTableDesc(DTable).tableLog; + + const BYTE* const ilimit = (const BYTE*)src + 6 + 8; + + BYTE* const oend = (BYTE*)dst + dstSize; + + /* The fast decoding loop assumes 64-bit little-endian. + * This condition is false on x32. + */ + if (!MEM_isLittleEndian() || MEM_32bits()) + return 0; + + /* strict minimum : jump table + 1 byte per stream */ + if (srcSize < 10) + return ERROR(corruption_detected); + + /* Must have at least 8 bytes per stream because we don't handle initializing smaller bit containers. + * If table log is not correct at this point, fallback to the old decoder. + * On small inputs we don't have enough data to trigger the fast loop, so use the old decoder. + */ + if (dtLog != HUF_DECODER_FAST_TABLELOG) + return 0; + + /* Read the jump table. */ + { + const BYTE* const istart = (const BYTE*)src; + size_t const length1 = MEM_readLE16(istart); + size_t const length2 = MEM_readLE16(istart+2); + size_t const length3 = MEM_readLE16(istart+4); + size_t const length4 = srcSize - (length1 + length2 + length3 + 6); + args->iend[0] = istart + 6; /* jumpTable */ + args->iend[1] = args->iend[0] + length1; + args->iend[2] = args->iend[1] + length2; + args->iend[3] = args->iend[2] + length3; + + /* HUF_initFastDStream() requires this, and this small of an input + * won't benefit from the ASM loop anyways. + * length1 must be >= 16 so that ip[0] >= ilimit before the loop + * starts. + */ + if (length1 < 16 || length2 < 8 || length3 < 8 || length4 < 8) + return 0; + if (length4 > srcSize) return ERROR(corruption_detected); /* overflow */ + } + /* ip[] contains the position that is currently loaded into bits[]. */ + args->ip[0] = args->iend[1] - sizeof(U64); + args->ip[1] = args->iend[2] - sizeof(U64); + args->ip[2] = args->iend[3] - sizeof(U64); + args->ip[3] = (BYTE const*)src + srcSize - sizeof(U64); + + /* op[] contains the output pointers. */ + args->op[0] = (BYTE*)dst; + args->op[1] = args->op[0] + (dstSize+3)/4; + args->op[2] = args->op[1] + (dstSize+3)/4; + args->op[3] = args->op[2] + (dstSize+3)/4; + + /* No point to call the ASM loop for tiny outputs. */ + if (args->op[3] >= oend) + return 0; + + /* bits[] is the bit container. + * It is read from the MSB down to the LSB. + * It is shifted left as it is read, and zeros are + * shifted in. After the lowest valid bit a 1 is + * set, so that CountTrailingZeros(bits[]) can be used + * to count how many bits we've consumed. + */ + args->bits[0] = HUF_initFastDStream(args->ip[0]); + args->bits[1] = HUF_initFastDStream(args->ip[1]); + args->bits[2] = HUF_initFastDStream(args->ip[2]); + args->bits[3] = HUF_initFastDStream(args->ip[3]); + + /* If ip[] >= ilimit, it is guaranteed to be safe to + * reload bits[]. It may be beyond its section, but is + * guaranteed to be valid (>= istart). + */ + args->ilimit = ilimit; + + args->oend = oend; + args->dt = dt; + + return 1; +} + +static size_t HUF_initRemainingDStream(BIT_DStream_t* bit, HUF_DecompressFastArgs const* args, int stream, BYTE* segmentEnd) +{ + /* Validate that we haven't overwritten. */ + if (args->op[stream] > segmentEnd) + return ERROR(corruption_detected); + /* Validate that we haven't read beyond iend[]. + * Note that ip[] may be < iend[] because the MSB is + * the next bit to read, and we may have consumed 100% + * of the stream, so down to iend[i] - 8 is valid. + */ + if (args->ip[stream] < args->iend[stream] - 8) + return ERROR(corruption_detected); + + /* Construct the BIT_DStream_t. */ + assert(sizeof(size_t) == 8); + bit->bitContainer = MEM_readLEST(args->ip[stream]); + bit->bitsConsumed = ZSTD_countTrailingZeros64(args->bits[stream]); + bit->start = (const char*)args->iend[0]; + bit->limitPtr = bit->start + sizeof(size_t); + bit->ptr = (const char*)args->ip[stream]; + + return 0; +} + + +#ifndef HUF_FORCE_DECOMPRESS_X2 + +/*-***************************/ +/* single-symbol decoding */ +/*-***************************/ +typedef struct { BYTE nbBits; BYTE byte; } HUF_DEltX1; /* single-symbol decoding */ + +/** + * Packs 4 HUF_DEltX1 structs into a U64. This is used to lay down 4 entries at + * a time. + */ +static U64 HUF_DEltX1_set4(BYTE symbol, BYTE nbBits) { + U64 D4; + if (MEM_isLittleEndian()) { + D4 = (U64)((symbol << 8) + nbBits); + } else { + D4 = (U64)(symbol + (nbBits << 8)); + } + assert(D4 < (1U << 16)); + D4 *= 0x0001000100010001ULL; + return D4; +} + +/** + * Increase the tableLog to targetTableLog and rescales the stats. + * If tableLog > targetTableLog this is a no-op. + * @returns New tableLog + */ +static U32 HUF_rescaleStats(BYTE* huffWeight, U32* rankVal, U32 nbSymbols, U32 tableLog, U32 targetTableLog) +{ + if (tableLog > targetTableLog) + return tableLog; + if (tableLog < targetTableLog) { + U32 const scale = targetTableLog - tableLog; + U32 s; + /* Increase the weight for all non-zero probability symbols by scale. */ + for (s = 0; s < nbSymbols; ++s) { + huffWeight[s] += (BYTE)((huffWeight[s] == 0) ? 0 : scale); + } + /* Update rankVal to reflect the new weights. + * All weights except 0 get moved to weight + scale. + * Weights [1, scale] are empty. + */ + for (s = targetTableLog; s > scale; --s) { + rankVal[s] = rankVal[s - scale]; + } + for (s = scale; s > 0; --s) { + rankVal[s] = 0; + } + } + return targetTableLog; +} + +typedef struct { + U32 rankVal[HUF_TABLELOG_ABSOLUTEMAX + 1]; + U32 rankStart[HUF_TABLELOG_ABSOLUTEMAX + 1]; + U32 statsWksp[HUF_READ_STATS_WORKSPACE_SIZE_U32]; + BYTE symbols[HUF_SYMBOLVALUE_MAX + 1]; + BYTE huffWeight[HUF_SYMBOLVALUE_MAX + 1]; +} HUF_ReadDTableX1_Workspace; + +size_t HUF_readDTableX1_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int flags) +{ + U32 tableLog = 0; + U32 nbSymbols = 0; + size_t iSize; + void* const dtPtr = DTable + 1; + HUF_DEltX1* const dt = (HUF_DEltX1*)dtPtr; + HUF_ReadDTableX1_Workspace* wksp = (HUF_ReadDTableX1_Workspace*)workSpace; + + DEBUG_STATIC_ASSERT(HUF_DECOMPRESS_WORKSPACE_SIZE >= sizeof(*wksp)); + if (sizeof(*wksp) > wkspSize) return ERROR(tableLog_tooLarge); + + DEBUG_STATIC_ASSERT(sizeof(DTableDesc) == sizeof(HUF_DTable)); + /* ZSTD_memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */ + + iSize = HUF_readStats_wksp(wksp->huffWeight, HUF_SYMBOLVALUE_MAX + 1, wksp->rankVal, &nbSymbols, &tableLog, src, srcSize, wksp->statsWksp, sizeof(wksp->statsWksp), flags); + if (HUF_isError(iSize)) return iSize; + + + /* Table header */ + { DTableDesc dtd = HUF_getDTableDesc(DTable); + U32 const maxTableLog = dtd.maxTableLog + 1; + U32 const targetTableLog = MIN(maxTableLog, HUF_DECODER_FAST_TABLELOG); + tableLog = HUF_rescaleStats(wksp->huffWeight, wksp->rankVal, nbSymbols, tableLog, targetTableLog); + if (tableLog > (U32)(dtd.maxTableLog+1)) return ERROR(tableLog_tooLarge); /* DTable too small, Huffman tree cannot fit in */ + dtd.tableType = 0; + dtd.tableLog = (BYTE)tableLog; + ZSTD_memcpy(DTable, &dtd, sizeof(dtd)); + } + + /* Compute symbols and rankStart given rankVal: + * + * rankVal already contains the number of values of each weight. + * + * symbols contains the symbols ordered by weight. First are the rankVal[0] + * weight 0 symbols, followed by the rankVal[1] weight 1 symbols, and so on. + * symbols[0] is filled (but unused) to avoid a branch. + * + * rankStart contains the offset where each rank belongs in the DTable. + * rankStart[0] is not filled because there are no entries in the table for + * weight 0. + */ + { int n; + U32 nextRankStart = 0; + int const unroll = 4; + int const nLimit = (int)nbSymbols - unroll + 1; + for (n=0; n<(int)tableLog+1; n++) { + U32 const curr = nextRankStart; + nextRankStart += wksp->rankVal[n]; + wksp->rankStart[n] = curr; + } + for (n=0; n < nLimit; n += unroll) { + int u; + for (u=0; u < unroll; ++u) { + size_t const w = wksp->huffWeight[n+u]; + wksp->symbols[wksp->rankStart[w]++] = (BYTE)(n+u); + } + } + for (; n < (int)nbSymbols; ++n) { + size_t const w = wksp->huffWeight[n]; + wksp->symbols[wksp->rankStart[w]++] = (BYTE)n; + } + } + + /* fill DTable + * We fill all entries of each weight in order. + * That way length is a constant for each iteration of the outer loop. + * We can switch based on the length to a different inner loop which is + * optimized for that particular case. + */ + { U32 w; + int symbol = wksp->rankVal[0]; + int rankStart = 0; + for (w=1; wrankVal[w]; + int const length = (1 << w) >> 1; + int uStart = rankStart; + BYTE const nbBits = (BYTE)(tableLog + 1 - w); + int s; + int u; + switch (length) { + case 1: + for (s=0; ssymbols[symbol + s]; + D.nbBits = nbBits; + dt[uStart] = D; + uStart += 1; + } + break; + case 2: + for (s=0; ssymbols[symbol + s]; + D.nbBits = nbBits; + dt[uStart+0] = D; + dt[uStart+1] = D; + uStart += 2; + } + break; + case 4: + for (s=0; ssymbols[symbol + s], nbBits); + MEM_write64(dt + uStart, D4); + uStart += 4; + } + break; + case 8: + for (s=0; ssymbols[symbol + s], nbBits); + MEM_write64(dt + uStart, D4); + MEM_write64(dt + uStart + 4, D4); + uStart += 8; + } + break; + default: + for (s=0; ssymbols[symbol + s], nbBits); + for (u=0; u < length; u += 16) { + MEM_write64(dt + uStart + u + 0, D4); + MEM_write64(dt + uStart + u + 4, D4); + MEM_write64(dt + uStart + u + 8, D4); + MEM_write64(dt + uStart + u + 12, D4); + } + assert(u == length); + uStart += length; + } + break; + } + symbol += symbolCount; + rankStart += symbolCount * length; + } + } + return iSize; +} + +FORCE_INLINE_TEMPLATE BYTE +HUF_decodeSymbolX1(BIT_DStream_t* Dstream, const HUF_DEltX1* dt, const U32 dtLog) +{ + size_t const val = BIT_lookBitsFast(Dstream, dtLog); /* note : dtLog >= 1 */ + BYTE const c = dt[val].byte; + BIT_skipBits(Dstream, dt[val].nbBits); + return c; +} + +#define HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr) \ + *ptr++ = HUF_decodeSymbolX1(DStreamPtr, dt, dtLog) + +#define HUF_DECODE_SYMBOLX1_1(ptr, DStreamPtr) \ + if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \ + HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr) + +#define HUF_DECODE_SYMBOLX1_2(ptr, DStreamPtr) \ + if (MEM_64bits()) \ + HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr) + +HINT_INLINE size_t +HUF_decodeStreamX1(BYTE* p, BIT_DStream_t* const bitDPtr, BYTE* const pEnd, const HUF_DEltX1* const dt, const U32 dtLog) +{ + BYTE* const pStart = p; + + /* up to 4 symbols at a time */ + if ((pEnd - p) > 3) { + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-3)) { + HUF_DECODE_SYMBOLX1_2(p, bitDPtr); + HUF_DECODE_SYMBOLX1_1(p, bitDPtr); + HUF_DECODE_SYMBOLX1_2(p, bitDPtr); + HUF_DECODE_SYMBOLX1_0(p, bitDPtr); + } + } else { + BIT_reloadDStream(bitDPtr); + } + + /* [0-3] symbols remaining */ + if (MEM_32bits()) + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd)) + HUF_DECODE_SYMBOLX1_0(p, bitDPtr); + + /* no more data to retrieve from bitstream, no need to reload */ + while (p < pEnd) + HUF_DECODE_SYMBOLX1_0(p, bitDPtr); + + return (size_t)(pEnd-pStart); +} + +FORCE_INLINE_TEMPLATE size_t +HUF_decompress1X1_usingDTable_internal_body( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + BYTE* op = (BYTE*)dst; + BYTE* const oend = op + dstSize; + const void* dtPtr = DTable + 1; + const HUF_DEltX1* const dt = (const HUF_DEltX1*)dtPtr; + BIT_DStream_t bitD; + DTableDesc const dtd = HUF_getDTableDesc(DTable); + U32 const dtLog = dtd.tableLog; + + CHECK_F( BIT_initDStream(&bitD, cSrc, cSrcSize) ); + + HUF_decodeStreamX1(op, &bitD, oend, dt, dtLog); + + if (!BIT_endOfDStream(&bitD)) return ERROR(corruption_detected); + + return dstSize; +} + +/* HUF_decompress4X1_usingDTable_internal_body(): + * Conditions : + * @dstSize >= 6 + */ +FORCE_INLINE_TEMPLATE size_t +HUF_decompress4X1_usingDTable_internal_body( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + /* Check */ + if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */ + + { const BYTE* const istart = (const BYTE*) cSrc; + BYTE* const ostart = (BYTE*) dst; + BYTE* const oend = ostart + dstSize; + BYTE* const olimit = oend - 3; + const void* const dtPtr = DTable + 1; + const HUF_DEltX1* const dt = (const HUF_DEltX1*)dtPtr; + + /* Init */ + BIT_DStream_t bitD1; + BIT_DStream_t bitD2; + BIT_DStream_t bitD3; + BIT_DStream_t bitD4; + size_t const length1 = MEM_readLE16(istart); + size_t const length2 = MEM_readLE16(istart+2); + size_t const length3 = MEM_readLE16(istart+4); + size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6); + const BYTE* const istart1 = istart + 6; /* jumpTable */ + const BYTE* const istart2 = istart1 + length1; + const BYTE* const istart3 = istart2 + length2; + const BYTE* const istart4 = istart3 + length3; + const size_t segmentSize = (dstSize+3) / 4; + BYTE* const opStart2 = ostart + segmentSize; + BYTE* const opStart3 = opStart2 + segmentSize; + BYTE* const opStart4 = opStart3 + segmentSize; + BYTE* op1 = ostart; + BYTE* op2 = opStart2; + BYTE* op3 = opStart3; + BYTE* op4 = opStart4; + DTableDesc const dtd = HUF_getDTableDesc(DTable); + U32 const dtLog = dtd.tableLog; + U32 endSignal = 1; + + if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */ + if (opStart4 > oend) return ERROR(corruption_detected); /* overflow */ + if (dstSize < 6) return ERROR(corruption_detected); /* stream 4-split doesn't work */ + CHECK_F( BIT_initDStream(&bitD1, istart1, length1) ); + CHECK_F( BIT_initDStream(&bitD2, istart2, length2) ); + CHECK_F( BIT_initDStream(&bitD3, istart3, length3) ); + CHECK_F( BIT_initDStream(&bitD4, istart4, length4) ); + + /* up to 16 symbols per loop (4 symbols per stream) in 64-bit mode */ + if ((size_t)(oend - op4) >= sizeof(size_t)) { + for ( ; (endSignal) & (op4 < olimit) ; ) { + HUF_DECODE_SYMBOLX1_2(op1, &bitD1); + HUF_DECODE_SYMBOLX1_2(op2, &bitD2); + HUF_DECODE_SYMBOLX1_2(op3, &bitD3); + HUF_DECODE_SYMBOLX1_2(op4, &bitD4); + HUF_DECODE_SYMBOLX1_1(op1, &bitD1); + HUF_DECODE_SYMBOLX1_1(op2, &bitD2); + HUF_DECODE_SYMBOLX1_1(op3, &bitD3); + HUF_DECODE_SYMBOLX1_1(op4, &bitD4); + HUF_DECODE_SYMBOLX1_2(op1, &bitD1); + HUF_DECODE_SYMBOLX1_2(op2, &bitD2); + HUF_DECODE_SYMBOLX1_2(op3, &bitD3); + HUF_DECODE_SYMBOLX1_2(op4, &bitD4); + HUF_DECODE_SYMBOLX1_0(op1, &bitD1); + HUF_DECODE_SYMBOLX1_0(op2, &bitD2); + HUF_DECODE_SYMBOLX1_0(op3, &bitD3); + HUF_DECODE_SYMBOLX1_0(op4, &bitD4); + endSignal &= BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished; + } + } + + /* check corruption */ + /* note : should not be necessary : op# advance in lock step, and we control op4. + * but curiously, binary generated by gcc 7.2 & 7.3 with -mbmi2 runs faster when >=1 test is present */ + if (op1 > opStart2) return ERROR(corruption_detected); + if (op2 > opStart3) return ERROR(corruption_detected); + if (op3 > opStart4) return ERROR(corruption_detected); + /* note : op4 supposed already verified within main loop */ + + /* finish bitStreams one by one */ + HUF_decodeStreamX1(op1, &bitD1, opStart2, dt, dtLog); + HUF_decodeStreamX1(op2, &bitD2, opStart3, dt, dtLog); + HUF_decodeStreamX1(op3, &bitD3, opStart4, dt, dtLog); + HUF_decodeStreamX1(op4, &bitD4, oend, dt, dtLog); + + /* check */ + { U32 const endCheck = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4); + if (!endCheck) return ERROR(corruption_detected); } + + /* decoded size */ + return dstSize; + } +} + +#if HUF_NEED_BMI2_FUNCTION +static BMI2_TARGET_ATTRIBUTE +size_t HUF_decompress4X1_usingDTable_internal_bmi2(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable) { + return HUF_decompress4X1_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); +} +#endif + +static +size_t HUF_decompress4X1_usingDTable_internal_default(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable) { + return HUF_decompress4X1_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); +} + +#if ZSTD_ENABLE_ASM_X86_64_BMI2 + +HUF_ASM_DECL void HUF_decompress4X1_usingDTable_internal_fast_asm_loop(HUF_DecompressFastArgs* args) ZSTDLIB_HIDDEN; + +#endif + +static HUF_FAST_BMI2_ATTRS +void HUF_decompress4X1_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs* args) +{ + U64 bits[4]; + BYTE const* ip[4]; + BYTE* op[4]; + U16 const* const dtable = (U16 const*)args->dt; + BYTE* const oend = args->oend; + BYTE const* const ilimit = args->ilimit; + + /* Copy the arguments to local variables */ + ZSTD_memcpy(&bits, &args->bits, sizeof(bits)); + ZSTD_memcpy((void*)(&ip), &args->ip, sizeof(ip)); + ZSTD_memcpy(&op, &args->op, sizeof(op)); + + assert(MEM_isLittleEndian()); + assert(!MEM_32bits()); + + for (;;) { + BYTE* olimit; + int stream; + int symbol; + + /* Assert loop preconditions */ +#ifndef NDEBUG + for (stream = 0; stream < 4; ++stream) { + assert(op[stream] <= (stream == 3 ? oend : op[stream + 1])); + assert(ip[stream] >= ilimit); + } +#endif + /* Compute olimit */ + { + /* Each iteration produces 5 output symbols per stream */ + size_t const oiters = (size_t)(oend - op[3]) / 5; + /* Each iteration consumes up to 11 bits * 5 = 55 bits < 7 bytes + * per stream. + */ + size_t const iiters = (size_t)(ip[0] - ilimit) / 7; + /* We can safely run iters iterations before running bounds checks */ + size_t const iters = MIN(oiters, iiters); + size_t const symbols = iters * 5; + + /* We can simply check that op[3] < olimit, instead of checking all + * of our bounds, since we can't hit the other bounds until we've run + * iters iterations, which only happens when op[3] == olimit. + */ + olimit = op[3] + symbols; + + /* Exit fast decoding loop once we get close to the end. */ + if (op[3] + 20 > olimit) + break; + + /* Exit the decoding loop if any input pointer has crossed the + * previous one. This indicates corruption, and a precondition + * to our loop is that ip[i] >= ip[0]. + */ + for (stream = 1; stream < 4; ++stream) { + if (ip[stream] < ip[stream - 1]) + goto _out; + } + } + +#ifndef NDEBUG + for (stream = 1; stream < 4; ++stream) { + assert(ip[stream] >= ip[stream - 1]); + } +#endif + + do { + /* Decode 5 symbols in each of the 4 streams */ + for (symbol = 0; symbol < 5; ++symbol) { + for (stream = 0; stream < 4; ++stream) { + int const index = (int)(bits[stream] >> 53); + int const entry = (int)dtable[index]; + bits[stream] <<= (entry & 63); + op[stream][symbol] = (BYTE)((entry >> 8) & 0xFF); + } + } + /* Reload the bitstreams */ + for (stream = 0; stream < 4; ++stream) { + int const ctz = ZSTD_countTrailingZeros64(bits[stream]); + int const nbBits = ctz & 7; + int const nbBytes = ctz >> 3; + op[stream] += 5; + ip[stream] -= nbBytes; + bits[stream] = MEM_read64(ip[stream]) | 1; + bits[stream] <<= nbBits; + } + } while (op[3] < olimit); + } + +_out: + + /* Save the final values of each of the state variables back to args. */ + ZSTD_memcpy(&args->bits, &bits, sizeof(bits)); + ZSTD_memcpy((void*)(&args->ip), &ip, sizeof(ip)); + ZSTD_memcpy(&args->op, &op, sizeof(op)); +} + +/** + * @returns @p dstSize on success (>= 6) + * 0 if the fallback implementation should be used + * An error if an error occurred + */ +static HUF_FAST_BMI2_ATTRS +size_t +HUF_decompress4X1_usingDTable_internal_fast( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable, + HUF_DecompressFastLoopFn loopFn) +{ + void const* dt = DTable + 1; + const BYTE* const iend = (const BYTE*)cSrc + 6; + BYTE* const oend = (BYTE*)dst + dstSize; + HUF_DecompressFastArgs args; + { size_t const ret = HUF_DecompressFastArgs_init(&args, dst, dstSize, cSrc, cSrcSize, DTable); + FORWARD_IF_ERROR(ret, "Failed to init fast loop args"); + if (ret == 0) + return 0; + } + + assert(args.ip[0] >= args.ilimit); + loopFn(&args); + + /* Our loop guarantees that ip[] >= ilimit and that we haven't + * overwritten any op[]. + */ + assert(args.ip[0] >= iend); + assert(args.ip[1] >= iend); + assert(args.ip[2] >= iend); + assert(args.ip[3] >= iend); + assert(args.op[3] <= oend); + (void)iend; + + /* finish bit streams one by one. */ + { size_t const segmentSize = (dstSize+3) / 4; + BYTE* segmentEnd = (BYTE*)dst; + int i; + for (i = 0; i < 4; ++i) { + BIT_DStream_t bit; + if (segmentSize <= (size_t)(oend - segmentEnd)) + segmentEnd += segmentSize; + else + segmentEnd = oend; + FORWARD_IF_ERROR(HUF_initRemainingDStream(&bit, &args, i, segmentEnd), "corruption"); + /* Decompress and validate that we've produced exactly the expected length. */ + args.op[i] += HUF_decodeStreamX1(args.op[i], &bit, segmentEnd, (HUF_DEltX1 const*)dt, HUF_DECODER_FAST_TABLELOG); + if (args.op[i] != segmentEnd) return ERROR(corruption_detected); + } + } + + /* decoded size */ + assert(dstSize != 0); + return dstSize; +} + +HUF_DGEN(HUF_decompress1X1_usingDTable_internal) + +static size_t HUF_decompress4X1_usingDTable_internal(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable, int flags) +{ + HUF_DecompressUsingDTableFn fallbackFn = HUF_decompress4X1_usingDTable_internal_default; + HUF_DecompressFastLoopFn loopFn = HUF_decompress4X1_usingDTable_internal_fast_c_loop; + +#if DYNAMIC_BMI2 + if (flags & HUF_flags_bmi2) { + fallbackFn = HUF_decompress4X1_usingDTable_internal_bmi2; +# if ZSTD_ENABLE_ASM_X86_64_BMI2 + if (!(flags & HUF_flags_disableAsm)) { + loopFn = HUF_decompress4X1_usingDTable_internal_fast_asm_loop; + } +# endif + } else { + return fallbackFn(dst, dstSize, cSrc, cSrcSize, DTable); + } +#endif + +#if ZSTD_ENABLE_ASM_X86_64_BMI2 && defined(__BMI2__) + if (!(flags & HUF_flags_disableAsm)) { + loopFn = HUF_decompress4X1_usingDTable_internal_fast_asm_loop; + } +#endif + + if (!(flags & HUF_flags_disableFast)) { + size_t const ret = HUF_decompress4X1_usingDTable_internal_fast(dst, dstSize, cSrc, cSrcSize, DTable, loopFn); + if (ret != 0) + return ret; + } + return fallbackFn(dst, dstSize, cSrc, cSrcSize, DTable); +} + +static size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + void* workSpace, size_t wkspSize, int flags) +{ + const BYTE* ip = (const BYTE*) cSrc; + + size_t const hSize = HUF_readDTableX1_wksp(dctx, cSrc, cSrcSize, workSpace, wkspSize, flags); + if (HUF_isError(hSize)) return hSize; + if (hSize >= cSrcSize) return ERROR(srcSize_wrong); + ip += hSize; cSrcSize -= hSize; + + return HUF_decompress4X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, flags); +} + +#endif /* HUF_FORCE_DECOMPRESS_X2 */ + + +#ifndef HUF_FORCE_DECOMPRESS_X1 + +/* *************************/ +/* double-symbols decoding */ +/* *************************/ + +typedef struct { U16 sequence; BYTE nbBits; BYTE length; } HUF_DEltX2; /* double-symbols decoding */ +typedef struct { BYTE symbol; } sortedSymbol_t; +typedef U32 rankValCol_t[HUF_TABLELOG_MAX + 1]; +typedef rankValCol_t rankVal_t[HUF_TABLELOG_MAX]; + +/** + * Constructs a HUF_DEltX2 in a U32. + */ +static U32 HUF_buildDEltX2U32(U32 symbol, U32 nbBits, U32 baseSeq, int level) +{ + U32 seq; + DEBUG_STATIC_ASSERT(offsetof(HUF_DEltX2, sequence) == 0); + DEBUG_STATIC_ASSERT(offsetof(HUF_DEltX2, nbBits) == 2); + DEBUG_STATIC_ASSERT(offsetof(HUF_DEltX2, length) == 3); + DEBUG_STATIC_ASSERT(sizeof(HUF_DEltX2) == sizeof(U32)); + if (MEM_isLittleEndian()) { + seq = level == 1 ? symbol : (baseSeq + (symbol << 8)); + return seq + (nbBits << 16) + ((U32)level << 24); + } else { + seq = level == 1 ? (symbol << 8) : ((baseSeq << 8) + symbol); + return (seq << 16) + (nbBits << 8) + (U32)level; + } +} + +/** + * Constructs a HUF_DEltX2. + */ +static HUF_DEltX2 HUF_buildDEltX2(U32 symbol, U32 nbBits, U32 baseSeq, int level) +{ + HUF_DEltX2 DElt; + U32 const val = HUF_buildDEltX2U32(symbol, nbBits, baseSeq, level); + DEBUG_STATIC_ASSERT(sizeof(DElt) == sizeof(val)); + ZSTD_memcpy(&DElt, &val, sizeof(val)); + return DElt; +} + +/** + * Constructs 2 HUF_DEltX2s and packs them into a U64. + */ +static U64 HUF_buildDEltX2U64(U32 symbol, U32 nbBits, U16 baseSeq, int level) +{ + U32 DElt = HUF_buildDEltX2U32(symbol, nbBits, baseSeq, level); + return (U64)DElt + ((U64)DElt << 32); +} + +/** + * Fills the DTable rank with all the symbols from [begin, end) that are each + * nbBits long. + * + * @param DTableRank The start of the rank in the DTable. + * @param begin The first symbol to fill (inclusive). + * @param end The last symbol to fill (exclusive). + * @param nbBits Each symbol is nbBits long. + * @param tableLog The table log. + * @param baseSeq If level == 1 { 0 } else { the first level symbol } + * @param level The level in the table. Must be 1 or 2. + */ +static void HUF_fillDTableX2ForWeight( + HUF_DEltX2* DTableRank, + sortedSymbol_t const* begin, sortedSymbol_t const* end, + U32 nbBits, U32 tableLog, + U16 baseSeq, int const level) +{ + U32 const length = 1U << ((tableLog - nbBits) & 0x1F /* quiet static-analyzer */); + const sortedSymbol_t* ptr; + assert(level >= 1 && level <= 2); + switch (length) { + case 1: + for (ptr = begin; ptr != end; ++ptr) { + HUF_DEltX2 const DElt = HUF_buildDEltX2(ptr->symbol, nbBits, baseSeq, level); + *DTableRank++ = DElt; + } + break; + case 2: + for (ptr = begin; ptr != end; ++ptr) { + HUF_DEltX2 const DElt = HUF_buildDEltX2(ptr->symbol, nbBits, baseSeq, level); + DTableRank[0] = DElt; + DTableRank[1] = DElt; + DTableRank += 2; + } + break; + case 4: + for (ptr = begin; ptr != end; ++ptr) { + U64 const DEltX2 = HUF_buildDEltX2U64(ptr->symbol, nbBits, baseSeq, level); + ZSTD_memcpy(DTableRank + 0, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 2, &DEltX2, sizeof(DEltX2)); + DTableRank += 4; + } + break; + case 8: + for (ptr = begin; ptr != end; ++ptr) { + U64 const DEltX2 = HUF_buildDEltX2U64(ptr->symbol, nbBits, baseSeq, level); + ZSTD_memcpy(DTableRank + 0, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 2, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 4, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 6, &DEltX2, sizeof(DEltX2)); + DTableRank += 8; + } + break; + default: + for (ptr = begin; ptr != end; ++ptr) { + U64 const DEltX2 = HUF_buildDEltX2U64(ptr->symbol, nbBits, baseSeq, level); + HUF_DEltX2* const DTableRankEnd = DTableRank + length; + for (; DTableRank != DTableRankEnd; DTableRank += 8) { + ZSTD_memcpy(DTableRank + 0, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 2, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 4, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 6, &DEltX2, sizeof(DEltX2)); + } + } + break; + } +} + +/* HUF_fillDTableX2Level2() : + * `rankValOrigin` must be a table of at least (HUF_TABLELOG_MAX + 1) U32 */ +static void HUF_fillDTableX2Level2(HUF_DEltX2* DTable, U32 targetLog, const U32 consumedBits, + const U32* rankVal, const int minWeight, const int maxWeight1, + const sortedSymbol_t* sortedSymbols, U32 const* rankStart, + U32 nbBitsBaseline, U16 baseSeq) +{ + /* Fill skipped values (all positions up to rankVal[minWeight]). + * These are positions only get a single symbol because the combined weight + * is too large. + */ + if (minWeight>1) { + U32 const length = 1U << ((targetLog - consumedBits) & 0x1F /* quiet static-analyzer */); + U64 const DEltX2 = HUF_buildDEltX2U64(baseSeq, consumedBits, /* baseSeq */ 0, /* level */ 1); + int const skipSize = rankVal[minWeight]; + assert(length > 1); + assert((U32)skipSize < length); + switch (length) { + case 2: + assert(skipSize == 1); + ZSTD_memcpy(DTable, &DEltX2, sizeof(DEltX2)); + break; + case 4: + assert(skipSize <= 4); + ZSTD_memcpy(DTable + 0, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTable + 2, &DEltX2, sizeof(DEltX2)); + break; + default: + { + int i; + for (i = 0; i < skipSize; i += 8) { + ZSTD_memcpy(DTable + i + 0, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTable + i + 2, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTable + i + 4, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTable + i + 6, &DEltX2, sizeof(DEltX2)); + } + } + } + } + + /* Fill each of the second level symbols by weight. */ + { + int w; + for (w = minWeight; w < maxWeight1; ++w) { + int const begin = rankStart[w]; + int const end = rankStart[w+1]; + U32 const nbBits = nbBitsBaseline - w; + U32 const totalBits = nbBits + consumedBits; + HUF_fillDTableX2ForWeight( + DTable + rankVal[w], + sortedSymbols + begin, sortedSymbols + end, + totalBits, targetLog, + baseSeq, /* level */ 2); + } + } +} + +static void HUF_fillDTableX2(HUF_DEltX2* DTable, const U32 targetLog, + const sortedSymbol_t* sortedList, + const U32* rankStart, rankValCol_t* rankValOrigin, const U32 maxWeight, + const U32 nbBitsBaseline) +{ + U32* const rankVal = rankValOrigin[0]; + const int scaleLog = nbBitsBaseline - targetLog; /* note : targetLog >= srcLog, hence scaleLog <= 1 */ + const U32 minBits = nbBitsBaseline - maxWeight; + int w; + int const wEnd = (int)maxWeight + 1; + + /* Fill DTable in order of weight. */ + for (w = 1; w < wEnd; ++w) { + int const begin = (int)rankStart[w]; + int const end = (int)rankStart[w+1]; + U32 const nbBits = nbBitsBaseline - w; + + if (targetLog-nbBits >= minBits) { + /* Enough room for a second symbol. */ + int start = rankVal[w]; + U32 const length = 1U << ((targetLog - nbBits) & 0x1F /* quiet static-analyzer */); + int minWeight = nbBits + scaleLog; + int s; + if (minWeight < 1) minWeight = 1; + /* Fill the DTable for every symbol of weight w. + * These symbols get at least 1 second symbol. + */ + for (s = begin; s != end; ++s) { + HUF_fillDTableX2Level2( + DTable + start, targetLog, nbBits, + rankValOrigin[nbBits], minWeight, wEnd, + sortedList, rankStart, + nbBitsBaseline, sortedList[s].symbol); + start += length; + } + } else { + /* Only a single symbol. */ + HUF_fillDTableX2ForWeight( + DTable + rankVal[w], + sortedList + begin, sortedList + end, + nbBits, targetLog, + /* baseSeq */ 0, /* level */ 1); + } + } +} + +typedef struct { + rankValCol_t rankVal[HUF_TABLELOG_MAX]; + U32 rankStats[HUF_TABLELOG_MAX + 1]; + U32 rankStart0[HUF_TABLELOG_MAX + 3]; + sortedSymbol_t sortedSymbol[HUF_SYMBOLVALUE_MAX + 1]; + BYTE weightList[HUF_SYMBOLVALUE_MAX + 1]; + U32 calleeWksp[HUF_READ_STATS_WORKSPACE_SIZE_U32]; +} HUF_ReadDTableX2_Workspace; + +size_t HUF_readDTableX2_wksp(HUF_DTable* DTable, + const void* src, size_t srcSize, + void* workSpace, size_t wkspSize, int flags) +{ + U32 tableLog, maxW, nbSymbols; + DTableDesc dtd = HUF_getDTableDesc(DTable); + U32 maxTableLog = dtd.maxTableLog; + size_t iSize; + void* dtPtr = DTable+1; /* force compiler to avoid strict-aliasing */ + HUF_DEltX2* const dt = (HUF_DEltX2*)dtPtr; + U32 *rankStart; + + HUF_ReadDTableX2_Workspace* const wksp = (HUF_ReadDTableX2_Workspace*)workSpace; + + if (sizeof(*wksp) > wkspSize) return ERROR(GENERIC); + + rankStart = wksp->rankStart0 + 1; + ZSTD_memset(wksp->rankStats, 0, sizeof(wksp->rankStats)); + ZSTD_memset(wksp->rankStart0, 0, sizeof(wksp->rankStart0)); + + DEBUG_STATIC_ASSERT(sizeof(HUF_DEltX2) == sizeof(HUF_DTable)); /* if compiler fails here, assertion is wrong */ + if (maxTableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge); + /* ZSTD_memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */ + + iSize = HUF_readStats_wksp(wksp->weightList, HUF_SYMBOLVALUE_MAX + 1, wksp->rankStats, &nbSymbols, &tableLog, src, srcSize, wksp->calleeWksp, sizeof(wksp->calleeWksp), flags); + if (HUF_isError(iSize)) return iSize; + + /* check result */ + if (tableLog > maxTableLog) return ERROR(tableLog_tooLarge); /* DTable can't fit code depth */ + if (tableLog <= HUF_DECODER_FAST_TABLELOG && maxTableLog > HUF_DECODER_FAST_TABLELOG) maxTableLog = HUF_DECODER_FAST_TABLELOG; + + /* find maxWeight */ + for (maxW = tableLog; wksp->rankStats[maxW]==0; maxW--) {} /* necessarily finds a solution before 0 */ + + /* Get start index of each weight */ + { U32 w, nextRankStart = 0; + for (w=1; wrankStats[w]; + rankStart[w] = curr; + } + rankStart[0] = nextRankStart; /* put all 0w symbols at the end of sorted list*/ + rankStart[maxW+1] = nextRankStart; + } + + /* sort symbols by weight */ + { U32 s; + for (s=0; sweightList[s]; + U32 const r = rankStart[w]++; + wksp->sortedSymbol[r].symbol = (BYTE)s; + } + rankStart[0] = 0; /* forget 0w symbols; this is beginning of weight(1) */ + } + + /* Build rankVal */ + { U32* const rankVal0 = wksp->rankVal[0]; + { int const rescale = (maxTableLog-tableLog) - 1; /* tableLog <= maxTableLog */ + U32 nextRankVal = 0; + U32 w; + for (w=1; wrankStats[w] << (w+rescale); + rankVal0[w] = curr; + } } + { U32 const minBits = tableLog+1 - maxW; + U32 consumed; + for (consumed = minBits; consumed < maxTableLog - minBits + 1; consumed++) { + U32* const rankValPtr = wksp->rankVal[consumed]; + U32 w; + for (w = 1; w < maxW+1; w++) { + rankValPtr[w] = rankVal0[w] >> consumed; + } } } } + + HUF_fillDTableX2(dt, maxTableLog, + wksp->sortedSymbol, + wksp->rankStart0, wksp->rankVal, maxW, + tableLog+1); + + dtd.tableLog = (BYTE)maxTableLog; + dtd.tableType = 1; + ZSTD_memcpy(DTable, &dtd, sizeof(dtd)); + return iSize; +} + + +FORCE_INLINE_TEMPLATE U32 +HUF_decodeSymbolX2(void* op, BIT_DStream_t* DStream, const HUF_DEltX2* dt, const U32 dtLog) +{ + size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */ + ZSTD_memcpy(op, &dt[val].sequence, 2); + BIT_skipBits(DStream, dt[val].nbBits); + return dt[val].length; +} + +FORCE_INLINE_TEMPLATE U32 +HUF_decodeLastSymbolX2(void* op, BIT_DStream_t* DStream, const HUF_DEltX2* dt, const U32 dtLog) +{ + size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */ + ZSTD_memcpy(op, &dt[val].sequence, 1); + if (dt[val].length==1) { + BIT_skipBits(DStream, dt[val].nbBits); + } else { + if (DStream->bitsConsumed < (sizeof(DStream->bitContainer)*8)) { + BIT_skipBits(DStream, dt[val].nbBits); + if (DStream->bitsConsumed > (sizeof(DStream->bitContainer)*8)) + /* ugly hack; works only because it's the last symbol. Note : can't easily extract nbBits from just this symbol */ + DStream->bitsConsumed = (sizeof(DStream->bitContainer)*8); + } + } + return 1; +} + +#define HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr) \ + ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog) + +#define HUF_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \ + if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \ + ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog) + +#define HUF_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \ + if (MEM_64bits()) \ + ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog) + +HINT_INLINE size_t +HUF_decodeStreamX2(BYTE* p, BIT_DStream_t* bitDPtr, BYTE* const pEnd, + const HUF_DEltX2* const dt, const U32 dtLog) +{ + BYTE* const pStart = p; + + /* up to 8 symbols at a time */ + if ((size_t)(pEnd - p) >= sizeof(bitDPtr->bitContainer)) { + if (dtLog <= 11 && MEM_64bits()) { + /* up to 10 symbols at a time */ + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-9)) { + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + } + } else { + /* up to 8 symbols at a time */ + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-(sizeof(bitDPtr->bitContainer)-1))) { + HUF_DECODE_SYMBOLX2_2(p, bitDPtr); + HUF_DECODE_SYMBOLX2_1(p, bitDPtr); + HUF_DECODE_SYMBOLX2_2(p, bitDPtr); + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + } + } + } else { + BIT_reloadDStream(bitDPtr); + } + + /* closer to end : up to 2 symbols at a time */ + if ((size_t)(pEnd - p) >= 2) { + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p <= pEnd-2)) + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + + while (p <= pEnd-2) + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); /* no need to reload : reached the end of DStream */ + } + + if (p < pEnd) + p += HUF_decodeLastSymbolX2(p, bitDPtr, dt, dtLog); + + return p-pStart; +} + +FORCE_INLINE_TEMPLATE size_t +HUF_decompress1X2_usingDTable_internal_body( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + BIT_DStream_t bitD; + + /* Init */ + CHECK_F( BIT_initDStream(&bitD, cSrc, cSrcSize) ); + + /* decode */ + { BYTE* const ostart = (BYTE*) dst; + BYTE* const oend = ostart + dstSize; + const void* const dtPtr = DTable+1; /* force compiler to not use strict-aliasing */ + const HUF_DEltX2* const dt = (const HUF_DEltX2*)dtPtr; + DTableDesc const dtd = HUF_getDTableDesc(DTable); + HUF_decodeStreamX2(ostart, &bitD, oend, dt, dtd.tableLog); + } + + /* check */ + if (!BIT_endOfDStream(&bitD)) return ERROR(corruption_detected); + + /* decoded size */ + return dstSize; +} + +/* HUF_decompress4X2_usingDTable_internal_body(): + * Conditions: + * @dstSize >= 6 + */ +FORCE_INLINE_TEMPLATE size_t +HUF_decompress4X2_usingDTable_internal_body( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */ + + { const BYTE* const istart = (const BYTE*) cSrc; + BYTE* const ostart = (BYTE*) dst; + BYTE* const oend = ostart + dstSize; + BYTE* const olimit = oend - (sizeof(size_t)-1); + const void* const dtPtr = DTable+1; + const HUF_DEltX2* const dt = (const HUF_DEltX2*)dtPtr; + + /* Init */ + BIT_DStream_t bitD1; + BIT_DStream_t bitD2; + BIT_DStream_t bitD3; + BIT_DStream_t bitD4; + size_t const length1 = MEM_readLE16(istart); + size_t const length2 = MEM_readLE16(istart+2); + size_t const length3 = MEM_readLE16(istart+4); + size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6); + const BYTE* const istart1 = istart + 6; /* jumpTable */ + const BYTE* const istart2 = istart1 + length1; + const BYTE* const istart3 = istart2 + length2; + const BYTE* const istart4 = istart3 + length3; + size_t const segmentSize = (dstSize+3) / 4; + BYTE* const opStart2 = ostart + segmentSize; + BYTE* const opStart3 = opStart2 + segmentSize; + BYTE* const opStart4 = opStart3 + segmentSize; + BYTE* op1 = ostart; + BYTE* op2 = opStart2; + BYTE* op3 = opStart3; + BYTE* op4 = opStart4; + U32 endSignal = 1; + DTableDesc const dtd = HUF_getDTableDesc(DTable); + U32 const dtLog = dtd.tableLog; + + if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */ + if (opStart4 > oend) return ERROR(corruption_detected); /* overflow */ + if (dstSize < 6) return ERROR(corruption_detected); /* stream 4-split doesn't work */ + CHECK_F( BIT_initDStream(&bitD1, istart1, length1) ); + CHECK_F( BIT_initDStream(&bitD2, istart2, length2) ); + CHECK_F( BIT_initDStream(&bitD3, istart3, length3) ); + CHECK_F( BIT_initDStream(&bitD4, istart4, length4) ); + + /* 16-32 symbols per loop (4-8 symbols per stream) */ + if ((size_t)(oend - op4) >= sizeof(size_t)) { + for ( ; (endSignal) & (op4 < olimit); ) { +#if defined(__clang__) && (defined(__x86_64__) || defined(__i386__)) + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_1(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_0(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_1(op2, &bitD2); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_0(op2, &bitD2); + endSignal &= BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished; + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_1(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_0(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_1(op4, &bitD4); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_0(op4, &bitD4); + endSignal &= BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished; +#else + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_1(op1, &bitD1); + HUF_DECODE_SYMBOLX2_1(op2, &bitD2); + HUF_DECODE_SYMBOLX2_1(op3, &bitD3); + HUF_DECODE_SYMBOLX2_1(op4, &bitD4); + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_0(op1, &bitD1); + HUF_DECODE_SYMBOLX2_0(op2, &bitD2); + HUF_DECODE_SYMBOLX2_0(op3, &bitD3); + HUF_DECODE_SYMBOLX2_0(op4, &bitD4); + endSignal = (U32)LIKELY((U32) + (BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished) + & (BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished) + & (BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished) + & (BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished)); +#endif + } + } + + /* check corruption */ + if (op1 > opStart2) return ERROR(corruption_detected); + if (op2 > opStart3) return ERROR(corruption_detected); + if (op3 > opStart4) return ERROR(corruption_detected); + /* note : op4 already verified within main loop */ + + /* finish bitStreams one by one */ + HUF_decodeStreamX2(op1, &bitD1, opStart2, dt, dtLog); + HUF_decodeStreamX2(op2, &bitD2, opStart3, dt, dtLog); + HUF_decodeStreamX2(op3, &bitD3, opStart4, dt, dtLog); + HUF_decodeStreamX2(op4, &bitD4, oend, dt, dtLog); + + /* check */ + { U32 const endCheck = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4); + if (!endCheck) return ERROR(corruption_detected); } + + /* decoded size */ + return dstSize; + } +} + +#if HUF_NEED_BMI2_FUNCTION +static BMI2_TARGET_ATTRIBUTE +size_t HUF_decompress4X2_usingDTable_internal_bmi2(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable) { + return HUF_decompress4X2_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); +} +#endif + +static +size_t HUF_decompress4X2_usingDTable_internal_default(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable) { + return HUF_decompress4X2_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); +} + +#if ZSTD_ENABLE_ASM_X86_64_BMI2 + +HUF_ASM_DECL void HUF_decompress4X2_usingDTable_internal_fast_asm_loop(HUF_DecompressFastArgs* args) ZSTDLIB_HIDDEN; + +#endif + +static HUF_FAST_BMI2_ATTRS +void HUF_decompress4X2_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs* args) +{ + U64 bits[4]; + BYTE const* ip[4]; + BYTE* op[4]; + BYTE* oend[4]; + HUF_DEltX2 const* const dtable = (HUF_DEltX2 const*)args->dt; + BYTE const* const ilimit = args->ilimit; + + /* Copy the arguments to local registers. */ + ZSTD_memcpy(&bits, &args->bits, sizeof(bits)); + ZSTD_memcpy((void*)(&ip), &args->ip, sizeof(ip)); + ZSTD_memcpy(&op, &args->op, sizeof(op)); + + oend[0] = op[1]; + oend[1] = op[2]; + oend[2] = op[3]; + oend[3] = args->oend; + + assert(MEM_isLittleEndian()); + assert(!MEM_32bits()); + + for (;;) { + BYTE* olimit; + int stream; + int symbol; + + /* Assert loop preconditions */ +#ifndef NDEBUG + for (stream = 0; stream < 4; ++stream) { + assert(op[stream] <= oend[stream]); + assert(ip[stream] >= ilimit); + } +#endif + /* Compute olimit */ + { + /* Each loop does 5 table lookups for each of the 4 streams. + * Each table lookup consumes up to 11 bits of input, and produces + * up to 2 bytes of output. + */ + /* We can consume up to 7 bytes of input per iteration per stream. + * We also know that each input pointer is >= ip[0]. So we can run + * iters loops before running out of input. + */ + size_t iters = (size_t)(ip[0] - ilimit) / 7; + /* Each iteration can produce up to 10 bytes of output per stream. + * Each output stream my advance at different rates. So take the + * minimum number of safe iterations among all the output streams. + */ + for (stream = 0; stream < 4; ++stream) { + size_t const oiters = (size_t)(oend[stream] - op[stream]) / 10; + iters = MIN(iters, oiters); + } + + /* Each iteration produces at least 5 output symbols. So until + * op[3] crosses olimit, we know we haven't executed iters + * iterations yet. This saves us maintaining an iters counter, + * at the expense of computing the remaining # of iterations + * more frequently. + */ + olimit = op[3] + (iters * 5); + + /* Exit the fast decoding loop if we are too close to the end. */ + if (op[3] + 10 > olimit) + break; + + /* Exit the decoding loop if any input pointer has crossed the + * previous one. This indicates corruption, and a precondition + * to our loop is that ip[i] >= ip[0]. + */ + for (stream = 1; stream < 4; ++stream) { + if (ip[stream] < ip[stream - 1]) + goto _out; + } + } + +#ifndef NDEBUG + for (stream = 1; stream < 4; ++stream) { + assert(ip[stream] >= ip[stream - 1]); + } +#endif + + do { + /* Do 5 table lookups for each of the first 3 streams */ + for (symbol = 0; symbol < 5; ++symbol) { + for (stream = 0; stream < 3; ++stream) { + int const index = (int)(bits[stream] >> 53); + HUF_DEltX2 const entry = dtable[index]; + MEM_write16(op[stream], entry.sequence); + bits[stream] <<= (entry.nbBits); + op[stream] += (entry.length); + } + } + /* Do 1 table lookup from the final stream */ + { + int const index = (int)(bits[3] >> 53); + HUF_DEltX2 const entry = dtable[index]; + MEM_write16(op[3], entry.sequence); + bits[3] <<= (entry.nbBits); + op[3] += (entry.length); + } + /* Do 4 table lookups from the final stream & reload bitstreams */ + for (stream = 0; stream < 4; ++stream) { + /* Do a table lookup from the final stream. + * This is interleaved with the reloading to reduce register + * pressure. This shouldn't be necessary, but compilers can + * struggle with codegen with high register pressure. + */ + { + int const index = (int)(bits[3] >> 53); + HUF_DEltX2 const entry = dtable[index]; + MEM_write16(op[3], entry.sequence); + bits[3] <<= (entry.nbBits); + op[3] += (entry.length); + } + /* Reload the bistreams. The final bitstream must be reloaded + * after the 5th symbol was decoded. + */ + { + int const ctz = ZSTD_countTrailingZeros64(bits[stream]); + int const nbBits = ctz & 7; + int const nbBytes = ctz >> 3; + ip[stream] -= nbBytes; + bits[stream] = MEM_read64(ip[stream]) | 1; + bits[stream] <<= nbBits; + } + } + } while (op[3] < olimit); + } + +_out: + + /* Save the final values of each of the state variables back to args. */ + ZSTD_memcpy(&args->bits, &bits, sizeof(bits)); + ZSTD_memcpy((void*)(&args->ip), &ip, sizeof(ip)); + ZSTD_memcpy(&args->op, &op, sizeof(op)); +} + + +static HUF_FAST_BMI2_ATTRS size_t +HUF_decompress4X2_usingDTable_internal_fast( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable, + HUF_DecompressFastLoopFn loopFn) { + void const* dt = DTable + 1; + const BYTE* const iend = (const BYTE*)cSrc + 6; + BYTE* const oend = (BYTE*)dst + dstSize; + HUF_DecompressFastArgs args; + { + size_t const ret = HUF_DecompressFastArgs_init(&args, dst, dstSize, cSrc, cSrcSize, DTable); + FORWARD_IF_ERROR(ret, "Failed to init asm args"); + if (ret == 0) + return 0; + } + + assert(args.ip[0] >= args.ilimit); + loopFn(&args); + + /* note : op4 already verified within main loop */ + assert(args.ip[0] >= iend); + assert(args.ip[1] >= iend); + assert(args.ip[2] >= iend); + assert(args.ip[3] >= iend); + assert(args.op[3] <= oend); + (void)iend; + + /* finish bitStreams one by one */ + { + size_t const segmentSize = (dstSize+3) / 4; + BYTE* segmentEnd = (BYTE*)dst; + int i; + for (i = 0; i < 4; ++i) { + BIT_DStream_t bit; + if (segmentSize <= (size_t)(oend - segmentEnd)) + segmentEnd += segmentSize; + else + segmentEnd = oend; + FORWARD_IF_ERROR(HUF_initRemainingDStream(&bit, &args, i, segmentEnd), "corruption"); + args.op[i] += HUF_decodeStreamX2(args.op[i], &bit, segmentEnd, (HUF_DEltX2 const*)dt, HUF_DECODER_FAST_TABLELOG); + if (args.op[i] != segmentEnd) + return ERROR(corruption_detected); + } + } + + /* decoded size */ + return dstSize; +} + +static size_t HUF_decompress4X2_usingDTable_internal(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable, int flags) +{ + HUF_DecompressUsingDTableFn fallbackFn = HUF_decompress4X2_usingDTable_internal_default; + HUF_DecompressFastLoopFn loopFn = HUF_decompress4X2_usingDTable_internal_fast_c_loop; + +#if DYNAMIC_BMI2 + if (flags & HUF_flags_bmi2) { + fallbackFn = HUF_decompress4X2_usingDTable_internal_bmi2; +# if ZSTD_ENABLE_ASM_X86_64_BMI2 + if (!(flags & HUF_flags_disableAsm)) { + loopFn = HUF_decompress4X2_usingDTable_internal_fast_asm_loop; + } +# endif + } else { + return fallbackFn(dst, dstSize, cSrc, cSrcSize, DTable); + } +#endif + +#if ZSTD_ENABLE_ASM_X86_64_BMI2 && defined(__BMI2__) + if (!(flags & HUF_flags_disableAsm)) { + loopFn = HUF_decompress4X2_usingDTable_internal_fast_asm_loop; + } +#endif + + if (!(flags & HUF_flags_disableFast)) { + size_t const ret = HUF_decompress4X2_usingDTable_internal_fast(dst, dstSize, cSrc, cSrcSize, DTable, loopFn); + if (ret != 0) + return ret; + } + return fallbackFn(dst, dstSize, cSrc, cSrcSize, DTable); +} + +HUF_DGEN(HUF_decompress1X2_usingDTable_internal) + +size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + void* workSpace, size_t wkspSize, int flags) +{ + const BYTE* ip = (const BYTE*) cSrc; + + size_t const hSize = HUF_readDTableX2_wksp(DCtx, cSrc, cSrcSize, + workSpace, wkspSize, flags); + if (HUF_isError(hSize)) return hSize; + if (hSize >= cSrcSize) return ERROR(srcSize_wrong); + ip += hSize; cSrcSize -= hSize; + + return HUF_decompress1X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx, flags); +} + +static size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + void* workSpace, size_t wkspSize, int flags) +{ + const BYTE* ip = (const BYTE*) cSrc; + + size_t hSize = HUF_readDTableX2_wksp(dctx, cSrc, cSrcSize, + workSpace, wkspSize, flags); + if (HUF_isError(hSize)) return hSize; + if (hSize >= cSrcSize) return ERROR(srcSize_wrong); + ip += hSize; cSrcSize -= hSize; + + return HUF_decompress4X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, flags); +} + +#endif /* HUF_FORCE_DECOMPRESS_X1 */ + + +/* ***********************************/ +/* Universal decompression selectors */ +/* ***********************************/ + + +#if !defined(HUF_FORCE_DECOMPRESS_X1) && !defined(HUF_FORCE_DECOMPRESS_X2) +typedef struct { U32 tableTime; U32 decode256Time; } algo_time_t; +static const algo_time_t algoTime[16 /* Quantization */][2 /* single, double */] = +{ + /* single, double, quad */ + {{0,0}, {1,1}}, /* Q==0 : impossible */ + {{0,0}, {1,1}}, /* Q==1 : impossible */ + {{ 150,216}, { 381,119}}, /* Q == 2 : 12-18% */ + {{ 170,205}, { 514,112}}, /* Q == 3 : 18-25% */ + {{ 177,199}, { 539,110}}, /* Q == 4 : 25-32% */ + {{ 197,194}, { 644,107}}, /* Q == 5 : 32-38% */ + {{ 221,192}, { 735,107}}, /* Q == 6 : 38-44% */ + {{ 256,189}, { 881,106}}, /* Q == 7 : 44-50% */ + {{ 359,188}, {1167,109}}, /* Q == 8 : 50-56% */ + {{ 582,187}, {1570,114}}, /* Q == 9 : 56-62% */ + {{ 688,187}, {1712,122}}, /* Q ==10 : 62-69% */ + {{ 825,186}, {1965,136}}, /* Q ==11 : 69-75% */ + {{ 976,185}, {2131,150}}, /* Q ==12 : 75-81% */ + {{1180,186}, {2070,175}}, /* Q ==13 : 81-87% */ + {{1377,185}, {1731,202}}, /* Q ==14 : 87-93% */ + {{1412,185}, {1695,202}}, /* Q ==15 : 93-99% */ +}; +#endif + +/** HUF_selectDecoder() : + * Tells which decoder is likely to decode faster, + * based on a set of pre-computed metrics. + * @return : 0==HUF_decompress4X1, 1==HUF_decompress4X2 . + * Assumption : 0 < dstSize <= 128 KB */ +U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize) +{ + assert(dstSize > 0); + assert(dstSize <= 128*1024); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)dstSize; + (void)cSrcSize; + return 0; +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)dstSize; + (void)cSrcSize; + return 1; +#else + /* decoder timing evaluation */ + { U32 const Q = (cSrcSize >= dstSize) ? 15 : (U32)(cSrcSize * 16 / dstSize); /* Q < 16 */ + U32 const D256 = (U32)(dstSize >> 8); + U32 const DTime0 = algoTime[Q][0].tableTime + (algoTime[Q][0].decode256Time * D256); + U32 DTime1 = algoTime[Q][1].tableTime + (algoTime[Q][1].decode256Time * D256); + DTime1 += DTime1 >> 5; /* small advantage to algorithm using less memory, to reduce cache eviction */ + return DTime1 < DTime0; + } +#endif +} + +size_t HUF_decompress1X_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + void* workSpace, size_t wkspSize, int flags) +{ + /* validation checks */ + if (dstSize == 0) return ERROR(dstSize_tooSmall); + if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */ + if (cSrcSize == dstSize) { ZSTD_memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */ + if (cSrcSize == 1) { ZSTD_memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */ + + { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)algoNb; + assert(algoNb == 0); + return HUF_decompress1X1_DCtx_wksp(dctx, dst, dstSize, cSrc, + cSrcSize, workSpace, wkspSize, flags); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)algoNb; + assert(algoNb == 1); + return HUF_decompress1X2_DCtx_wksp(dctx, dst, dstSize, cSrc, + cSrcSize, workSpace, wkspSize, flags); +#else + return algoNb ? HUF_decompress1X2_DCtx_wksp(dctx, dst, dstSize, cSrc, + cSrcSize, workSpace, wkspSize, flags): + HUF_decompress1X1_DCtx_wksp(dctx, dst, dstSize, cSrc, + cSrcSize, workSpace, wkspSize, flags); +#endif + } +} + + +size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int flags) +{ + DTableDesc const dtd = HUF_getDTableDesc(DTable); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)dtd; + assert(dtd.tableType == 0); + return HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)dtd; + assert(dtd.tableType == 1); + return HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags); +#else + return dtd.tableType ? HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags) : + HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags); +#endif +} + +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int flags) +{ + const BYTE* ip = (const BYTE*) cSrc; + + size_t const hSize = HUF_readDTableX1_wksp(dctx, cSrc, cSrcSize, workSpace, wkspSize, flags); + if (HUF_isError(hSize)) return hSize; + if (hSize >= cSrcSize) return ERROR(srcSize_wrong); + ip += hSize; cSrcSize -= hSize; + + return HUF_decompress1X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, flags); +} +#endif + +size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int flags) +{ + DTableDesc const dtd = HUF_getDTableDesc(DTable); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)dtd; + assert(dtd.tableType == 0); + return HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)dtd; + assert(dtd.tableType == 1); + return HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags); +#else + return dtd.tableType ? HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags) : + HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags); +#endif +} + +size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int flags) +{ + /* validation checks */ + if (dstSize == 0) return ERROR(dstSize_tooSmall); + if (cSrcSize == 0) return ERROR(corruption_detected); + + { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)algoNb; + assert(algoNb == 0); + return HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, flags); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)algoNb; + assert(algoNb == 1); + return HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, flags); +#else + return algoNb ? HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, flags) : + HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, flags); +#endif + } +} diff --git a/lib/zstd/lib/decompress/zstd_ddict.c b/lib/zstd/lib/decompress/zstd_ddict.c new file mode 100644 index 0000000..309ec0d --- /dev/null +++ b/lib/zstd/lib/decompress/zstd_ddict.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +/* zstd_ddict.c : + * concentrates all logic that needs to know the internals of ZSTD_DDict object */ + +/*-******************************************************* +* Dependencies +*********************************************************/ +#include "../common/allocations.h" /* ZSTD_customMalloc, ZSTD_customFree */ +#include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */ +#include "../common/cpu.h" /* bmi2 */ +#include "../common/mem.h" /* low level memory routines */ +#define FSE_STATIC_LINKING_ONLY +#include "../common/fse.h" +#include "../common/huf.h" +#include "zstd_decompress_internal.h" +#include "zstd_ddict.h" + +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) +# include "../legacy/zstd_legacy.h" +#endif + + + +/*-******************************************************* +* Types +*********************************************************/ +struct ZSTD_DDict_s { + void* dictBuffer; + const void* dictContent; + size_t dictSize; + ZSTD_entropyDTables_t entropy; + U32 dictID; + U32 entropyPresent; + ZSTD_customMem cMem; +}; /* typedef'd to ZSTD_DDict within "zstd.h" */ + +const void* ZSTD_DDict_dictContent(const ZSTD_DDict* ddict) +{ + assert(ddict != NULL); + return ddict->dictContent; +} + +size_t ZSTD_DDict_dictSize(const ZSTD_DDict* ddict) +{ + assert(ddict != NULL); + return ddict->dictSize; +} + +void ZSTD_copyDDictParameters(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict) +{ + DEBUGLOG(4, "ZSTD_copyDDictParameters"); + assert(dctx != NULL); + assert(ddict != NULL); + dctx->dictID = ddict->dictID; + dctx->prefixStart = ddict->dictContent; + dctx->virtualStart = ddict->dictContent; + dctx->dictEnd = (const BYTE*)ddict->dictContent + ddict->dictSize; + dctx->previousDstEnd = dctx->dictEnd; +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + dctx->dictContentBeginForFuzzing = dctx->prefixStart; + dctx->dictContentEndForFuzzing = dctx->previousDstEnd; +#endif + if (ddict->entropyPresent) { + dctx->litEntropy = 1; + dctx->fseEntropy = 1; + dctx->LLTptr = ddict->entropy.LLTable; + dctx->MLTptr = ddict->entropy.MLTable; + dctx->OFTptr = ddict->entropy.OFTable; + dctx->HUFptr = ddict->entropy.hufTable; + dctx->entropy.rep[0] = ddict->entropy.rep[0]; + dctx->entropy.rep[1] = ddict->entropy.rep[1]; + dctx->entropy.rep[2] = ddict->entropy.rep[2]; + } else { + dctx->litEntropy = 0; + dctx->fseEntropy = 0; + } +} + + +static size_t +ZSTD_loadEntropy_intoDDict(ZSTD_DDict* ddict, + ZSTD_dictContentType_e dictContentType) +{ + ddict->dictID = 0; + ddict->entropyPresent = 0; + if (dictContentType == ZSTD_dct_rawContent) return 0; + + if (ddict->dictSize < 8) { + if (dictContentType == ZSTD_dct_fullDict) + return ERROR(dictionary_corrupted); /* only accept specified dictionaries */ + return 0; /* pure content mode */ + } + { U32 const magic = MEM_readLE32(ddict->dictContent); + if (magic != ZSTD_MAGIC_DICTIONARY) { + if (dictContentType == ZSTD_dct_fullDict) + return ERROR(dictionary_corrupted); /* only accept specified dictionaries */ + return 0; /* pure content mode */ + } + } + ddict->dictID = MEM_readLE32((const char*)ddict->dictContent + ZSTD_FRAMEIDSIZE); + + /* load entropy tables */ + RETURN_ERROR_IF(ZSTD_isError(ZSTD_loadDEntropy( + &ddict->entropy, ddict->dictContent, ddict->dictSize)), + dictionary_corrupted, ""); + ddict->entropyPresent = 1; + return 0; +} + + +static size_t ZSTD_initDDict_internal(ZSTD_DDict* ddict, + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType) +{ + if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dict) || (!dictSize)) { + ddict->dictBuffer = NULL; + ddict->dictContent = dict; + if (!dict) dictSize = 0; + } else { + void* const internalBuffer = ZSTD_customMalloc(dictSize, ddict->cMem); + ddict->dictBuffer = internalBuffer; + ddict->dictContent = internalBuffer; + if (!internalBuffer) return ERROR(memory_allocation); + ZSTD_memcpy(internalBuffer, dict, dictSize); + } + ddict->dictSize = dictSize; + ddict->entropy.hufTable[0] = (HUF_DTable)((ZSTD_HUFFDTABLE_CAPACITY_LOG)*0x1000001); /* cover both little and big endian */ + + /* parse dictionary content */ + FORWARD_IF_ERROR( ZSTD_loadEntropy_intoDDict(ddict, dictContentType) , ""); + + return 0; +} + +ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType, + ZSTD_customMem customMem) +{ + if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; + + { ZSTD_DDict* const ddict = (ZSTD_DDict*) ZSTD_customMalloc(sizeof(ZSTD_DDict), customMem); + if (ddict == NULL) return NULL; + ddict->cMem = customMem; + { size_t const initResult = ZSTD_initDDict_internal(ddict, + dict, dictSize, + dictLoadMethod, dictContentType); + if (ZSTD_isError(initResult)) { + ZSTD_freeDDict(ddict); + return NULL; + } } + return ddict; + } +} + +/*! ZSTD_createDDict() : +* Create a digested dictionary, to start decompression without startup delay. +* `dict` content is copied inside DDict. +* Consequently, `dict` can be released after `ZSTD_DDict` creation */ +ZSTD_DDict* ZSTD_createDDict(const void* dict, size_t dictSize) +{ + ZSTD_customMem const allocator = { NULL, NULL, NULL }; + return ZSTD_createDDict_advanced(dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto, allocator); +} + +/*! ZSTD_createDDict_byReference() : + * Create a digested dictionary, to start decompression without startup delay. + * Dictionary content is simply referenced, it will be accessed during decompression. + * Warning : dictBuffer must outlive DDict (DDict must be freed before dictBuffer) */ +ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize) +{ + ZSTD_customMem const allocator = { NULL, NULL, NULL }; + return ZSTD_createDDict_advanced(dictBuffer, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto, allocator); +} + + +const ZSTD_DDict* ZSTD_initStaticDDict( + void* sBuffer, size_t sBufferSize, + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType) +{ + size_t const neededSpace = sizeof(ZSTD_DDict) + + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize); + ZSTD_DDict* const ddict = (ZSTD_DDict*)sBuffer; + assert(sBuffer != NULL); + assert(dict != NULL); + if ((size_t)sBuffer & 7) return NULL; /* 8-aligned */ + if (sBufferSize < neededSpace) return NULL; + if (dictLoadMethod == ZSTD_dlm_byCopy) { + ZSTD_memcpy(ddict+1, dict, dictSize); /* local copy */ + dict = ddict+1; + } + if (ZSTD_isError( ZSTD_initDDict_internal(ddict, + dict, dictSize, + ZSTD_dlm_byRef, dictContentType) )) + return NULL; + return ddict; +} + + +size_t ZSTD_freeDDict(ZSTD_DDict* ddict) +{ + if (ddict==NULL) return 0; /* support free on NULL */ + { ZSTD_customMem const cMem = ddict->cMem; + ZSTD_customFree(ddict->dictBuffer, cMem); + ZSTD_customFree(ddict, cMem); + return 0; + } +} + +/*! ZSTD_estimateDDictSize() : + * Estimate amount of memory that will be needed to create a dictionary for decompression. + * Note : dictionary created by reference using ZSTD_dlm_byRef are smaller */ +size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod) +{ + return sizeof(ZSTD_DDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize); +} + +size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict) +{ + if (ddict==NULL) return 0; /* support sizeof on NULL */ + return sizeof(*ddict) + (ddict->dictBuffer ? ddict->dictSize : 0) ; +} + +/*! ZSTD_getDictID_fromDDict() : + * Provides the dictID of the dictionary loaded into `ddict`. + * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty. + * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */ +unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict) +{ + if (ddict==NULL) return 0; + return ddict->dictID; +} diff --git a/lib/zstd/lib/decompress/zstd_ddict.h b/lib/zstd/lib/decompress/zstd_ddict.h new file mode 100644 index 0000000..c4ca887 --- /dev/null +++ b/lib/zstd/lib/decompress/zstd_ddict.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + + +#ifndef ZSTD_DDICT_H +#define ZSTD_DDICT_H + +/*-******************************************************* + * Dependencies + *********************************************************/ +#include "../common/zstd_deps.h" /* size_t */ +#include "../zstd.h" /* ZSTD_DDict, and several public functions */ + + +/*-******************************************************* + * Interface + *********************************************************/ + +/* note: several prototypes are already published in `zstd.h` : + * ZSTD_createDDict() + * ZSTD_createDDict_byReference() + * ZSTD_createDDict_advanced() + * ZSTD_freeDDict() + * ZSTD_initStaticDDict() + * ZSTD_sizeof_DDict() + * ZSTD_estimateDDictSize() + * ZSTD_getDictID_fromDict() + */ + +const void* ZSTD_DDict_dictContent(const ZSTD_DDict* ddict); +size_t ZSTD_DDict_dictSize(const ZSTD_DDict* ddict); + +void ZSTD_copyDDictParameters(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); + + + +#endif /* ZSTD_DDICT_H */ diff --git a/lib/zstd/lib/decompress/zstd_decompress.c b/lib/zstd/lib/decompress/zstd_decompress.c new file mode 100644 index 0000000..7bc2713 --- /dev/null +++ b/lib/zstd/lib/decompress/zstd_decompress.c @@ -0,0 +1,2355 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + + +/* *************************************************************** +* Tuning parameters +*****************************************************************/ +/*! + * HEAPMODE : + * Select how default decompression function ZSTD_decompress() allocates its context, + * on stack (0), or into heap (1, default; requires malloc()). + * Note that functions with explicit context such as ZSTD_decompressDCtx() are unaffected. + */ +#ifndef ZSTD_HEAPMODE +# define ZSTD_HEAPMODE 1 +#endif + +/*! +* LEGACY_SUPPORT : +* if set to 1+, ZSTD_decompress() can decode older formats (v0.1+) +*/ +#ifndef ZSTD_LEGACY_SUPPORT +# define ZSTD_LEGACY_SUPPORT 0 +#endif + +/*! + * MAXWINDOWSIZE_DEFAULT : + * maximum window size accepted by DStream __by default__. + * Frames requiring more memory will be rejected. + * It's possible to set a different limit using ZSTD_DCtx_setMaxWindowSize(). + */ +#ifndef ZSTD_MAXWINDOWSIZE_DEFAULT +# define ZSTD_MAXWINDOWSIZE_DEFAULT (((U32)1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT) + 1) +#endif + +/*! + * NO_FORWARD_PROGRESS_MAX : + * maximum allowed nb of calls to ZSTD_decompressStream() + * without any forward progress + * (defined as: no byte read from input, and no byte flushed to output) + * before triggering an error. + */ +#ifndef ZSTD_NO_FORWARD_PROGRESS_MAX +# define ZSTD_NO_FORWARD_PROGRESS_MAX 16 +#endif + + +/*-******************************************************* +* Dependencies +*********************************************************/ +#include "../common/allocations.h" /* ZSTD_customMalloc, ZSTD_customCalloc, ZSTD_customFree */ +#include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */ +#include "../common/mem.h" /* low level memory routines */ +#define FSE_STATIC_LINKING_ONLY +#include "../common/fse.h" +#include "../common/huf.h" +#include "../common/xxhash.h" /* XXH64_reset, XXH64_update, XXH64_digest, XXH64 */ +#include "../common/zstd_internal.h" /* blockProperties_t */ +#include "zstd_decompress_internal.h" /* ZSTD_DCtx */ +#include "zstd_ddict.h" /* ZSTD_DDictDictContent */ +#include "zstd_decompress_block.h" /* ZSTD_decompressBlock_internal */ +#include "../common/bits.h" /* ZSTD_highbit32 */ + +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) +# include "../legacy/zstd_legacy.h" +#endif + + + +/************************************* + * Multiple DDicts Hashset internals * + *************************************/ + +#define DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT 4 +#define DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT 3 /* These two constants represent SIZE_MULT/COUNT_MULT load factor without using a float. + * Currently, that means a 0.75 load factor. + * So, if count * COUNT_MULT / size * SIZE_MULT != 0, then we've exceeded + * the load factor of the ddict hash set. + */ + +#define DDICT_HASHSET_TABLE_BASE_SIZE 64 +#define DDICT_HASHSET_RESIZE_FACTOR 2 + +/* Hash function to determine starting position of dict insertion within the table + * Returns an index between [0, hashSet->ddictPtrTableSize] + */ +static size_t ZSTD_DDictHashSet_getIndex(const ZSTD_DDictHashSet* hashSet, U32 dictID) { + const U64 hash = XXH64(&dictID, sizeof(U32), 0); + /* DDict ptr table size is a multiple of 2, use size - 1 as mask to get index within [0, hashSet->ddictPtrTableSize) */ + return hash & (hashSet->ddictPtrTableSize - 1); +} + +/* Adds DDict to a hashset without resizing it. + * If inserting a DDict with a dictID that already exists in the set, replaces the one in the set. + * Returns 0 if successful, or a zstd error code if something went wrong. + */ +static size_t ZSTD_DDictHashSet_emplaceDDict(ZSTD_DDictHashSet* hashSet, const ZSTD_DDict* ddict) { + const U32 dictID = ZSTD_getDictID_fromDDict(ddict); + size_t idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID); + const size_t idxRangeMask = hashSet->ddictPtrTableSize - 1; + RETURN_ERROR_IF(hashSet->ddictPtrCount == hashSet->ddictPtrTableSize, GENERIC, "Hash set is full!"); + DEBUGLOG(4, "Hashed index: for dictID: %u is %zu", dictID, idx); + while (hashSet->ddictPtrTable[idx] != NULL) { + /* Replace existing ddict if inserting ddict with same dictID */ + if (ZSTD_getDictID_fromDDict(hashSet->ddictPtrTable[idx]) == dictID) { + DEBUGLOG(4, "DictID already exists, replacing rather than adding"); + hashSet->ddictPtrTable[idx] = ddict; + return 0; + } + idx &= idxRangeMask; + idx++; + } + DEBUGLOG(4, "Final idx after probing for dictID %u is: %zu", dictID, idx); + hashSet->ddictPtrTable[idx] = ddict; + hashSet->ddictPtrCount++; + return 0; +} + +/* Expands hash table by factor of DDICT_HASHSET_RESIZE_FACTOR and + * rehashes all values, allocates new table, frees old table. + * Returns 0 on success, otherwise a zstd error code. + */ +static size_t ZSTD_DDictHashSet_expand(ZSTD_DDictHashSet* hashSet, ZSTD_customMem customMem) { + size_t newTableSize = hashSet->ddictPtrTableSize * DDICT_HASHSET_RESIZE_FACTOR; + const ZSTD_DDict** newTable = (const ZSTD_DDict**)ZSTD_customCalloc(sizeof(ZSTD_DDict*) * newTableSize, customMem); + const ZSTD_DDict** oldTable = hashSet->ddictPtrTable; + size_t oldTableSize = hashSet->ddictPtrTableSize; + size_t i; + + DEBUGLOG(4, "Expanding DDict hash table! Old size: %zu new size: %zu", oldTableSize, newTableSize); + RETURN_ERROR_IF(!newTable, memory_allocation, "Expanded hashset allocation failed!"); + hashSet->ddictPtrTable = newTable; + hashSet->ddictPtrTableSize = newTableSize; + hashSet->ddictPtrCount = 0; + for (i = 0; i < oldTableSize; ++i) { + if (oldTable[i] != NULL) { + FORWARD_IF_ERROR(ZSTD_DDictHashSet_emplaceDDict(hashSet, oldTable[i]), ""); + } + } + ZSTD_customFree((void*)oldTable, customMem); + DEBUGLOG(4, "Finished re-hash"); + return 0; +} + +/* Fetches a DDict with the given dictID + * Returns the ZSTD_DDict* with the requested dictID. If it doesn't exist, then returns NULL. + */ +static const ZSTD_DDict* ZSTD_DDictHashSet_getDDict(ZSTD_DDictHashSet* hashSet, U32 dictID) { + size_t idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID); + const size_t idxRangeMask = hashSet->ddictPtrTableSize - 1; + DEBUGLOG(4, "Hashed index: for dictID: %u is %zu", dictID, idx); + for (;;) { + size_t currDictID = ZSTD_getDictID_fromDDict(hashSet->ddictPtrTable[idx]); + if (currDictID == dictID || currDictID == 0) { + /* currDictID == 0 implies a NULL ddict entry */ + break; + } else { + idx &= idxRangeMask; /* Goes to start of table when we reach the end */ + idx++; + } + } + DEBUGLOG(4, "Final idx after probing for dictID %u is: %zu", dictID, idx); + return hashSet->ddictPtrTable[idx]; +} + +/* Allocates space for and returns a ddict hash set + * The hash set's ZSTD_DDict* table has all values automatically set to NULL to begin with. + * Returns NULL if allocation failed. + */ +static ZSTD_DDictHashSet* ZSTD_createDDictHashSet(ZSTD_customMem customMem) { + ZSTD_DDictHashSet* ret = (ZSTD_DDictHashSet*)ZSTD_customMalloc(sizeof(ZSTD_DDictHashSet), customMem); + DEBUGLOG(4, "Allocating new hash set"); + if (!ret) + return NULL; + ret->ddictPtrTable = (const ZSTD_DDict**)ZSTD_customCalloc(DDICT_HASHSET_TABLE_BASE_SIZE * sizeof(ZSTD_DDict*), customMem); + if (!ret->ddictPtrTable) { + ZSTD_customFree(ret, customMem); + return NULL; + } + ret->ddictPtrTableSize = DDICT_HASHSET_TABLE_BASE_SIZE; + ret->ddictPtrCount = 0; + return ret; +} + +/* Frees the table of ZSTD_DDict* within a hashset, then frees the hashset itself. + * Note: The ZSTD_DDict* within the table are NOT freed. + */ +static void ZSTD_freeDDictHashSet(ZSTD_DDictHashSet* hashSet, ZSTD_customMem customMem) { + DEBUGLOG(4, "Freeing ddict hash set"); + if (hashSet && hashSet->ddictPtrTable) { + ZSTD_customFree((void*)hashSet->ddictPtrTable, customMem); + } + if (hashSet) { + ZSTD_customFree(hashSet, customMem); + } +} + +/* Public function: Adds a DDict into the ZSTD_DDictHashSet, possibly triggering a resize of the hash set. + * Returns 0 on success, or a ZSTD error. + */ +static size_t ZSTD_DDictHashSet_addDDict(ZSTD_DDictHashSet* hashSet, const ZSTD_DDict* ddict, ZSTD_customMem customMem) { + DEBUGLOG(4, "Adding dict ID: %u to hashset with - Count: %zu Tablesize: %zu", ZSTD_getDictID_fromDDict(ddict), hashSet->ddictPtrCount, hashSet->ddictPtrTableSize); + if (hashSet->ddictPtrCount * DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT / hashSet->ddictPtrTableSize * DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT != 0) { + FORWARD_IF_ERROR(ZSTD_DDictHashSet_expand(hashSet, customMem), ""); + } + FORWARD_IF_ERROR(ZSTD_DDictHashSet_emplaceDDict(hashSet, ddict), ""); + return 0; +} + +/*-************************************************************* +* Context management +***************************************************************/ +size_t ZSTD_sizeof_DCtx (const ZSTD_DCtx* dctx) +{ + if (dctx==NULL) return 0; /* support sizeof NULL */ + return sizeof(*dctx) + + ZSTD_sizeof_DDict(dctx->ddictLocal) + + dctx->inBuffSize + dctx->outBuffSize; +} + +size_t ZSTD_estimateDCtxSize(void) { return sizeof(ZSTD_DCtx); } + + +static size_t ZSTD_startingInputLength(ZSTD_format_e format) +{ + size_t const startingInputLength = ZSTD_FRAMEHEADERSIZE_PREFIX(format); + /* only supports formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless */ + assert( (format == ZSTD_f_zstd1) || (format == ZSTD_f_zstd1_magicless) ); + return startingInputLength; +} + +static void ZSTD_DCtx_resetParameters(ZSTD_DCtx* dctx) +{ + assert(dctx->streamStage == zdss_init); + dctx->format = ZSTD_f_zstd1; + dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT; + dctx->outBufferMode = ZSTD_bm_buffered; + dctx->forceIgnoreChecksum = ZSTD_d_validateChecksum; + dctx->refMultipleDDicts = ZSTD_rmd_refSingleDDict; + dctx->disableHufAsm = 0; +} + +static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx) +{ + dctx->staticSize = 0; + dctx->ddict = NULL; + dctx->ddictLocal = NULL; + dctx->dictEnd = NULL; + dctx->ddictIsCold = 0; + dctx->dictUses = ZSTD_dont_use; + dctx->inBuff = NULL; + dctx->inBuffSize = 0; + dctx->outBuffSize = 0; + dctx->streamStage = zdss_init; +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) + dctx->legacyContext = NULL; + dctx->previousLegacyVersion = 0; +#endif + dctx->noForwardProgress = 0; + dctx->oversizedDuration = 0; +#if DYNAMIC_BMI2 + dctx->bmi2 = ZSTD_cpuSupportsBmi2(); +#endif + dctx->ddictSet = NULL; + ZSTD_DCtx_resetParameters(dctx); +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + dctx->dictContentEndForFuzzing = NULL; +#endif +} + +ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize) +{ + ZSTD_DCtx* const dctx = (ZSTD_DCtx*) workspace; + + if ((size_t)workspace & 7) return NULL; /* 8-aligned */ + if (workspaceSize < sizeof(ZSTD_DCtx)) return NULL; /* minimum size */ + + ZSTD_initDCtx_internal(dctx); + dctx->staticSize = workspaceSize; + dctx->inBuff = (char*)(dctx+1); + return dctx; +} + +static ZSTD_DCtx* ZSTD_createDCtx_internal(ZSTD_customMem customMem) { + if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; + + { ZSTD_DCtx* const dctx = (ZSTD_DCtx*)ZSTD_customMalloc(sizeof(*dctx), customMem); + if (!dctx) return NULL; + dctx->customMem = customMem; + ZSTD_initDCtx_internal(dctx); + return dctx; + } +} + +ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem) +{ + return ZSTD_createDCtx_internal(customMem); +} + +ZSTD_DCtx* ZSTD_createDCtx(void) +{ + DEBUGLOG(3, "ZSTD_createDCtx"); + return ZSTD_createDCtx_internal(ZSTD_defaultCMem); +} + +static void ZSTD_clearDict(ZSTD_DCtx* dctx) +{ + ZSTD_freeDDict(dctx->ddictLocal); + dctx->ddictLocal = NULL; + dctx->ddict = NULL; + dctx->dictUses = ZSTD_dont_use; +} + +size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx) +{ + if (dctx==NULL) return 0; /* support free on NULL */ + RETURN_ERROR_IF(dctx->staticSize, memory_allocation, "not compatible with static DCtx"); + { ZSTD_customMem const cMem = dctx->customMem; + ZSTD_clearDict(dctx); + ZSTD_customFree(dctx->inBuff, cMem); + dctx->inBuff = NULL; +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) + if (dctx->legacyContext) + ZSTD_freeLegacyStreamContext(dctx->legacyContext, dctx->previousLegacyVersion); +#endif + if (dctx->ddictSet) { + ZSTD_freeDDictHashSet(dctx->ddictSet, cMem); + dctx->ddictSet = NULL; + } + ZSTD_customFree(dctx, cMem); + return 0; + } +} + +/* no longer useful */ +void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx) +{ + size_t const toCopy = (size_t)((char*)(&dstDCtx->inBuff) - (char*)dstDCtx); + ZSTD_memcpy(dstDCtx, srcDCtx, toCopy); /* no need to copy workspace */ +} + +/* Given a dctx with a digested frame params, re-selects the correct ZSTD_DDict based on + * the requested dict ID from the frame. If there exists a reference to the correct ZSTD_DDict, then + * accordingly sets the ddict to be used to decompress the frame. + * + * If no DDict is found, then no action is taken, and the ZSTD_DCtx::ddict remains as-is. + * + * ZSTD_d_refMultipleDDicts must be enabled for this function to be called. + */ +static void ZSTD_DCtx_selectFrameDDict(ZSTD_DCtx* dctx) { + assert(dctx->refMultipleDDicts && dctx->ddictSet); + DEBUGLOG(4, "Adjusting DDict based on requested dict ID from frame"); + if (dctx->ddict) { + const ZSTD_DDict* frameDDict = ZSTD_DDictHashSet_getDDict(dctx->ddictSet, dctx->fParams.dictID); + if (frameDDict) { + DEBUGLOG(4, "DDict found!"); + ZSTD_clearDict(dctx); + dctx->dictID = dctx->fParams.dictID; + dctx->ddict = frameDDict; + dctx->dictUses = ZSTD_use_indefinitely; + } + } +} + + +/*-************************************************************* + * Frame header decoding + ***************************************************************/ + +/*! ZSTD_isFrame() : + * Tells if the content of `buffer` starts with a valid Frame Identifier. + * Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0. + * Note 2 : Legacy Frame Identifiers are considered valid only if Legacy Support is enabled. + * Note 3 : Skippable Frame Identifiers are considered valid. */ +unsigned ZSTD_isFrame(const void* buffer, size_t size) +{ + if (size < ZSTD_FRAMEIDSIZE) return 0; + { U32 const magic = MEM_readLE32(buffer); + if (magic == ZSTD_MAGICNUMBER) return 1; + if ((magic & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) return 1; + } +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) + if (ZSTD_isLegacy(buffer, size)) return 1; +#endif + return 0; +} + +/*! ZSTD_isSkippableFrame() : + * Tells if the content of `buffer` starts with a valid Frame Identifier for a skippable frame. + * Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0. + */ +unsigned ZSTD_isSkippableFrame(const void* buffer, size_t size) +{ + if (size < ZSTD_FRAMEIDSIZE) return 0; + { U32 const magic = MEM_readLE32(buffer); + if ((magic & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) return 1; + } + return 0; +} + +/** ZSTD_frameHeaderSize_internal() : + * srcSize must be large enough to reach header size fields. + * note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless. + * @return : size of the Frame Header + * or an error code, which can be tested with ZSTD_isError() */ +static size_t ZSTD_frameHeaderSize_internal(const void* src, size_t srcSize, ZSTD_format_e format) +{ + size_t const minInputSize = ZSTD_startingInputLength(format); + RETURN_ERROR_IF(srcSize < minInputSize, srcSize_wrong, ""); + + { BYTE const fhd = ((const BYTE*)src)[minInputSize-1]; + U32 const dictID= fhd & 3; + U32 const singleSegment = (fhd >> 5) & 1; + U32 const fcsId = fhd >> 6; + return minInputSize + !singleSegment + + ZSTD_did_fieldSize[dictID] + ZSTD_fcs_fieldSize[fcsId] + + (singleSegment && !fcsId); + } +} + +/** ZSTD_frameHeaderSize() : + * srcSize must be >= ZSTD_frameHeaderSize_prefix. + * @return : size of the Frame Header, + * or an error code (if srcSize is too small) */ +size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize) +{ + return ZSTD_frameHeaderSize_internal(src, srcSize, ZSTD_f_zstd1); +} + + +/** ZSTD_getFrameHeader_advanced() : + * decode Frame Header, or require larger `srcSize`. + * note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless + * @return : 0, `zfhPtr` is correctly filled, + * >0, `srcSize` is too small, value is wanted `srcSize` amount, +** or an error code, which can be tested using ZSTD_isError() */ +size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format) +{ + const BYTE* ip = (const BYTE*)src; + size_t const minInputSize = ZSTD_startingInputLength(format); + + DEBUGLOG(5, "ZSTD_getFrameHeader_advanced: minInputSize = %zu, srcSize = %zu", minInputSize, srcSize); + + if (srcSize > 0) { + /* note : technically could be considered an assert(), since it's an invalid entry */ + RETURN_ERROR_IF(src==NULL, GENERIC, "invalid parameter : src==NULL, but srcSize>0"); + } + if (srcSize < minInputSize) { + if (srcSize > 0 && format != ZSTD_f_zstd1_magicless) { + /* when receiving less than @minInputSize bytes, + * control these bytes at least correspond to a supported magic number + * in order to error out early if they don't. + **/ + size_t const toCopy = MIN(4, srcSize); + unsigned char hbuf[4]; MEM_writeLE32(hbuf, ZSTD_MAGICNUMBER); + assert(src != NULL); + ZSTD_memcpy(hbuf, src, toCopy); + if ( MEM_readLE32(hbuf) != ZSTD_MAGICNUMBER ) { + /* not a zstd frame : let's check if it's a skippable frame */ + MEM_writeLE32(hbuf, ZSTD_MAGIC_SKIPPABLE_START); + ZSTD_memcpy(hbuf, src, toCopy); + if ((MEM_readLE32(hbuf) & ZSTD_MAGIC_SKIPPABLE_MASK) != ZSTD_MAGIC_SKIPPABLE_START) { + RETURN_ERROR(prefix_unknown, + "first bytes don't correspond to any supported magic number"); + } } } + return minInputSize; + } + + ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr)); /* not strictly necessary, but static analyzers may not understand that zfhPtr will be read only if return value is zero, since they are 2 different signals */ + if ( (format != ZSTD_f_zstd1_magicless) + && (MEM_readLE32(src) != ZSTD_MAGICNUMBER) ) { + if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { + /* skippable frame */ + if (srcSize < ZSTD_SKIPPABLEHEADERSIZE) + return ZSTD_SKIPPABLEHEADERSIZE; /* magic number + frame length */ + ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr)); + zfhPtr->frameContentSize = MEM_readLE32((const char *)src + ZSTD_FRAMEIDSIZE); + zfhPtr->frameType = ZSTD_skippableFrame; + return 0; + } + RETURN_ERROR(prefix_unknown, ""); + } + + /* ensure there is enough `srcSize` to fully read/decode frame header */ + { size_t const fhsize = ZSTD_frameHeaderSize_internal(src, srcSize, format); + if (srcSize < fhsize) return fhsize; + zfhPtr->headerSize = (U32)fhsize; + } + + { BYTE const fhdByte = ip[minInputSize-1]; + size_t pos = minInputSize; + U32 const dictIDSizeCode = fhdByte&3; + U32 const checksumFlag = (fhdByte>>2)&1; + U32 const singleSegment = (fhdByte>>5)&1; + U32 const fcsID = fhdByte>>6; + U64 windowSize = 0; + U32 dictID = 0; + U64 frameContentSize = ZSTD_CONTENTSIZE_UNKNOWN; + RETURN_ERROR_IF((fhdByte & 0x08) != 0, frameParameter_unsupported, + "reserved bits, must be zero"); + + if (!singleSegment) { + BYTE const wlByte = ip[pos++]; + U32 const windowLog = (wlByte >> 3) + ZSTD_WINDOWLOG_ABSOLUTEMIN; + RETURN_ERROR_IF(windowLog > ZSTD_WINDOWLOG_MAX, frameParameter_windowTooLarge, ""); + windowSize = (1ULL << windowLog); + windowSize += (windowSize >> 3) * (wlByte&7); + } + switch(dictIDSizeCode) + { + default: + assert(0); /* impossible */ + ZSTD_FALLTHROUGH; + case 0 : break; + case 1 : dictID = ip[pos]; pos++; break; + case 2 : dictID = MEM_readLE16(ip+pos); pos+=2; break; + case 3 : dictID = MEM_readLE32(ip+pos); pos+=4; break; + } + switch(fcsID) + { + default: + assert(0); /* impossible */ + ZSTD_FALLTHROUGH; + case 0 : if (singleSegment) frameContentSize = ip[pos]; break; + case 1 : frameContentSize = MEM_readLE16(ip+pos)+256; break; + case 2 : frameContentSize = MEM_readLE32(ip+pos); break; + case 3 : frameContentSize = MEM_readLE64(ip+pos); break; + } + if (singleSegment) windowSize = frameContentSize; + + zfhPtr->frameType = ZSTD_frame; + zfhPtr->frameContentSize = frameContentSize; + zfhPtr->windowSize = windowSize; + zfhPtr->blockSizeMax = (unsigned) MIN(windowSize, ZSTD_BLOCKSIZE_MAX); + zfhPtr->dictID = dictID; + zfhPtr->checksumFlag = checksumFlag; + } + return 0; +} + +/** ZSTD_getFrameHeader() : + * decode Frame Header, or require larger `srcSize`. + * note : this function does not consume input, it only reads it. + * @return : 0, `zfhPtr` is correctly filled, + * >0, `srcSize` is too small, value is wanted `srcSize` amount, + * or an error code, which can be tested using ZSTD_isError() */ +size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize) +{ + return ZSTD_getFrameHeader_advanced(zfhPtr, src, srcSize, ZSTD_f_zstd1); +} + +/** ZSTD_getFrameContentSize() : + * compatible with legacy mode + * @return : decompressed size of the single frame pointed to be `src` if known, otherwise + * - ZSTD_CONTENTSIZE_UNKNOWN if the size cannot be determined + * - ZSTD_CONTENTSIZE_ERROR if an error occurred (e.g. invalid magic number, srcSize too small) */ +unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize) +{ +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) + if (ZSTD_isLegacy(src, srcSize)) { + unsigned long long const ret = ZSTD_getDecompressedSize_legacy(src, srcSize); + return ret == 0 ? ZSTD_CONTENTSIZE_UNKNOWN : ret; + } +#endif + { ZSTD_frameHeader zfh; + if (ZSTD_getFrameHeader(&zfh, src, srcSize) != 0) + return ZSTD_CONTENTSIZE_ERROR; + if (zfh.frameType == ZSTD_skippableFrame) { + return 0; + } else { + return zfh.frameContentSize; + } } +} + +static size_t readSkippableFrameSize(void const* src, size_t srcSize) +{ + size_t const skippableHeaderSize = ZSTD_SKIPPABLEHEADERSIZE; + U32 sizeU32; + + RETURN_ERROR_IF(srcSize < ZSTD_SKIPPABLEHEADERSIZE, srcSize_wrong, ""); + + sizeU32 = MEM_readLE32((BYTE const*)src + ZSTD_FRAMEIDSIZE); + RETURN_ERROR_IF((U32)(sizeU32 + ZSTD_SKIPPABLEHEADERSIZE) < sizeU32, + frameParameter_unsupported, ""); + { size_t const skippableSize = skippableHeaderSize + sizeU32; + RETURN_ERROR_IF(skippableSize > srcSize, srcSize_wrong, ""); + return skippableSize; + } +} + +/*! ZSTD_readSkippableFrame() : + * Retrieves content of a skippable frame, and writes it to dst buffer. + * + * The parameter magicVariant will receive the magicVariant that was supplied when the frame was written, + * i.e. magicNumber - ZSTD_MAGIC_SKIPPABLE_START. This can be NULL if the caller is not interested + * in the magicVariant. + * + * Returns an error if destination buffer is not large enough, or if this is not a valid skippable frame. + * + * @return : number of bytes written or a ZSTD error. + */ +size_t ZSTD_readSkippableFrame(void* dst, size_t dstCapacity, + unsigned* magicVariant, /* optional, can be NULL */ + const void* src, size_t srcSize) +{ + RETURN_ERROR_IF(srcSize < ZSTD_SKIPPABLEHEADERSIZE, srcSize_wrong, ""); + + { U32 const magicNumber = MEM_readLE32(src); + size_t skippableFrameSize = readSkippableFrameSize(src, srcSize); + size_t skippableContentSize = skippableFrameSize - ZSTD_SKIPPABLEHEADERSIZE; + + /* check input validity */ + RETURN_ERROR_IF(!ZSTD_isSkippableFrame(src, srcSize), frameParameter_unsupported, ""); + RETURN_ERROR_IF(skippableFrameSize < ZSTD_SKIPPABLEHEADERSIZE || skippableFrameSize > srcSize, srcSize_wrong, ""); + RETURN_ERROR_IF(skippableContentSize > dstCapacity, dstSize_tooSmall, ""); + + /* deliver payload */ + if (skippableContentSize > 0 && dst != NULL) + ZSTD_memcpy(dst, (const BYTE *)src + ZSTD_SKIPPABLEHEADERSIZE, skippableContentSize); + if (magicVariant != NULL) + *magicVariant = magicNumber - ZSTD_MAGIC_SKIPPABLE_START; + return skippableContentSize; + } +} + +/** ZSTD_findDecompressedSize() : + * `srcSize` must be the exact length of some number of ZSTD compressed and/or + * skippable frames + * note: compatible with legacy mode + * @return : decompressed size of the frames contained */ +unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize) +{ + unsigned long long totalDstSize = 0; + + while (srcSize >= ZSTD_startingInputLength(ZSTD_f_zstd1)) { + U32 const magicNumber = MEM_readLE32(src); + + if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { + size_t const skippableSize = readSkippableFrameSize(src, srcSize); + if (ZSTD_isError(skippableSize)) return ZSTD_CONTENTSIZE_ERROR; + assert(skippableSize <= srcSize); + + src = (const BYTE *)src + skippableSize; + srcSize -= skippableSize; + continue; + } + + { unsigned long long const fcs = ZSTD_getFrameContentSize(src, srcSize); + if (fcs >= ZSTD_CONTENTSIZE_ERROR) return fcs; + + if (totalDstSize + fcs < totalDstSize) + return ZSTD_CONTENTSIZE_ERROR; /* check for overflow */ + totalDstSize += fcs; + } + /* skip to next frame */ + { size_t const frameSrcSize = ZSTD_findFrameCompressedSize(src, srcSize); + if (ZSTD_isError(frameSrcSize)) return ZSTD_CONTENTSIZE_ERROR; + assert(frameSrcSize <= srcSize); + + src = (const BYTE *)src + frameSrcSize; + srcSize -= frameSrcSize; + } + } /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */ + + if (srcSize) return ZSTD_CONTENTSIZE_ERROR; + + return totalDstSize; +} + +/** ZSTD_getDecompressedSize() : + * compatible with legacy mode + * @return : decompressed size if known, 0 otherwise + note : 0 can mean any of the following : + - frame content is empty + - decompressed size field is not present in frame header + - frame header unknown / not supported + - frame header not complete (`srcSize` too small) */ +unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize) +{ + unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize); + ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_ERROR < ZSTD_CONTENTSIZE_UNKNOWN); + return (ret >= ZSTD_CONTENTSIZE_ERROR) ? 0 : ret; +} + + +/** ZSTD_decodeFrameHeader() : + * `headerSize` must be the size provided by ZSTD_frameHeaderSize(). + * If multiple DDict references are enabled, also will choose the correct DDict to use. + * @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */ +static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t headerSize) +{ + size_t const result = ZSTD_getFrameHeader_advanced(&(dctx->fParams), src, headerSize, dctx->format); + if (ZSTD_isError(result)) return result; /* invalid header */ + RETURN_ERROR_IF(result>0, srcSize_wrong, "headerSize too small"); + + /* Reference DDict requested by frame if dctx references multiple ddicts */ + if (dctx->refMultipleDDicts == ZSTD_rmd_refMultipleDDicts && dctx->ddictSet) { + ZSTD_DCtx_selectFrameDDict(dctx); + } + +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* Skip the dictID check in fuzzing mode, because it makes the search + * harder. + */ + RETURN_ERROR_IF(dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID), + dictionary_wrong, ""); +#endif + dctx->validateChecksum = (dctx->fParams.checksumFlag && !dctx->forceIgnoreChecksum) ? 1 : 0; + if (dctx->validateChecksum) XXH64_reset(&dctx->xxhState, 0); + dctx->processedCSize += headerSize; + return 0; +} + +static ZSTD_frameSizeInfo ZSTD_errorFrameSizeInfo(size_t ret) +{ + ZSTD_frameSizeInfo frameSizeInfo; + frameSizeInfo.compressedSize = ret; + frameSizeInfo.decompressedBound = ZSTD_CONTENTSIZE_ERROR; + return frameSizeInfo; +} + +static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize) +{ + ZSTD_frameSizeInfo frameSizeInfo; + ZSTD_memset(&frameSizeInfo, 0, sizeof(ZSTD_frameSizeInfo)); + +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) + if (ZSTD_isLegacy(src, srcSize)) + return ZSTD_findFrameSizeInfoLegacy(src, srcSize); +#endif + + if ((srcSize >= ZSTD_SKIPPABLEHEADERSIZE) + && (MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { + frameSizeInfo.compressedSize = readSkippableFrameSize(src, srcSize); + assert(ZSTD_isError(frameSizeInfo.compressedSize) || + frameSizeInfo.compressedSize <= srcSize); + return frameSizeInfo; + } else { + const BYTE* ip = (const BYTE*)src; + const BYTE* const ipstart = ip; + size_t remainingSize = srcSize; + size_t nbBlocks = 0; + ZSTD_frameHeader zfh; + + /* Extract Frame Header */ + { size_t const ret = ZSTD_getFrameHeader(&zfh, src, srcSize); + if (ZSTD_isError(ret)) + return ZSTD_errorFrameSizeInfo(ret); + if (ret > 0) + return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong)); + } + + ip += zfh.headerSize; + remainingSize -= zfh.headerSize; + + /* Iterate over each block */ + while (1) { + blockProperties_t blockProperties; + size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSize, &blockProperties); + if (ZSTD_isError(cBlockSize)) + return ZSTD_errorFrameSizeInfo(cBlockSize); + + if (ZSTD_blockHeaderSize + cBlockSize > remainingSize) + return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong)); + + ip += ZSTD_blockHeaderSize + cBlockSize; + remainingSize -= ZSTD_blockHeaderSize + cBlockSize; + nbBlocks++; + + if (blockProperties.lastBlock) break; + } + + /* Final frame content checksum */ + if (zfh.checksumFlag) { + if (remainingSize < 4) + return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong)); + ip += 4; + } + + frameSizeInfo.nbBlocks = nbBlocks; + frameSizeInfo.compressedSize = (size_t)(ip - ipstart); + frameSizeInfo.decompressedBound = (zfh.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) + ? zfh.frameContentSize + : (unsigned long long)nbBlocks * zfh.blockSizeMax; + return frameSizeInfo; + } +} + +/** ZSTD_findFrameCompressedSize() : + * compatible with legacy mode + * `src` must point to the start of a ZSTD frame, ZSTD legacy frame, or skippable frame + * `srcSize` must be at least as large as the frame contained + * @return : the compressed size of the frame starting at `src` */ +size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize) +{ + ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize); + return frameSizeInfo.compressedSize; +} + +/** ZSTD_decompressBound() : + * compatible with legacy mode + * `src` must point to the start of a ZSTD frame or a skippeable frame + * `srcSize` must be at least as large as the frame contained + * @return : the maximum decompressed size of the compressed source + */ +unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize) +{ + unsigned long long bound = 0; + /* Iterate over each frame */ + while (srcSize > 0) { + ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize); + size_t const compressedSize = frameSizeInfo.compressedSize; + unsigned long long const decompressedBound = frameSizeInfo.decompressedBound; + if (ZSTD_isError(compressedSize) || decompressedBound == ZSTD_CONTENTSIZE_ERROR) + return ZSTD_CONTENTSIZE_ERROR; + assert(srcSize >= compressedSize); + src = (const BYTE*)src + compressedSize; + srcSize -= compressedSize; + bound += decompressedBound; + } + return bound; +} + +size_t ZSTD_decompressionMargin(void const* src, size_t srcSize) +{ + size_t margin = 0; + unsigned maxBlockSize = 0; + + /* Iterate over each frame */ + while (srcSize > 0) { + ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize); + size_t const compressedSize = frameSizeInfo.compressedSize; + unsigned long long const decompressedBound = frameSizeInfo.decompressedBound; + ZSTD_frameHeader zfh; + + FORWARD_IF_ERROR(ZSTD_getFrameHeader(&zfh, src, srcSize), ""); + if (ZSTD_isError(compressedSize) || decompressedBound == ZSTD_CONTENTSIZE_ERROR) + return ERROR(corruption_detected); + + if (zfh.frameType == ZSTD_frame) { + /* Add the frame header to our margin */ + margin += zfh.headerSize; + /* Add the checksum to our margin */ + margin += zfh.checksumFlag ? 4 : 0; + /* Add 3 bytes per block */ + margin += 3 * frameSizeInfo.nbBlocks; + + /* Compute the max block size */ + maxBlockSize = MAX(maxBlockSize, zfh.blockSizeMax); + } else { + assert(zfh.frameType == ZSTD_skippableFrame); + /* Add the entire skippable frame size to our margin. */ + margin += compressedSize; + } + + assert(srcSize >= compressedSize); + src = (const BYTE*)src + compressedSize; + srcSize -= compressedSize; + } + + /* Add the max block size back to the margin. */ + margin += maxBlockSize; + + return margin; +} + +/*-************************************************************* + * Frame decoding + ***************************************************************/ + +/** ZSTD_insertBlock() : + * insert `src` block into `dctx` history. Useful to track uncompressed blocks. */ +size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize) +{ + DEBUGLOG(5, "ZSTD_insertBlock: %u bytes", (unsigned)blockSize); + ZSTD_checkContinuity(dctx, blockStart, blockSize); + dctx->previousDstEnd = (const char*)blockStart + blockSize; + return blockSize; +} + + +static size_t ZSTD_copyRawBlock(void* dst, size_t dstCapacity, + const void* src, size_t srcSize) +{ + DEBUGLOG(5, "ZSTD_copyRawBlock"); + RETURN_ERROR_IF(srcSize > dstCapacity, dstSize_tooSmall, ""); + if (dst == NULL) { + if (srcSize == 0) return 0; + RETURN_ERROR(dstBuffer_null, ""); + } + ZSTD_memmove(dst, src, srcSize); + return srcSize; +} + +static size_t ZSTD_setRleBlock(void* dst, size_t dstCapacity, + BYTE b, + size_t regenSize) +{ + RETURN_ERROR_IF(regenSize > dstCapacity, dstSize_tooSmall, ""); + if (dst == NULL) { + if (regenSize == 0) return 0; + RETURN_ERROR(dstBuffer_null, ""); + } + ZSTD_memset(dst, b, regenSize); + return regenSize; +} + +static void ZSTD_DCtx_trace_end(ZSTD_DCtx const* dctx, U64 uncompressedSize, U64 compressedSize, unsigned streaming) +{ +#if ZSTD_TRACE + if (dctx->traceCtx && ZSTD_trace_decompress_end != NULL) { + ZSTD_Trace trace; + ZSTD_memset(&trace, 0, sizeof(trace)); + trace.version = ZSTD_VERSION_NUMBER; + trace.streaming = streaming; + if (dctx->ddict) { + trace.dictionaryID = ZSTD_getDictID_fromDDict(dctx->ddict); + trace.dictionarySize = ZSTD_DDict_dictSize(dctx->ddict); + trace.dictionaryIsCold = dctx->ddictIsCold; + } + trace.uncompressedSize = (size_t)uncompressedSize; + trace.compressedSize = (size_t)compressedSize; + trace.dctx = dctx; + ZSTD_trace_decompress_end(dctx->traceCtx, &trace); + } +#else + (void)dctx; + (void)uncompressedSize; + (void)compressedSize; + (void)streaming; +#endif +} + + +/*! ZSTD_decompressFrame() : + * @dctx must be properly initialized + * will update *srcPtr and *srcSizePtr, + * to make *srcPtr progress by one frame. */ +static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void** srcPtr, size_t *srcSizePtr) +{ + const BYTE* const istart = (const BYTE*)(*srcPtr); + const BYTE* ip = istart; + BYTE* const ostart = (BYTE*)dst; + BYTE* const oend = dstCapacity != 0 ? ostart + dstCapacity : ostart; + BYTE* op = ostart; + size_t remainingSrcSize = *srcSizePtr; + + DEBUGLOG(4, "ZSTD_decompressFrame (srcSize:%i)", (int)*srcSizePtr); + + /* check */ + RETURN_ERROR_IF( + remainingSrcSize < ZSTD_FRAMEHEADERSIZE_MIN(dctx->format)+ZSTD_blockHeaderSize, + srcSize_wrong, ""); + + /* Frame Header */ + { size_t const frameHeaderSize = ZSTD_frameHeaderSize_internal( + ip, ZSTD_FRAMEHEADERSIZE_PREFIX(dctx->format), dctx->format); + if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize; + RETURN_ERROR_IF(remainingSrcSize < frameHeaderSize+ZSTD_blockHeaderSize, + srcSize_wrong, ""); + FORWARD_IF_ERROR( ZSTD_decodeFrameHeader(dctx, ip, frameHeaderSize) , ""); + ip += frameHeaderSize; remainingSrcSize -= frameHeaderSize; + } + + /* Loop on each block */ + while (1) { + BYTE* oBlockEnd = oend; + size_t decodedSize; + blockProperties_t blockProperties; + size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSrcSize, &blockProperties); + if (ZSTD_isError(cBlockSize)) return cBlockSize; + + ip += ZSTD_blockHeaderSize; + remainingSrcSize -= ZSTD_blockHeaderSize; + RETURN_ERROR_IF(cBlockSize > remainingSrcSize, srcSize_wrong, ""); + + if (ip >= op && ip < oBlockEnd) { + /* We are decompressing in-place. Limit the output pointer so that we + * don't overwrite the block that we are currently reading. This will + * fail decompression if the input & output pointers aren't spaced + * far enough apart. + * + * This is important to set, even when the pointers are far enough + * apart, because ZSTD_decompressBlock_internal() can decide to store + * literals in the output buffer, after the block it is decompressing. + * Since we don't want anything to overwrite our input, we have to tell + * ZSTD_decompressBlock_internal to never write past ip. + * + * See ZSTD_allocateLiteralsBuffer() for reference. + */ + oBlockEnd = op + (ip - op); + } + + switch(blockProperties.blockType) + { + case bt_compressed: + decodedSize = ZSTD_decompressBlock_internal(dctx, op, (size_t)(oBlockEnd-op), ip, cBlockSize, /* frame */ 1, not_streaming); + break; + case bt_raw : + /* Use oend instead of oBlockEnd because this function is safe to overlap. It uses memmove. */ + decodedSize = ZSTD_copyRawBlock(op, (size_t)(oend-op), ip, cBlockSize); + break; + case bt_rle : + decodedSize = ZSTD_setRleBlock(op, (size_t)(oBlockEnd-op), *ip, blockProperties.origSize); + break; + case bt_reserved : + default: + RETURN_ERROR(corruption_detected, "invalid block type"); + } + + if (ZSTD_isError(decodedSize)) return decodedSize; + if (dctx->validateChecksum) + XXH64_update(&dctx->xxhState, op, decodedSize); + if (decodedSize != 0) + op += decodedSize; + assert(ip != NULL); + ip += cBlockSize; + remainingSrcSize -= cBlockSize; + if (blockProperties.lastBlock) break; + } + + if (dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) { + RETURN_ERROR_IF((U64)(op-ostart) != dctx->fParams.frameContentSize, + corruption_detected, ""); + } + if (dctx->fParams.checksumFlag) { /* Frame content checksum verification */ + RETURN_ERROR_IF(remainingSrcSize<4, checksum_wrong, ""); + if (!dctx->forceIgnoreChecksum) { + U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState); + U32 checkRead; + checkRead = MEM_readLE32(ip); + RETURN_ERROR_IF(checkRead != checkCalc, checksum_wrong, ""); + } + ip += 4; + remainingSrcSize -= 4; + } + ZSTD_DCtx_trace_end(dctx, (U64)(op-ostart), (U64)(ip-istart), /* streaming */ 0); + /* Allow caller to get size read */ + DEBUGLOG(4, "ZSTD_decompressFrame: decompressed frame of size %zi, consuming %zi bytes of input", op-ostart, ip - (const BYTE*)*srcPtr); + *srcPtr = ip; + *srcSizePtr = remainingSrcSize; + return (size_t)(op-ostart); +} + +static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const void* dict, size_t dictSize, + const ZSTD_DDict* ddict) +{ + void* const dststart = dst; + int moreThan1Frame = 0; + + DEBUGLOG(5, "ZSTD_decompressMultiFrame"); + assert(dict==NULL || ddict==NULL); /* either dict or ddict set, not both */ + + if (ddict) { + dict = ZSTD_DDict_dictContent(ddict); + dictSize = ZSTD_DDict_dictSize(ddict); + } + + while (srcSize >= ZSTD_startingInputLength(dctx->format)) { + +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) + if (ZSTD_isLegacy(src, srcSize)) { + size_t decodedSize; + size_t const frameSize = ZSTD_findFrameCompressedSizeLegacy(src, srcSize); + if (ZSTD_isError(frameSize)) return frameSize; + RETURN_ERROR_IF(dctx->staticSize, memory_allocation, + "legacy support is not compatible with static dctx"); + + decodedSize = ZSTD_decompressLegacy(dst, dstCapacity, src, frameSize, dict, dictSize); + if (ZSTD_isError(decodedSize)) return decodedSize; + + assert(decodedSize <= dstCapacity); + dst = (BYTE*)dst + decodedSize; + dstCapacity -= decodedSize; + + src = (const BYTE*)src + frameSize; + srcSize -= frameSize; + + continue; + } +#endif + + if (srcSize >= 4) { + U32 const magicNumber = MEM_readLE32(src); + DEBUGLOG(5, "reading magic number %08X", (unsigned)magicNumber); + if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { + /* skippable frame detected : skip it */ + size_t const skippableSize = readSkippableFrameSize(src, srcSize); + FORWARD_IF_ERROR(skippableSize, "invalid skippable frame"); + assert(skippableSize <= srcSize); + + src = (const BYTE *)src + skippableSize; + srcSize -= skippableSize; + continue; /* check next frame */ + } } + + if (ddict) { + /* we were called from ZSTD_decompress_usingDDict */ + FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(dctx, ddict), ""); + } else { + /* this will initialize correctly with no dict if dict == NULL, so + * use this in all cases but ddict */ + FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDict(dctx, dict, dictSize), ""); + } + ZSTD_checkContinuity(dctx, dst, dstCapacity); + + { const size_t res = ZSTD_decompressFrame(dctx, dst, dstCapacity, + &src, &srcSize); + RETURN_ERROR_IF( + (ZSTD_getErrorCode(res) == ZSTD_error_prefix_unknown) + && (moreThan1Frame==1), + srcSize_wrong, + "At least one frame successfully completed, " + "but following bytes are garbage: " + "it's more likely to be a srcSize error, " + "specifying more input bytes than size of frame(s). " + "Note: one could be unlucky, it might be a corruption error instead, " + "happening right at the place where we expect zstd magic bytes. " + "But this is _much_ less likely than a srcSize field error."); + if (ZSTD_isError(res)) return res; + assert(res <= dstCapacity); + if (res != 0) + dst = (BYTE*)dst + res; + dstCapacity -= res; + } + moreThan1Frame = 1; + } /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */ + + RETURN_ERROR_IF(srcSize, srcSize_wrong, "input not entirely consumed"); + + return (size_t)((BYTE*)dst - (BYTE*)dststart); +} + +size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const void* dict, size_t dictSize) +{ + return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize, dict, dictSize, NULL); +} + + +static ZSTD_DDict const* ZSTD_getDDict(ZSTD_DCtx* dctx) +{ + switch (dctx->dictUses) { + default: + assert(0 /* Impossible */); + ZSTD_FALLTHROUGH; + case ZSTD_dont_use: + ZSTD_clearDict(dctx); + return NULL; + case ZSTD_use_indefinitely: + return dctx->ddict; + case ZSTD_use_once: + dctx->dictUses = ZSTD_dont_use; + return dctx->ddict; + } +} + +size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) +{ + return ZSTD_decompress_usingDDict(dctx, dst, dstCapacity, src, srcSize, ZSTD_getDDict(dctx)); +} + + +size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t srcSize) +{ +#if defined(ZSTD_HEAPMODE) && (ZSTD_HEAPMODE>=1) + size_t regenSize; + ZSTD_DCtx* const dctx = ZSTD_createDCtx_internal(ZSTD_defaultCMem); + RETURN_ERROR_IF(dctx==NULL, memory_allocation, "NULL pointer!"); + regenSize = ZSTD_decompressDCtx(dctx, dst, dstCapacity, src, srcSize); + ZSTD_freeDCtx(dctx); + return regenSize; +#else /* stack mode */ + ZSTD_DCtx dctx; + ZSTD_initDCtx_internal(&dctx); + return ZSTD_decompressDCtx(&dctx, dst, dstCapacity, src, srcSize); +#endif +} + + +/*-************************************** +* Advanced Streaming Decompression API +* Bufferless and synchronous +****************************************/ +size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx) { return dctx->expected; } + +/** + * Similar to ZSTD_nextSrcSizeToDecompress(), but when a block input can be streamed, we + * allow taking a partial block as the input. Currently only raw uncompressed blocks can + * be streamed. + * + * For blocks that can be streamed, this allows us to reduce the latency until we produce + * output, and avoid copying the input. + * + * @param inputSize - The total amount of input that the caller currently has. + */ +static size_t ZSTD_nextSrcSizeToDecompressWithInputSize(ZSTD_DCtx* dctx, size_t inputSize) { + if (!(dctx->stage == ZSTDds_decompressBlock || dctx->stage == ZSTDds_decompressLastBlock)) + return dctx->expected; + if (dctx->bType != bt_raw) + return dctx->expected; + return BOUNDED(1, inputSize, dctx->expected); +} + +ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx) { + switch(dctx->stage) + { + default: /* should not happen */ + assert(0); + ZSTD_FALLTHROUGH; + case ZSTDds_getFrameHeaderSize: + ZSTD_FALLTHROUGH; + case ZSTDds_decodeFrameHeader: + return ZSTDnit_frameHeader; + case ZSTDds_decodeBlockHeader: + return ZSTDnit_blockHeader; + case ZSTDds_decompressBlock: + return ZSTDnit_block; + case ZSTDds_decompressLastBlock: + return ZSTDnit_lastBlock; + case ZSTDds_checkChecksum: + return ZSTDnit_checksum; + case ZSTDds_decodeSkippableHeader: + ZSTD_FALLTHROUGH; + case ZSTDds_skipFrame: + return ZSTDnit_skippableFrame; + } +} + +static int ZSTD_isSkipFrame(ZSTD_DCtx* dctx) { return dctx->stage == ZSTDds_skipFrame; } + +/** ZSTD_decompressContinue() : + * srcSize : must be the exact nb of bytes expected (see ZSTD_nextSrcSizeToDecompress()) + * @return : nb of bytes generated into `dst` (necessarily <= `dstCapacity) + * or an error code, which can be tested using ZSTD_isError() */ +size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) +{ + DEBUGLOG(5, "ZSTD_decompressContinue (srcSize:%u)", (unsigned)srcSize); + /* Sanity check */ + RETURN_ERROR_IF(srcSize != ZSTD_nextSrcSizeToDecompressWithInputSize(dctx, srcSize), srcSize_wrong, "not allowed"); + ZSTD_checkContinuity(dctx, dst, dstCapacity); + + dctx->processedCSize += srcSize; + + switch (dctx->stage) + { + case ZSTDds_getFrameHeaderSize : + assert(src != NULL); + if (dctx->format == ZSTD_f_zstd1) { /* allows header */ + assert(srcSize >= ZSTD_FRAMEIDSIZE); /* to read skippable magic number */ + if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */ + ZSTD_memcpy(dctx->headerBuffer, src, srcSize); + dctx->expected = ZSTD_SKIPPABLEHEADERSIZE - srcSize; /* remaining to load to get full skippable frame header */ + dctx->stage = ZSTDds_decodeSkippableHeader; + return 0; + } } + dctx->headerSize = ZSTD_frameHeaderSize_internal(src, srcSize, dctx->format); + if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize; + ZSTD_memcpy(dctx->headerBuffer, src, srcSize); + dctx->expected = dctx->headerSize - srcSize; + dctx->stage = ZSTDds_decodeFrameHeader; + return 0; + + case ZSTDds_decodeFrameHeader: + assert(src != NULL); + ZSTD_memcpy(dctx->headerBuffer + (dctx->headerSize - srcSize), src, srcSize); + FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize), ""); + dctx->expected = ZSTD_blockHeaderSize; + dctx->stage = ZSTDds_decodeBlockHeader; + return 0; + + case ZSTDds_decodeBlockHeader: + { blockProperties_t bp; + size_t const cBlockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &bp); + if (ZSTD_isError(cBlockSize)) return cBlockSize; + RETURN_ERROR_IF(cBlockSize > dctx->fParams.blockSizeMax, corruption_detected, "Block Size Exceeds Maximum"); + dctx->expected = cBlockSize; + dctx->bType = bp.blockType; + dctx->rleSize = bp.origSize; + if (cBlockSize) { + dctx->stage = bp.lastBlock ? ZSTDds_decompressLastBlock : ZSTDds_decompressBlock; + return 0; + } + /* empty block */ + if (bp.lastBlock) { + if (dctx->fParams.checksumFlag) { + dctx->expected = 4; + dctx->stage = ZSTDds_checkChecksum; + } else { + dctx->expected = 0; /* end of frame */ + dctx->stage = ZSTDds_getFrameHeaderSize; + } + } else { + dctx->expected = ZSTD_blockHeaderSize; /* jump to next header */ + dctx->stage = ZSTDds_decodeBlockHeader; + } + return 0; + } + + case ZSTDds_decompressLastBlock: + case ZSTDds_decompressBlock: + DEBUGLOG(5, "ZSTD_decompressContinue: case ZSTDds_decompressBlock"); + { size_t rSize; + switch(dctx->bType) + { + case bt_compressed: + DEBUGLOG(5, "ZSTD_decompressContinue: case bt_compressed"); + rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 1, is_streaming); + dctx->expected = 0; /* Streaming not supported */ + break; + case bt_raw : + assert(srcSize <= dctx->expected); + rSize = ZSTD_copyRawBlock(dst, dstCapacity, src, srcSize); + FORWARD_IF_ERROR(rSize, "ZSTD_copyRawBlock failed"); + assert(rSize == srcSize); + dctx->expected -= rSize; + break; + case bt_rle : + rSize = ZSTD_setRleBlock(dst, dstCapacity, *(const BYTE*)src, dctx->rleSize); + dctx->expected = 0; /* Streaming not supported */ + break; + case bt_reserved : /* should never happen */ + default: + RETURN_ERROR(corruption_detected, "invalid block type"); + } + FORWARD_IF_ERROR(rSize, ""); + RETURN_ERROR_IF(rSize > dctx->fParams.blockSizeMax, corruption_detected, "Decompressed Block Size Exceeds Maximum"); + DEBUGLOG(5, "ZSTD_decompressContinue: decoded size from block : %u", (unsigned)rSize); + dctx->decodedSize += rSize; + if (dctx->validateChecksum) XXH64_update(&dctx->xxhState, dst, rSize); + dctx->previousDstEnd = (char*)dst + rSize; + + /* Stay on the same stage until we are finished streaming the block. */ + if (dctx->expected > 0) { + return rSize; + } + + if (dctx->stage == ZSTDds_decompressLastBlock) { /* end of frame */ + DEBUGLOG(4, "ZSTD_decompressContinue: decoded size from frame : %u", (unsigned)dctx->decodedSize); + RETURN_ERROR_IF( + dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN + && dctx->decodedSize != dctx->fParams.frameContentSize, + corruption_detected, ""); + if (dctx->fParams.checksumFlag) { /* another round for frame checksum */ + dctx->expected = 4; + dctx->stage = ZSTDds_checkChecksum; + } else { + ZSTD_DCtx_trace_end(dctx, dctx->decodedSize, dctx->processedCSize, /* streaming */ 1); + dctx->expected = 0; /* ends here */ + dctx->stage = ZSTDds_getFrameHeaderSize; + } + } else { + dctx->stage = ZSTDds_decodeBlockHeader; + dctx->expected = ZSTD_blockHeaderSize; + } + return rSize; + } + + case ZSTDds_checkChecksum: + assert(srcSize == 4); /* guaranteed by dctx->expected */ + { + if (dctx->validateChecksum) { + U32 const h32 = (U32)XXH64_digest(&dctx->xxhState); + U32 const check32 = MEM_readLE32(src); + DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", (unsigned)h32, (unsigned)check32); + RETURN_ERROR_IF(check32 != h32, checksum_wrong, ""); + } + ZSTD_DCtx_trace_end(dctx, dctx->decodedSize, dctx->processedCSize, /* streaming */ 1); + dctx->expected = 0; + dctx->stage = ZSTDds_getFrameHeaderSize; + return 0; + } + + case ZSTDds_decodeSkippableHeader: + assert(src != NULL); + assert(srcSize <= ZSTD_SKIPPABLEHEADERSIZE); + ZSTD_memcpy(dctx->headerBuffer + (ZSTD_SKIPPABLEHEADERSIZE - srcSize), src, srcSize); /* complete skippable header */ + dctx->expected = MEM_readLE32(dctx->headerBuffer + ZSTD_FRAMEIDSIZE); /* note : dctx->expected can grow seriously large, beyond local buffer size */ + dctx->stage = ZSTDds_skipFrame; + return 0; + + case ZSTDds_skipFrame: + dctx->expected = 0; + dctx->stage = ZSTDds_getFrameHeaderSize; + return 0; + + default: + assert(0); /* impossible */ + RETURN_ERROR(GENERIC, "impossible to reach"); /* some compilers require default to do something */ + } +} + + +static size_t ZSTD_refDictContent(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) +{ + dctx->dictEnd = dctx->previousDstEnd; + dctx->virtualStart = (const char*)dict - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart)); + dctx->prefixStart = dict; + dctx->previousDstEnd = (const char*)dict + dictSize; +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + dctx->dictContentBeginForFuzzing = dctx->prefixStart; + dctx->dictContentEndForFuzzing = dctx->previousDstEnd; +#endif + return 0; +} + +/*! ZSTD_loadDEntropy() : + * dict : must point at beginning of a valid zstd dictionary. + * @return : size of entropy tables read */ +size_t +ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy, + const void* const dict, size_t const dictSize) +{ + const BYTE* dictPtr = (const BYTE*)dict; + const BYTE* const dictEnd = dictPtr + dictSize; + + RETURN_ERROR_IF(dictSize <= 8, dictionary_corrupted, "dict is too small"); + assert(MEM_readLE32(dict) == ZSTD_MAGIC_DICTIONARY); /* dict must be valid */ + dictPtr += 8; /* skip header = magic + dictID */ + + ZSTD_STATIC_ASSERT(offsetof(ZSTD_entropyDTables_t, OFTable) == offsetof(ZSTD_entropyDTables_t, LLTable) + sizeof(entropy->LLTable)); + ZSTD_STATIC_ASSERT(offsetof(ZSTD_entropyDTables_t, MLTable) == offsetof(ZSTD_entropyDTables_t, OFTable) + sizeof(entropy->OFTable)); + ZSTD_STATIC_ASSERT(sizeof(entropy->LLTable) + sizeof(entropy->OFTable) + sizeof(entropy->MLTable) >= HUF_DECOMPRESS_WORKSPACE_SIZE); + { void* const workspace = &entropy->LLTable; /* use fse tables as temporary workspace; implies fse tables are grouped together */ + size_t const workspaceSize = sizeof(entropy->LLTable) + sizeof(entropy->OFTable) + sizeof(entropy->MLTable); +#ifdef HUF_FORCE_DECOMPRESS_X1 + /* in minimal huffman, we always use X1 variants */ + size_t const hSize = HUF_readDTableX1_wksp(entropy->hufTable, + dictPtr, dictEnd - dictPtr, + workspace, workspaceSize, /* flags */ 0); +#else + size_t const hSize = HUF_readDTableX2_wksp(entropy->hufTable, + dictPtr, (size_t)(dictEnd - dictPtr), + workspace, workspaceSize, /* flags */ 0); +#endif + RETURN_ERROR_IF(HUF_isError(hSize), dictionary_corrupted, ""); + dictPtr += hSize; + } + + { short offcodeNCount[MaxOff+1]; + unsigned offcodeMaxValue = MaxOff, offcodeLog; + size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, (size_t)(dictEnd-dictPtr)); + RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted, ""); + RETURN_ERROR_IF(offcodeMaxValue > MaxOff, dictionary_corrupted, ""); + RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted, ""); + ZSTD_buildFSETable( entropy->OFTable, + offcodeNCount, offcodeMaxValue, + OF_base, OF_bits, + offcodeLog, + entropy->workspace, sizeof(entropy->workspace), + /* bmi2 */0); + dictPtr += offcodeHeaderSize; + } + + { short matchlengthNCount[MaxML+1]; + unsigned matchlengthMaxValue = MaxML, matchlengthLog; + size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, (size_t)(dictEnd-dictPtr)); + RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted, ""); + RETURN_ERROR_IF(matchlengthMaxValue > MaxML, dictionary_corrupted, ""); + RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted, ""); + ZSTD_buildFSETable( entropy->MLTable, + matchlengthNCount, matchlengthMaxValue, + ML_base, ML_bits, + matchlengthLog, + entropy->workspace, sizeof(entropy->workspace), + /* bmi2 */ 0); + dictPtr += matchlengthHeaderSize; + } + + { short litlengthNCount[MaxLL+1]; + unsigned litlengthMaxValue = MaxLL, litlengthLog; + size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, (size_t)(dictEnd-dictPtr)); + RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted, ""); + RETURN_ERROR_IF(litlengthMaxValue > MaxLL, dictionary_corrupted, ""); + RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted, ""); + ZSTD_buildFSETable( entropy->LLTable, + litlengthNCount, litlengthMaxValue, + LL_base, LL_bits, + litlengthLog, + entropy->workspace, sizeof(entropy->workspace), + /* bmi2 */ 0); + dictPtr += litlengthHeaderSize; + } + + RETURN_ERROR_IF(dictPtr+12 > dictEnd, dictionary_corrupted, ""); + { int i; + size_t const dictContentSize = (size_t)(dictEnd - (dictPtr+12)); + for (i=0; i<3; i++) { + U32 const rep = MEM_readLE32(dictPtr); dictPtr += 4; + RETURN_ERROR_IF(rep==0 || rep > dictContentSize, + dictionary_corrupted, ""); + entropy->rep[i] = rep; + } } + + return (size_t)(dictPtr - (const BYTE*)dict); +} + +static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) +{ + if (dictSize < 8) return ZSTD_refDictContent(dctx, dict, dictSize); + { U32 const magic = MEM_readLE32(dict); + if (magic != ZSTD_MAGIC_DICTIONARY) { + return ZSTD_refDictContent(dctx, dict, dictSize); /* pure content mode */ + } } + dctx->dictID = MEM_readLE32((const char*)dict + ZSTD_FRAMEIDSIZE); + + /* load entropy tables */ + { size_t const eSize = ZSTD_loadDEntropy(&dctx->entropy, dict, dictSize); + RETURN_ERROR_IF(ZSTD_isError(eSize), dictionary_corrupted, ""); + dict = (const char*)dict + eSize; + dictSize -= eSize; + } + dctx->litEntropy = dctx->fseEntropy = 1; + + /* reference dictionary content */ + return ZSTD_refDictContent(dctx, dict, dictSize); +} + +size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx) +{ + assert(dctx != NULL); +#if ZSTD_TRACE + dctx->traceCtx = (ZSTD_trace_decompress_begin != NULL) ? ZSTD_trace_decompress_begin(dctx) : 0; +#endif + dctx->expected = ZSTD_startingInputLength(dctx->format); /* dctx->format must be properly set */ + dctx->stage = ZSTDds_getFrameHeaderSize; + dctx->processedCSize = 0; + dctx->decodedSize = 0; + dctx->previousDstEnd = NULL; + dctx->prefixStart = NULL; + dctx->virtualStart = NULL; + dctx->dictEnd = NULL; + dctx->entropy.hufTable[0] = (HUF_DTable)((ZSTD_HUFFDTABLE_CAPACITY_LOG)*0x1000001); /* cover both little and big endian */ + dctx->litEntropy = dctx->fseEntropy = 0; + dctx->dictID = 0; + dctx->bType = bt_reserved; + ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue)); + ZSTD_memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */ + dctx->LLTptr = dctx->entropy.LLTable; + dctx->MLTptr = dctx->entropy.MLTable; + dctx->OFTptr = dctx->entropy.OFTable; + dctx->HUFptr = dctx->entropy.hufTable; + return 0; +} + +size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) +{ + FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) , ""); + if (dict && dictSize) + RETURN_ERROR_IF( + ZSTD_isError(ZSTD_decompress_insertDictionary(dctx, dict, dictSize)), + dictionary_corrupted, ""); + return 0; +} + + +/* ====== ZSTD_DDict ====== */ + +size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict) +{ + DEBUGLOG(4, "ZSTD_decompressBegin_usingDDict"); + assert(dctx != NULL); + if (ddict) { + const char* const dictStart = (const char*)ZSTD_DDict_dictContent(ddict); + size_t const dictSize = ZSTD_DDict_dictSize(ddict); + const void* const dictEnd = dictStart + dictSize; + dctx->ddictIsCold = (dctx->dictEnd != dictEnd); + DEBUGLOG(4, "DDict is %s", + dctx->ddictIsCold ? "~cold~" : "hot!"); + } + FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) , ""); + if (ddict) { /* NULL ddict is equivalent to no dictionary */ + ZSTD_copyDDictParameters(dctx, ddict); + } + return 0; +} + +/*! ZSTD_getDictID_fromDict() : + * Provides the dictID stored within dictionary. + * if @return == 0, the dictionary is not conformant with Zstandard specification. + * It can still be loaded, but as a content-only dictionary. */ +unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize) +{ + if (dictSize < 8) return 0; + if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) return 0; + return MEM_readLE32((const char*)dict + ZSTD_FRAMEIDSIZE); +} + +/*! ZSTD_getDictID_fromFrame() : + * Provides the dictID required to decompress frame stored within `src`. + * If @return == 0, the dictID could not be decoded. + * This could for one of the following reasons : + * - The frame does not require a dictionary (most common case). + * - The frame was built with dictID intentionally removed. + * Needed dictionary is a hidden piece of information. + * Note : this use case also happens when using a non-conformant dictionary. + * - `srcSize` is too small, and as a result, frame header could not be decoded. + * Note : possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`. + * - This is not a Zstandard frame. + * When identifying the exact failure cause, it's possible to use + * ZSTD_getFrameHeader(), which will provide a more precise error code. */ +unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize) +{ + ZSTD_frameHeader zfp = { 0, 0, 0, ZSTD_frame, 0, 0, 0, 0, 0 }; + size_t const hError = ZSTD_getFrameHeader(&zfp, src, srcSize); + if (ZSTD_isError(hError)) return 0; + return zfp.dictID; +} + + +/*! ZSTD_decompress_usingDDict() : +* Decompression using a pre-digested Dictionary +* Use dictionary without significant overhead. */ +size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const ZSTD_DDict* ddict) +{ + /* pass content and size in case legacy frames are encountered */ + return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize, + NULL, 0, + ddict); +} + + +/*===================================== +* Streaming decompression +*====================================*/ + +ZSTD_DStream* ZSTD_createDStream(void) +{ + DEBUGLOG(3, "ZSTD_createDStream"); + return ZSTD_createDCtx_internal(ZSTD_defaultCMem); +} + +ZSTD_DStream* ZSTD_initStaticDStream(void *workspace, size_t workspaceSize) +{ + return ZSTD_initStaticDCtx(workspace, workspaceSize); +} + +ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem) +{ + return ZSTD_createDCtx_internal(customMem); +} + +size_t ZSTD_freeDStream(ZSTD_DStream* zds) +{ + return ZSTD_freeDCtx(zds); +} + + +/* *** Initialization *** */ + +size_t ZSTD_DStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize; } +size_t ZSTD_DStreamOutSize(void) { return ZSTD_BLOCKSIZE_MAX; } + +size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType) +{ + RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, ""); + ZSTD_clearDict(dctx); + if (dict && dictSize != 0) { + dctx->ddictLocal = ZSTD_createDDict_advanced(dict, dictSize, dictLoadMethod, dictContentType, dctx->customMem); + RETURN_ERROR_IF(dctx->ddictLocal == NULL, memory_allocation, "NULL pointer!"); + dctx->ddict = dctx->ddictLocal; + dctx->dictUses = ZSTD_use_indefinitely; + } + return 0; +} + +size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) +{ + return ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto); +} + +size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) +{ + return ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto); +} + +size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType) +{ + FORWARD_IF_ERROR(ZSTD_DCtx_loadDictionary_advanced(dctx, prefix, prefixSize, ZSTD_dlm_byRef, dictContentType), ""); + dctx->dictUses = ZSTD_use_once; + return 0; +} + +size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize) +{ + return ZSTD_DCtx_refPrefix_advanced(dctx, prefix, prefixSize, ZSTD_dct_rawContent); +} + + +/* ZSTD_initDStream_usingDict() : + * return : expected size, aka ZSTD_startingInputLength(). + * this function cannot fail */ +size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize) +{ + DEBUGLOG(4, "ZSTD_initDStream_usingDict"); + FORWARD_IF_ERROR( ZSTD_DCtx_reset(zds, ZSTD_reset_session_only) , ""); + FORWARD_IF_ERROR( ZSTD_DCtx_loadDictionary(zds, dict, dictSize) , ""); + return ZSTD_startingInputLength(zds->format); +} + +/* note : this variant can't fail */ +size_t ZSTD_initDStream(ZSTD_DStream* zds) +{ + DEBUGLOG(4, "ZSTD_initDStream"); + FORWARD_IF_ERROR(ZSTD_DCtx_reset(zds, ZSTD_reset_session_only), ""); + FORWARD_IF_ERROR(ZSTD_DCtx_refDDict(zds, NULL), ""); + return ZSTD_startingInputLength(zds->format); +} + +/* ZSTD_initDStream_usingDDict() : + * ddict will just be referenced, and must outlive decompression session + * this function cannot fail */ +size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* dctx, const ZSTD_DDict* ddict) +{ + DEBUGLOG(4, "ZSTD_initDStream_usingDDict"); + FORWARD_IF_ERROR( ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only) , ""); + FORWARD_IF_ERROR( ZSTD_DCtx_refDDict(dctx, ddict) , ""); + return ZSTD_startingInputLength(dctx->format); +} + +/* ZSTD_resetDStream() : + * return : expected size, aka ZSTD_startingInputLength(). + * this function cannot fail */ +size_t ZSTD_resetDStream(ZSTD_DStream* dctx) +{ + DEBUGLOG(4, "ZSTD_resetDStream"); + FORWARD_IF_ERROR(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only), ""); + return ZSTD_startingInputLength(dctx->format); +} + + +size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict) +{ + RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, ""); + ZSTD_clearDict(dctx); + if (ddict) { + dctx->ddict = ddict; + dctx->dictUses = ZSTD_use_indefinitely; + if (dctx->refMultipleDDicts == ZSTD_rmd_refMultipleDDicts) { + if (dctx->ddictSet == NULL) { + dctx->ddictSet = ZSTD_createDDictHashSet(dctx->customMem); + if (!dctx->ddictSet) { + RETURN_ERROR(memory_allocation, "Failed to allocate memory for hash set!"); + } + } + assert(!dctx->staticSize); /* Impossible: ddictSet cannot have been allocated if static dctx */ + FORWARD_IF_ERROR(ZSTD_DDictHashSet_addDDict(dctx->ddictSet, ddict, dctx->customMem), ""); + } + } + return 0; +} + +/* ZSTD_DCtx_setMaxWindowSize() : + * note : no direct equivalence in ZSTD_DCtx_setParameter, + * since this version sets windowSize, and the other sets windowLog */ +size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize) +{ + ZSTD_bounds const bounds = ZSTD_dParam_getBounds(ZSTD_d_windowLogMax); + size_t const min = (size_t)1 << bounds.lowerBound; + size_t const max = (size_t)1 << bounds.upperBound; + RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, ""); + RETURN_ERROR_IF(maxWindowSize < min, parameter_outOfBound, ""); + RETURN_ERROR_IF(maxWindowSize > max, parameter_outOfBound, ""); + dctx->maxWindowSize = maxWindowSize; + return 0; +} + +size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format) +{ + return ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, (int)format); +} + +ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam) +{ + ZSTD_bounds bounds = { 0, 0, 0 }; + switch(dParam) { + case ZSTD_d_windowLogMax: + bounds.lowerBound = ZSTD_WINDOWLOG_ABSOLUTEMIN; + bounds.upperBound = ZSTD_WINDOWLOG_MAX; + return bounds; + case ZSTD_d_format: + bounds.lowerBound = (int)ZSTD_f_zstd1; + bounds.upperBound = (int)ZSTD_f_zstd1_magicless; + ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless); + return bounds; + case ZSTD_d_stableOutBuffer: + bounds.lowerBound = (int)ZSTD_bm_buffered; + bounds.upperBound = (int)ZSTD_bm_stable; + return bounds; + case ZSTD_d_forceIgnoreChecksum: + bounds.lowerBound = (int)ZSTD_d_validateChecksum; + bounds.upperBound = (int)ZSTD_d_ignoreChecksum; + return bounds; + case ZSTD_d_refMultipleDDicts: + bounds.lowerBound = (int)ZSTD_rmd_refSingleDDict; + bounds.upperBound = (int)ZSTD_rmd_refMultipleDDicts; + return bounds; + case ZSTD_d_disableHuffmanAssembly: + bounds.lowerBound = 0; + bounds.upperBound = 1; + return bounds; + + default:; + } + bounds.error = ERROR(parameter_unsupported); + return bounds; +} + +/* ZSTD_dParam_withinBounds: + * @return 1 if value is within dParam bounds, + * 0 otherwise */ +static int ZSTD_dParam_withinBounds(ZSTD_dParameter dParam, int value) +{ + ZSTD_bounds const bounds = ZSTD_dParam_getBounds(dParam); + if (ZSTD_isError(bounds.error)) return 0; + if (value < bounds.lowerBound) return 0; + if (value > bounds.upperBound) return 0; + return 1; +} + +#define CHECK_DBOUNDS(p,v) { \ + RETURN_ERROR_IF(!ZSTD_dParam_withinBounds(p, v), parameter_outOfBound, ""); \ +} + +size_t ZSTD_DCtx_getParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int* value) +{ + switch (param) { + case ZSTD_d_windowLogMax: + *value = (int)ZSTD_highbit32((U32)dctx->maxWindowSize); + return 0; + case ZSTD_d_format: + *value = (int)dctx->format; + return 0; + case ZSTD_d_stableOutBuffer: + *value = (int)dctx->outBufferMode; + return 0; + case ZSTD_d_forceIgnoreChecksum: + *value = (int)dctx->forceIgnoreChecksum; + return 0; + case ZSTD_d_refMultipleDDicts: + *value = (int)dctx->refMultipleDDicts; + return 0; + case ZSTD_d_disableHuffmanAssembly: + *value = (int)dctx->disableHufAsm; + return 0; + default:; + } + RETURN_ERROR(parameter_unsupported, ""); +} + +size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value) +{ + RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, ""); + switch(dParam) { + case ZSTD_d_windowLogMax: + if (value == 0) value = ZSTD_WINDOWLOG_LIMIT_DEFAULT; + CHECK_DBOUNDS(ZSTD_d_windowLogMax, value); + dctx->maxWindowSize = ((size_t)1) << value; + return 0; + case ZSTD_d_format: + CHECK_DBOUNDS(ZSTD_d_format, value); + dctx->format = (ZSTD_format_e)value; + return 0; + case ZSTD_d_stableOutBuffer: + CHECK_DBOUNDS(ZSTD_d_stableOutBuffer, value); + dctx->outBufferMode = (ZSTD_bufferMode_e)value; + return 0; + case ZSTD_d_forceIgnoreChecksum: + CHECK_DBOUNDS(ZSTD_d_forceIgnoreChecksum, value); + dctx->forceIgnoreChecksum = (ZSTD_forceIgnoreChecksum_e)value; + return 0; + case ZSTD_d_refMultipleDDicts: + CHECK_DBOUNDS(ZSTD_d_refMultipleDDicts, value); + if (dctx->staticSize != 0) { + RETURN_ERROR(parameter_unsupported, "Static dctx does not support multiple DDicts!"); + } + dctx->refMultipleDDicts = (ZSTD_refMultipleDDicts_e)value; + return 0; + case ZSTD_d_disableHuffmanAssembly: + CHECK_DBOUNDS(ZSTD_d_disableHuffmanAssembly, value); + dctx->disableHufAsm = value != 0; + return 0; + default:; + } + RETURN_ERROR(parameter_unsupported, ""); +} + +size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset) +{ + if ( (reset == ZSTD_reset_session_only) + || (reset == ZSTD_reset_session_and_parameters) ) { + dctx->streamStage = zdss_init; + dctx->noForwardProgress = 0; + } + if ( (reset == ZSTD_reset_parameters) + || (reset == ZSTD_reset_session_and_parameters) ) { + RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, ""); + ZSTD_clearDict(dctx); + ZSTD_DCtx_resetParameters(dctx); + } + return 0; +} + + +size_t ZSTD_sizeof_DStream(const ZSTD_DStream* dctx) +{ + return ZSTD_sizeof_DCtx(dctx); +} + +size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize) +{ + size_t const blockSize = (size_t) MIN(windowSize, ZSTD_BLOCKSIZE_MAX); + /* space is needed to store the litbuffer after the output of a given block without stomping the extDict of a previous run, as well as to cover both windows against wildcopy*/ + unsigned long long const neededRBSize = windowSize + blockSize + ZSTD_BLOCKSIZE_MAX + (WILDCOPY_OVERLENGTH * 2); + unsigned long long const neededSize = MIN(frameContentSize, neededRBSize); + size_t const minRBSize = (size_t) neededSize; + RETURN_ERROR_IF((unsigned long long)minRBSize != neededSize, + frameParameter_windowTooLarge, ""); + return minRBSize; +} + +size_t ZSTD_estimateDStreamSize(size_t windowSize) +{ + size_t const blockSize = MIN(windowSize, ZSTD_BLOCKSIZE_MAX); + size_t const inBuffSize = blockSize; /* no block can be larger */ + size_t const outBuffSize = ZSTD_decodingBufferSize_min(windowSize, ZSTD_CONTENTSIZE_UNKNOWN); + return ZSTD_estimateDCtxSize() + inBuffSize + outBuffSize; +} + +size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize) +{ + U32 const windowSizeMax = 1U << ZSTD_WINDOWLOG_MAX; /* note : should be user-selectable, but requires an additional parameter (or a dctx) */ + ZSTD_frameHeader zfh; + size_t const err = ZSTD_getFrameHeader(&zfh, src, srcSize); + if (ZSTD_isError(err)) return err; + RETURN_ERROR_IF(err>0, srcSize_wrong, ""); + RETURN_ERROR_IF(zfh.windowSize > windowSizeMax, + frameParameter_windowTooLarge, ""); + return ZSTD_estimateDStreamSize((size_t)zfh.windowSize); +} + + +/* ***** Decompression ***** */ + +static int ZSTD_DCtx_isOverflow(ZSTD_DStream* zds, size_t const neededInBuffSize, size_t const neededOutBuffSize) +{ + return (zds->inBuffSize + zds->outBuffSize) >= (neededInBuffSize + neededOutBuffSize) * ZSTD_WORKSPACETOOLARGE_FACTOR; +} + +static void ZSTD_DCtx_updateOversizedDuration(ZSTD_DStream* zds, size_t const neededInBuffSize, size_t const neededOutBuffSize) +{ + if (ZSTD_DCtx_isOverflow(zds, neededInBuffSize, neededOutBuffSize)) + zds->oversizedDuration++; + else + zds->oversizedDuration = 0; +} + +static int ZSTD_DCtx_isOversizedTooLong(ZSTD_DStream* zds) +{ + return zds->oversizedDuration >= ZSTD_WORKSPACETOOLARGE_MAXDURATION; +} + +/* Checks that the output buffer hasn't changed if ZSTD_obm_stable is used. */ +static size_t ZSTD_checkOutBuffer(ZSTD_DStream const* zds, ZSTD_outBuffer const* output) +{ + ZSTD_outBuffer const expect = zds->expectedOutBuffer; + /* No requirement when ZSTD_obm_stable is not enabled. */ + if (zds->outBufferMode != ZSTD_bm_stable) + return 0; + /* Any buffer is allowed in zdss_init, this must be the same for every other call until + * the context is reset. + */ + if (zds->streamStage == zdss_init) + return 0; + /* The buffer must match our expectation exactly. */ + if (expect.dst == output->dst && expect.pos == output->pos && expect.size == output->size) + return 0; + RETURN_ERROR(dstBuffer_wrong, "ZSTD_d_stableOutBuffer enabled but output differs!"); +} + +/* Calls ZSTD_decompressContinue() with the right parameters for ZSTD_decompressStream() + * and updates the stage and the output buffer state. This call is extracted so it can be + * used both when reading directly from the ZSTD_inBuffer, and in buffered input mode. + * NOTE: You must break after calling this function since the streamStage is modified. + */ +static size_t ZSTD_decompressContinueStream( + ZSTD_DStream* zds, char** op, char* oend, + void const* src, size_t srcSize) { + int const isSkipFrame = ZSTD_isSkipFrame(zds); + if (zds->outBufferMode == ZSTD_bm_buffered) { + size_t const dstSize = isSkipFrame ? 0 : zds->outBuffSize - zds->outStart; + size_t const decodedSize = ZSTD_decompressContinue(zds, + zds->outBuff + zds->outStart, dstSize, src, srcSize); + FORWARD_IF_ERROR(decodedSize, ""); + if (!decodedSize && !isSkipFrame) { + zds->streamStage = zdss_read; + } else { + zds->outEnd = zds->outStart + decodedSize; + zds->streamStage = zdss_flush; + } + } else { + /* Write directly into the output buffer */ + size_t const dstSize = isSkipFrame ? 0 : (size_t)(oend - *op); + size_t const decodedSize = ZSTD_decompressContinue(zds, *op, dstSize, src, srcSize); + FORWARD_IF_ERROR(decodedSize, ""); + *op += decodedSize; + /* Flushing is not needed. */ + zds->streamStage = zdss_read; + assert(*op <= oend); + assert(zds->outBufferMode == ZSTD_bm_stable); + } + return 0; +} + +size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input) +{ + const char* const src = (const char*)input->src; + const char* const istart = input->pos != 0 ? src + input->pos : src; + const char* const iend = input->size != 0 ? src + input->size : src; + const char* ip = istart; + char* const dst = (char*)output->dst; + char* const ostart = output->pos != 0 ? dst + output->pos : dst; + char* const oend = output->size != 0 ? dst + output->size : dst; + char* op = ostart; + U32 someMoreWork = 1; + + DEBUGLOG(5, "ZSTD_decompressStream"); + RETURN_ERROR_IF( + input->pos > input->size, + srcSize_wrong, + "forbidden. in: pos: %u vs size: %u", + (U32)input->pos, (U32)input->size); + RETURN_ERROR_IF( + output->pos > output->size, + dstSize_tooSmall, + "forbidden. out: pos: %u vs size: %u", + (U32)output->pos, (U32)output->size); + DEBUGLOG(5, "input size : %u", (U32)(input->size - input->pos)); + FORWARD_IF_ERROR(ZSTD_checkOutBuffer(zds, output), ""); + + while (someMoreWork) { + switch(zds->streamStage) + { + case zdss_init : + DEBUGLOG(5, "stage zdss_init => transparent reset "); + zds->streamStage = zdss_loadHeader; + zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0; +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) + zds->legacyVersion = 0; +#endif + zds->hostageByte = 0; + zds->expectedOutBuffer = *output; + ZSTD_FALLTHROUGH; + + case zdss_loadHeader : + DEBUGLOG(5, "stage zdss_loadHeader (srcSize : %u)", (U32)(iend - ip)); +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) + if (zds->legacyVersion) { + RETURN_ERROR_IF(zds->staticSize, memory_allocation, + "legacy support is incompatible with static dctx"); + { size_t const hint = ZSTD_decompressLegacyStream(zds->legacyContext, zds->legacyVersion, output, input); + if (hint==0) zds->streamStage = zdss_init; + return hint; + } } +#endif + { size_t const hSize = ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format); + if (zds->refMultipleDDicts && zds->ddictSet) { + ZSTD_DCtx_selectFrameDDict(zds); + } + if (ZSTD_isError(hSize)) { +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) + U32 const legacyVersion = ZSTD_isLegacy(istart, iend-istart); + if (legacyVersion) { + ZSTD_DDict const* const ddict = ZSTD_getDDict(zds); + const void* const dict = ddict ? ZSTD_DDict_dictContent(ddict) : NULL; + size_t const dictSize = ddict ? ZSTD_DDict_dictSize(ddict) : 0; + DEBUGLOG(5, "ZSTD_decompressStream: detected legacy version v0.%u", legacyVersion); + RETURN_ERROR_IF(zds->staticSize, memory_allocation, + "legacy support is incompatible with static dctx"); + FORWARD_IF_ERROR(ZSTD_initLegacyStream(&zds->legacyContext, + zds->previousLegacyVersion, legacyVersion, + dict, dictSize), ""); + zds->legacyVersion = zds->previousLegacyVersion = legacyVersion; + { size_t const hint = ZSTD_decompressLegacyStream(zds->legacyContext, legacyVersion, output, input); + if (hint==0) zds->streamStage = zdss_init; /* or stay in stage zdss_loadHeader */ + return hint; + } } +#endif + return hSize; /* error */ + } + if (hSize != 0) { /* need more input */ + size_t const toLoad = hSize - zds->lhSize; /* if hSize!=0, hSize > zds->lhSize */ + size_t const remainingInput = (size_t)(iend-ip); + assert(iend >= ip); + if (toLoad > remainingInput) { /* not enough input to load full header */ + if (remainingInput > 0) { + ZSTD_memcpy(zds->headerBuffer + zds->lhSize, ip, remainingInput); + zds->lhSize += remainingInput; + } + input->pos = input->size; + /* check first few bytes */ + FORWARD_IF_ERROR( + ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format), + "First few bytes detected incorrect" ); + /* return hint input size */ + return (MAX((size_t)ZSTD_FRAMEHEADERSIZE_MIN(zds->format), hSize) - zds->lhSize) + ZSTD_blockHeaderSize; /* remaining header bytes + next block header */ + } + assert(ip != NULL); + ZSTD_memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad); zds->lhSize = hSize; ip += toLoad; + break; + } } + + /* check for single-pass mode opportunity */ + if (zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN + && zds->fParams.frameType != ZSTD_skippableFrame + && (U64)(size_t)(oend-op) >= zds->fParams.frameContentSize) { + size_t const cSize = ZSTD_findFrameCompressedSize(istart, (size_t)(iend-istart)); + if (cSize <= (size_t)(iend-istart)) { + /* shortcut : using single-pass mode */ + size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, (size_t)(oend-op), istart, cSize, ZSTD_getDDict(zds)); + if (ZSTD_isError(decompressedSize)) return decompressedSize; + DEBUGLOG(4, "shortcut to single-pass ZSTD_decompress_usingDDict()") + assert(istart != NULL); + ip = istart + cSize; + op = op ? op + decompressedSize : op; /* can occur if frameContentSize = 0 (empty frame) */ + zds->expected = 0; + zds->streamStage = zdss_init; + someMoreWork = 0; + break; + } } + + /* Check output buffer is large enough for ZSTD_odm_stable. */ + if (zds->outBufferMode == ZSTD_bm_stable + && zds->fParams.frameType != ZSTD_skippableFrame + && zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN + && (U64)(size_t)(oend-op) < zds->fParams.frameContentSize) { + RETURN_ERROR(dstSize_tooSmall, "ZSTD_obm_stable passed but ZSTD_outBuffer is too small"); + } + + /* Consume header (see ZSTDds_decodeFrameHeader) */ + DEBUGLOG(4, "Consume header"); + FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(zds, ZSTD_getDDict(zds)), ""); + + if ((MEM_readLE32(zds->headerBuffer) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */ + zds->expected = MEM_readLE32(zds->headerBuffer + ZSTD_FRAMEIDSIZE); + zds->stage = ZSTDds_skipFrame; + } else { + FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(zds, zds->headerBuffer, zds->lhSize), ""); + zds->expected = ZSTD_blockHeaderSize; + zds->stage = ZSTDds_decodeBlockHeader; + } + + /* control buffer memory usage */ + DEBUGLOG(4, "Control max memory usage (%u KB <= max %u KB)", + (U32)(zds->fParams.windowSize >>10), + (U32)(zds->maxWindowSize >> 10) ); + zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN); + RETURN_ERROR_IF(zds->fParams.windowSize > zds->maxWindowSize, + frameParameter_windowTooLarge, ""); + + /* Adapt buffer sizes to frame header instructions */ + { size_t const neededInBuffSize = MAX(zds->fParams.blockSizeMax, 4 /* frame checksum */); + size_t const neededOutBuffSize = zds->outBufferMode == ZSTD_bm_buffered + ? ZSTD_decodingBufferSize_min(zds->fParams.windowSize, zds->fParams.frameContentSize) + : 0; + + ZSTD_DCtx_updateOversizedDuration(zds, neededInBuffSize, neededOutBuffSize); + + { int const tooSmall = (zds->inBuffSize < neededInBuffSize) || (zds->outBuffSize < neededOutBuffSize); + int const tooLarge = ZSTD_DCtx_isOversizedTooLong(zds); + + if (tooSmall || tooLarge) { + size_t const bufferSize = neededInBuffSize + neededOutBuffSize; + DEBUGLOG(4, "inBuff : from %u to %u", + (U32)zds->inBuffSize, (U32)neededInBuffSize); + DEBUGLOG(4, "outBuff : from %u to %u", + (U32)zds->outBuffSize, (U32)neededOutBuffSize); + if (zds->staticSize) { /* static DCtx */ + DEBUGLOG(4, "staticSize : %u", (U32)zds->staticSize); + assert(zds->staticSize >= sizeof(ZSTD_DCtx)); /* controlled at init */ + RETURN_ERROR_IF( + bufferSize > zds->staticSize - sizeof(ZSTD_DCtx), + memory_allocation, ""); + } else { + ZSTD_customFree(zds->inBuff, zds->customMem); + zds->inBuffSize = 0; + zds->outBuffSize = 0; + zds->inBuff = (char*)ZSTD_customMalloc(bufferSize, zds->customMem); + RETURN_ERROR_IF(zds->inBuff == NULL, memory_allocation, ""); + } + zds->inBuffSize = neededInBuffSize; + zds->outBuff = zds->inBuff + zds->inBuffSize; + zds->outBuffSize = neededOutBuffSize; + } } } + zds->streamStage = zdss_read; + ZSTD_FALLTHROUGH; + + case zdss_read: + DEBUGLOG(5, "stage zdss_read"); + { size_t const neededInSize = ZSTD_nextSrcSizeToDecompressWithInputSize(zds, (size_t)(iend - ip)); + DEBUGLOG(5, "neededInSize = %u", (U32)neededInSize); + if (neededInSize==0) { /* end of frame */ + zds->streamStage = zdss_init; + someMoreWork = 0; + break; + } + if ((size_t)(iend-ip) >= neededInSize) { /* decode directly from src */ + FORWARD_IF_ERROR(ZSTD_decompressContinueStream(zds, &op, oend, ip, neededInSize), ""); + assert(ip != NULL); + ip += neededInSize; + /* Function modifies the stage so we must break */ + break; + } } + if (ip==iend) { someMoreWork = 0; break; } /* no more input */ + zds->streamStage = zdss_load; + ZSTD_FALLTHROUGH; + + case zdss_load: + { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds); + size_t const toLoad = neededInSize - zds->inPos; + int const isSkipFrame = ZSTD_isSkipFrame(zds); + size_t loadedSize; + /* At this point we shouldn't be decompressing a block that we can stream. */ + assert(neededInSize == ZSTD_nextSrcSizeToDecompressWithInputSize(zds, (size_t)(iend - ip))); + if (isSkipFrame) { + loadedSize = MIN(toLoad, (size_t)(iend-ip)); + } else { + RETURN_ERROR_IF(toLoad > zds->inBuffSize - zds->inPos, + corruption_detected, + "should never happen"); + loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, (size_t)(iend-ip)); + } + if (loadedSize != 0) { + /* ip may be NULL */ + ip += loadedSize; + zds->inPos += loadedSize; + } + if (loadedSize < toLoad) { someMoreWork = 0; break; } /* not enough input, wait for more */ + + /* decode loaded input */ + zds->inPos = 0; /* input is consumed */ + FORWARD_IF_ERROR(ZSTD_decompressContinueStream(zds, &op, oend, zds->inBuff, neededInSize), ""); + /* Function modifies the stage so we must break */ + break; + } + case zdss_flush: + { + size_t const toFlushSize = zds->outEnd - zds->outStart; + size_t const flushedSize = ZSTD_limitCopy(op, (size_t)(oend-op), zds->outBuff + zds->outStart, toFlushSize); + + op = op ? op + flushedSize : op; + + zds->outStart += flushedSize; + if (flushedSize == toFlushSize) { /* flush completed */ + zds->streamStage = zdss_read; + if ( (zds->outBuffSize < zds->fParams.frameContentSize) + && (zds->outStart + zds->fParams.blockSizeMax > zds->outBuffSize) ) { + DEBUGLOG(5, "restart filling outBuff from beginning (left:%i, needed:%u)", + (int)(zds->outBuffSize - zds->outStart), + (U32)zds->fParams.blockSizeMax); + zds->outStart = zds->outEnd = 0; + } + break; + } } + /* cannot complete flush */ + someMoreWork = 0; + break; + + default: + assert(0); /* impossible */ + RETURN_ERROR(GENERIC, "impossible to reach"); /* some compilers require default to do something */ + } } + + /* result */ + input->pos = (size_t)(ip - (const char*)(input->src)); + output->pos = (size_t)(op - (char*)(output->dst)); + + /* Update the expected output buffer for ZSTD_obm_stable. */ + zds->expectedOutBuffer = *output; + + if ((ip==istart) && (op==ostart)) { /* no forward progress */ + zds->noForwardProgress ++; + if (zds->noForwardProgress >= ZSTD_NO_FORWARD_PROGRESS_MAX) { + RETURN_ERROR_IF(op==oend, noForwardProgress_destFull, ""); + RETURN_ERROR_IF(ip==iend, noForwardProgress_inputEmpty, ""); + assert(0); + } + } else { + zds->noForwardProgress = 0; + } + { size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zds); + if (!nextSrcSizeHint) { /* frame fully decoded */ + if (zds->outEnd == zds->outStart) { /* output fully flushed */ + if (zds->hostageByte) { + if (input->pos >= input->size) { + /* can't release hostage (not present) */ + zds->streamStage = zdss_read; + return 1; + } + input->pos++; /* release hostage */ + } /* zds->hostageByte */ + return 0; + } /* zds->outEnd == zds->outStart */ + if (!zds->hostageByte) { /* output not fully flushed; keep last byte as hostage; will be released when all output is flushed */ + input->pos--; /* note : pos > 0, otherwise, impossible to finish reading last block */ + zds->hostageByte=1; + } + return 1; + } /* nextSrcSizeHint==0 */ + nextSrcSizeHint += ZSTD_blockHeaderSize * (ZSTD_nextInputType(zds) == ZSTDnit_block); /* preload header of next block */ + assert(zds->inPos <= nextSrcSizeHint); + nextSrcSizeHint -= zds->inPos; /* part already loaded*/ + return nextSrcSizeHint; + } +} + +size_t ZSTD_decompressStream_simpleArgs ( + ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, size_t* dstPos, + const void* src, size_t srcSize, size_t* srcPos) +{ + ZSTD_outBuffer output; + ZSTD_inBuffer input; + output.dst = dst; + output.size = dstCapacity; + output.pos = *dstPos; + input.src = src; + input.size = srcSize; + input.pos = *srcPos; + { size_t const cErr = ZSTD_decompressStream(dctx, &output, &input); + *dstPos = output.pos; + *srcPos = input.pos; + return cErr; + } +} diff --git a/lib/zstd/lib/decompress/zstd_decompress_block.c b/lib/zstd/lib/decompress/zstd_decompress_block.c new file mode 100644 index 0000000..09896a9 --- /dev/null +++ b/lib/zstd/lib/decompress/zstd_decompress_block.c @@ -0,0 +1,2192 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +/* zstd_decompress_block : + * this module takes care of decompressing _compressed_ block */ + +/*-******************************************************* +* Dependencies +*********************************************************/ +#include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */ +#include "../common/compiler.h" /* prefetch */ +#include "../common/cpu.h" /* bmi2 */ +#include "../common/mem.h" /* low level memory routines */ +#define FSE_STATIC_LINKING_ONLY +#include "../common/fse.h" +#include "../common/huf.h" +#include "../common/zstd_internal.h" +#include "zstd_decompress_internal.h" /* ZSTD_DCtx */ +#include "zstd_ddict.h" /* ZSTD_DDictDictContent */ +#include "zstd_decompress_block.h" +#include "../common/bits.h" /* ZSTD_highbit32 */ + +/*_******************************************************* +* Macros +**********************************************************/ + +/* These two optional macros force the use one way or another of the two + * ZSTD_decompressSequences implementations. You can't force in both directions + * at the same time. + */ +#if defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \ + defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG) +#error "Cannot force the use of the short and the long ZSTD_decompressSequences variants!" +#endif + + +/*_******************************************************* +* Memory operations +**********************************************************/ +static void ZSTD_copy4(void* dst, const void* src) { ZSTD_memcpy(dst, src, 4); } + + +/*-************************************************************* + * Block decoding + ***************************************************************/ + +/*! ZSTD_getcBlockSize() : + * Provides the size of compressed block from block header `src` */ +size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, + blockProperties_t* bpPtr) +{ + RETURN_ERROR_IF(srcSize < ZSTD_blockHeaderSize, srcSize_wrong, ""); + + { U32 const cBlockHeader = MEM_readLE24(src); + U32 const cSize = cBlockHeader >> 3; + bpPtr->lastBlock = cBlockHeader & 1; + bpPtr->blockType = (blockType_e)((cBlockHeader >> 1) & 3); + bpPtr->origSize = cSize; /* only useful for RLE */ + if (bpPtr->blockType == bt_rle) return 1; + RETURN_ERROR_IF(bpPtr->blockType == bt_reserved, corruption_detected, ""); + return cSize; + } +} + +/* Allocate buffer for literals, either overlapping current dst, or split between dst and litExtraBuffer, or stored entirely within litExtraBuffer */ +static void ZSTD_allocateLiteralsBuffer(ZSTD_DCtx* dctx, void* const dst, const size_t dstCapacity, const size_t litSize, + const streaming_operation streaming, const size_t expectedWriteSize, const unsigned splitImmediately) +{ + if (streaming == not_streaming && dstCapacity > ZSTD_BLOCKSIZE_MAX + WILDCOPY_OVERLENGTH + litSize + WILDCOPY_OVERLENGTH) + { + /* room for litbuffer to fit without read faulting */ + dctx->litBuffer = (BYTE*)dst + ZSTD_BLOCKSIZE_MAX + WILDCOPY_OVERLENGTH; + dctx->litBufferEnd = dctx->litBuffer + litSize; + dctx->litBufferLocation = ZSTD_in_dst; + } + else if (litSize > ZSTD_LITBUFFEREXTRASIZE) + { + /* won't fit in litExtraBuffer, so it will be split between end of dst and extra buffer */ + if (splitImmediately) { + /* won't fit in litExtraBuffer, so it will be split between end of dst and extra buffer */ + dctx->litBuffer = (BYTE*)dst + expectedWriteSize - litSize + ZSTD_LITBUFFEREXTRASIZE - WILDCOPY_OVERLENGTH; + dctx->litBufferEnd = dctx->litBuffer + litSize - ZSTD_LITBUFFEREXTRASIZE; + } + else { + /* initially this will be stored entirely in dst during huffman decoding, it will partially be shifted to litExtraBuffer after */ + dctx->litBuffer = (BYTE*)dst + expectedWriteSize - litSize; + dctx->litBufferEnd = (BYTE*)dst + expectedWriteSize; + } + dctx->litBufferLocation = ZSTD_split; + } + else + { + /* fits entirely within litExtraBuffer, so no split is necessary */ + dctx->litBuffer = dctx->litExtraBuffer; + dctx->litBufferEnd = dctx->litBuffer + litSize; + dctx->litBufferLocation = ZSTD_not_in_dst; + } +} + +/* Hidden declaration for fullbench */ +size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, + const void* src, size_t srcSize, + void* dst, size_t dstCapacity, const streaming_operation streaming); +/*! ZSTD_decodeLiteralsBlock() : + * Where it is possible to do so without being stomped by the output during decompression, the literals block will be stored + * in the dstBuffer. If there is room to do so, it will be stored in full in the excess dst space after where the current + * block will be output. Otherwise it will be stored at the end of the current dst blockspace, with a small portion being + * stored in dctx->litExtraBuffer to help keep it "ahead" of the current output write. + * + * @return : nb of bytes read from src (< srcSize ) + * note : symbol not declared but exposed for fullbench */ +size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, + const void* src, size_t srcSize, /* note : srcSize < BLOCKSIZE */ + void* dst, size_t dstCapacity, const streaming_operation streaming) +{ + DEBUGLOG(5, "ZSTD_decodeLiteralsBlock"); + RETURN_ERROR_IF(srcSize < MIN_CBLOCK_SIZE, corruption_detected, ""); + + { const BYTE* const istart = (const BYTE*) src; + symbolEncodingType_e const litEncType = (symbolEncodingType_e)(istart[0] & 3); + + switch(litEncType) + { + case set_repeat: + DEBUGLOG(5, "set_repeat flag : re-using stats from previous compressed literals block"); + RETURN_ERROR_IF(dctx->litEntropy==0, dictionary_corrupted, ""); + ZSTD_FALLTHROUGH; + + case set_compressed: + RETURN_ERROR_IF(srcSize < 5, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 2; here we need up to 5 for case 3"); + { size_t lhSize, litSize, litCSize; + U32 singleStream=0; + U32 const lhlCode = (istart[0] >> 2) & 3; + U32 const lhc = MEM_readLE32(istart); + size_t hufSuccess; + size_t expectedWriteSize = MIN(ZSTD_BLOCKSIZE_MAX, dstCapacity); + int const flags = 0 + | (ZSTD_DCtx_get_bmi2(dctx) ? HUF_flags_bmi2 : 0) + | (dctx->disableHufAsm ? HUF_flags_disableAsm : 0); + switch(lhlCode) + { + case 0: case 1: default: /* note : default is impossible, since lhlCode into [0..3] */ + /* 2 - 2 - 10 - 10 */ + singleStream = !lhlCode; + lhSize = 3; + litSize = (lhc >> 4) & 0x3FF; + litCSize = (lhc >> 14) & 0x3FF; + break; + case 2: + /* 2 - 2 - 14 - 14 */ + lhSize = 4; + litSize = (lhc >> 4) & 0x3FFF; + litCSize = lhc >> 18; + break; + case 3: + /* 2 - 2 - 18 - 18 */ + lhSize = 5; + litSize = (lhc >> 4) & 0x3FFFF; + litCSize = (lhc >> 22) + ((size_t)istart[4] << 10); + break; + } + RETURN_ERROR_IF(litSize > 0 && dst == NULL, dstSize_tooSmall, "NULL not handled"); + RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected, ""); + if (!singleStream) + RETURN_ERROR_IF(litSize < MIN_LITERALS_FOR_4_STREAMS, literals_headerWrong, + "Not enough literals (%zu) for the 4-streams mode (min %u)", + litSize, MIN_LITERALS_FOR_4_STREAMS); + RETURN_ERROR_IF(litCSize + lhSize > srcSize, corruption_detected, ""); + RETURN_ERROR_IF(expectedWriteSize < litSize , dstSize_tooSmall, ""); + ZSTD_allocateLiteralsBuffer(dctx, dst, dstCapacity, litSize, streaming, expectedWriteSize, 0); + + /* prefetch huffman table if cold */ + if (dctx->ddictIsCold && (litSize > 768 /* heuristic */)) { + PREFETCH_AREA(dctx->HUFptr, sizeof(dctx->entropy.hufTable)); + } + + if (litEncType==set_repeat) { + if (singleStream) { + hufSuccess = HUF_decompress1X_usingDTable( + dctx->litBuffer, litSize, istart+lhSize, litCSize, + dctx->HUFptr, flags); + } else { + assert(litSize >= MIN_LITERALS_FOR_4_STREAMS); + hufSuccess = HUF_decompress4X_usingDTable( + dctx->litBuffer, litSize, istart+lhSize, litCSize, + dctx->HUFptr, flags); + } + } else { + if (singleStream) { +#if defined(HUF_FORCE_DECOMPRESS_X2) + hufSuccess = HUF_decompress1X_DCtx_wksp( + dctx->entropy.hufTable, dctx->litBuffer, litSize, + istart+lhSize, litCSize, dctx->workspace, + sizeof(dctx->workspace), flags); +#else + hufSuccess = HUF_decompress1X1_DCtx_wksp( + dctx->entropy.hufTable, dctx->litBuffer, litSize, + istart+lhSize, litCSize, dctx->workspace, + sizeof(dctx->workspace), flags); +#endif + } else { + hufSuccess = HUF_decompress4X_hufOnly_wksp( + dctx->entropy.hufTable, dctx->litBuffer, litSize, + istart+lhSize, litCSize, dctx->workspace, + sizeof(dctx->workspace), flags); + } + } + if (dctx->litBufferLocation == ZSTD_split) + { + ZSTD_memcpy(dctx->litExtraBuffer, dctx->litBufferEnd - ZSTD_LITBUFFEREXTRASIZE, ZSTD_LITBUFFEREXTRASIZE); + ZSTD_memmove(dctx->litBuffer + ZSTD_LITBUFFEREXTRASIZE - WILDCOPY_OVERLENGTH, dctx->litBuffer, litSize - ZSTD_LITBUFFEREXTRASIZE); + dctx->litBuffer += ZSTD_LITBUFFEREXTRASIZE - WILDCOPY_OVERLENGTH; + dctx->litBufferEnd -= WILDCOPY_OVERLENGTH; + } + + RETURN_ERROR_IF(HUF_isError(hufSuccess), corruption_detected, ""); + + dctx->litPtr = dctx->litBuffer; + dctx->litSize = litSize; + dctx->litEntropy = 1; + if (litEncType==set_compressed) dctx->HUFptr = dctx->entropy.hufTable; + return litCSize + lhSize; + } + + case set_basic: + { size_t litSize, lhSize; + U32 const lhlCode = ((istart[0]) >> 2) & 3; + size_t expectedWriteSize = MIN(ZSTD_BLOCKSIZE_MAX, dstCapacity); + switch(lhlCode) + { + case 0: case 2: default: /* note : default is impossible, since lhlCode into [0..3] */ + lhSize = 1; + litSize = istart[0] >> 3; + break; + case 1: + lhSize = 2; + litSize = MEM_readLE16(istart) >> 4; + break; + case 3: + lhSize = 3; + RETURN_ERROR_IF(srcSize<3, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 2; here we need lhSize = 3"); + litSize = MEM_readLE24(istart) >> 4; + break; + } + + RETURN_ERROR_IF(litSize > 0 && dst == NULL, dstSize_tooSmall, "NULL not handled"); + RETURN_ERROR_IF(expectedWriteSize < litSize, dstSize_tooSmall, ""); + ZSTD_allocateLiteralsBuffer(dctx, dst, dstCapacity, litSize, streaming, expectedWriteSize, 1); + if (lhSize+litSize+WILDCOPY_OVERLENGTH > srcSize) { /* risk reading beyond src buffer with wildcopy */ + RETURN_ERROR_IF(litSize+lhSize > srcSize, corruption_detected, ""); + if (dctx->litBufferLocation == ZSTD_split) + { + ZSTD_memcpy(dctx->litBuffer, istart + lhSize, litSize - ZSTD_LITBUFFEREXTRASIZE); + ZSTD_memcpy(dctx->litExtraBuffer, istart + lhSize + litSize - ZSTD_LITBUFFEREXTRASIZE, ZSTD_LITBUFFEREXTRASIZE); + } + else + { + ZSTD_memcpy(dctx->litBuffer, istart + lhSize, litSize); + } + dctx->litPtr = dctx->litBuffer; + dctx->litSize = litSize; + return lhSize+litSize; + } + /* direct reference into compressed stream */ + dctx->litPtr = istart+lhSize; + dctx->litSize = litSize; + dctx->litBufferEnd = dctx->litPtr + litSize; + dctx->litBufferLocation = ZSTD_not_in_dst; + return lhSize+litSize; + } + + case set_rle: + { U32 const lhlCode = ((istart[0]) >> 2) & 3; + size_t litSize, lhSize; + size_t expectedWriteSize = MIN(ZSTD_BLOCKSIZE_MAX, dstCapacity); + switch(lhlCode) + { + case 0: case 2: default: /* note : default is impossible, since lhlCode into [0..3] */ + lhSize = 1; + litSize = istart[0] >> 3; + break; + case 1: + lhSize = 2; + RETURN_ERROR_IF(srcSize<3, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 2; here we need lhSize+1 = 3"); + litSize = MEM_readLE16(istart) >> 4; + break; + case 3: + lhSize = 3; + RETURN_ERROR_IF(srcSize<4, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 2; here we need lhSize+1 = 4"); + litSize = MEM_readLE24(istart) >> 4; + break; + } + RETURN_ERROR_IF(litSize > 0 && dst == NULL, dstSize_tooSmall, "NULL not handled"); + RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected, ""); + RETURN_ERROR_IF(expectedWriteSize < litSize, dstSize_tooSmall, ""); + ZSTD_allocateLiteralsBuffer(dctx, dst, dstCapacity, litSize, streaming, expectedWriteSize, 1); + if (dctx->litBufferLocation == ZSTD_split) + { + ZSTD_memset(dctx->litBuffer, istart[lhSize], litSize - ZSTD_LITBUFFEREXTRASIZE); + ZSTD_memset(dctx->litExtraBuffer, istart[lhSize], ZSTD_LITBUFFEREXTRASIZE); + } + else + { + ZSTD_memset(dctx->litBuffer, istart[lhSize], litSize); + } + dctx->litPtr = dctx->litBuffer; + dctx->litSize = litSize; + return lhSize+1; + } + default: + RETURN_ERROR(corruption_detected, "impossible"); + } + } +} + +/* Default FSE distribution tables. + * These are pre-calculated FSE decoding tables using default distributions as defined in specification : + * https://github.com/facebook/zstd/blob/release/doc/zstd_compression_format.md#default-distributions + * They were generated programmatically with following method : + * - start from default distributions, present in /lib/common/zstd_internal.h + * - generate tables normally, using ZSTD_buildFSETable() + * - printout the content of tables + * - pretify output, report below, test with fuzzer to ensure it's correct */ + +/* Default FSE distribution table for Literal Lengths */ +static const ZSTD_seqSymbol LL_defaultDTable[(1<tableLog = 0; + DTableH->fastMode = 0; + + cell->nbBits = 0; + cell->nextState = 0; + assert(nbAddBits < 255); + cell->nbAdditionalBits = nbAddBits; + cell->baseValue = baseValue; +} + + +/* ZSTD_buildFSETable() : + * generate FSE decoding table for one symbol (ll, ml or off) + * cannot fail if input is valid => + * all inputs are presumed validated at this stage */ +FORCE_INLINE_TEMPLATE +void ZSTD_buildFSETable_body(ZSTD_seqSymbol* dt, + const short* normalizedCounter, unsigned maxSymbolValue, + const U32* baseValue, const U8* nbAdditionalBits, + unsigned tableLog, void* wksp, size_t wkspSize) +{ + ZSTD_seqSymbol* const tableDecode = dt+1; + U32 const maxSV1 = maxSymbolValue + 1; + U32 const tableSize = 1 << tableLog; + + U16* symbolNext = (U16*)wksp; + BYTE* spread = (BYTE*)(symbolNext + MaxSeq + 1); + U32 highThreshold = tableSize - 1; + + + /* Sanity Checks */ + assert(maxSymbolValue <= MaxSeq); + assert(tableLog <= MaxFSELog); + assert(wkspSize >= ZSTD_BUILD_FSE_TABLE_WKSP_SIZE); + (void)wkspSize; + /* Init, lay down lowprob symbols */ + { ZSTD_seqSymbol_header DTableH; + DTableH.tableLog = tableLog; + DTableH.fastMode = 1; + { S16 const largeLimit= (S16)(1 << (tableLog-1)); + U32 s; + for (s=0; s= largeLimit) DTableH.fastMode=0; + assert(normalizedCounter[s]>=0); + symbolNext[s] = (U16)normalizedCounter[s]; + } } } + ZSTD_memcpy(dt, &DTableH, sizeof(DTableH)); + } + + /* Spread symbols */ + assert(tableSize <= 512); + /* Specialized symbol spreading for the case when there are + * no low probability (-1 count) symbols. When compressing + * small blocks we avoid low probability symbols to hit this + * case, since header decoding speed matters more. + */ + if (highThreshold == tableSize - 1) { + size_t const tableMask = tableSize-1; + size_t const step = FSE_TABLESTEP(tableSize); + /* First lay down the symbols in order. + * We use a uint64_t to lay down 8 bytes at a time. This reduces branch + * misses since small blocks generally have small table logs, so nearly + * all symbols have counts <= 8. We ensure we have 8 bytes at the end of + * our buffer to handle the over-write. + */ + { + U64 const add = 0x0101010101010101ull; + size_t pos = 0; + U64 sv = 0; + U32 s; + for (s=0; s=0); + pos += (size_t)n; + } + } + /* Now we spread those positions across the table. + * The benefit of doing it in two stages is that we avoid the + * variable size inner loop, which caused lots of branch misses. + * Now we can run through all the positions without any branch misses. + * We unroll the loop twice, since that is what empirically worked best. + */ + { + size_t position = 0; + size_t s; + size_t const unroll = 2; + assert(tableSize % unroll == 0); /* FSE_MIN_TABLELOG is 5 */ + for (s = 0; s < (size_t)tableSize; s += unroll) { + size_t u; + for (u = 0; u < unroll; ++u) { + size_t const uPosition = (position + (u * step)) & tableMask; + tableDecode[uPosition].baseValue = spread[s + u]; + } + position = (position + (unroll * step)) & tableMask; + } + assert(position == 0); + } + } else { + U32 const tableMask = tableSize-1; + U32 const step = FSE_TABLESTEP(tableSize); + U32 s, position = 0; + for (s=0; s highThreshold)) position = (position + step) & tableMask; /* lowprob area */ + } } + assert(position == 0); /* position must reach all cells once, otherwise normalizedCounter is incorrect */ + } + + /* Build Decoding table */ + { + U32 u; + for (u=0; u max, corruption_detected, ""); + { U32 const symbol = *(const BYTE*)src; + U32 const baseline = baseValue[symbol]; + U8 const nbBits = nbAdditionalBits[symbol]; + ZSTD_buildSeqTable_rle(DTableSpace, baseline, nbBits); + } + *DTablePtr = DTableSpace; + return 1; + case set_basic : + *DTablePtr = defaultTable; + return 0; + case set_repeat: + RETURN_ERROR_IF(!flagRepeatTable, corruption_detected, ""); + /* prefetch FSE table if used */ + if (ddictIsCold && (nbSeq > 24 /* heuristic */)) { + const void* const pStart = *DTablePtr; + size_t const pSize = sizeof(ZSTD_seqSymbol) * (SEQSYMBOL_TABLE_SIZE(maxLog)); + PREFETCH_AREA(pStart, pSize); + } + return 0; + case set_compressed : + { unsigned tableLog; + S16 norm[MaxSeq+1]; + size_t const headerSize = FSE_readNCount(norm, &max, &tableLog, src, srcSize); + RETURN_ERROR_IF(FSE_isError(headerSize), corruption_detected, ""); + RETURN_ERROR_IF(tableLog > maxLog, corruption_detected, ""); + ZSTD_buildFSETable(DTableSpace, norm, max, baseValue, nbAdditionalBits, tableLog, wksp, wkspSize, bmi2); + *DTablePtr = DTableSpace; + return headerSize; + } + default : + assert(0); + RETURN_ERROR(GENERIC, "impossible"); + } +} + +size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, + const void* src, size_t srcSize) +{ + const BYTE* const istart = (const BYTE*)src; + const BYTE* const iend = istart + srcSize; + const BYTE* ip = istart; + int nbSeq; + DEBUGLOG(5, "ZSTD_decodeSeqHeaders"); + + /* check */ + RETURN_ERROR_IF(srcSize < MIN_SEQUENCES_SIZE, srcSize_wrong, ""); + + /* SeqHead */ + nbSeq = *ip++; + if (!nbSeq) { + *nbSeqPtr=0; + RETURN_ERROR_IF(srcSize != 1, srcSize_wrong, ""); + return 1; + } + if (nbSeq > 0x7F) { + if (nbSeq == 0xFF) { + RETURN_ERROR_IF(ip+2 > iend, srcSize_wrong, ""); + nbSeq = MEM_readLE16(ip) + LONGNBSEQ; + ip+=2; + } else { + RETURN_ERROR_IF(ip >= iend, srcSize_wrong, ""); + nbSeq = ((nbSeq-0x80)<<8) + *ip++; + } + } + *nbSeqPtr = nbSeq; + + /* FSE table descriptors */ + RETURN_ERROR_IF(ip+1 > iend, srcSize_wrong, ""); /* minimum possible size: 1 byte for symbol encoding types */ + { symbolEncodingType_e const LLtype = (symbolEncodingType_e)(*ip >> 6); + symbolEncodingType_e const OFtype = (symbolEncodingType_e)((*ip >> 4) & 3); + symbolEncodingType_e const MLtype = (symbolEncodingType_e)((*ip >> 2) & 3); + ip++; + + /* Build DTables */ + { size_t const llhSize = ZSTD_buildSeqTable(dctx->entropy.LLTable, &dctx->LLTptr, + LLtype, MaxLL, LLFSELog, + ip, iend-ip, + LL_base, LL_bits, + LL_defaultDTable, dctx->fseEntropy, + dctx->ddictIsCold, nbSeq, + dctx->workspace, sizeof(dctx->workspace), + ZSTD_DCtx_get_bmi2(dctx)); + RETURN_ERROR_IF(ZSTD_isError(llhSize), corruption_detected, "ZSTD_buildSeqTable failed"); + ip += llhSize; + } + + { size_t const ofhSize = ZSTD_buildSeqTable(dctx->entropy.OFTable, &dctx->OFTptr, + OFtype, MaxOff, OffFSELog, + ip, iend-ip, + OF_base, OF_bits, + OF_defaultDTable, dctx->fseEntropy, + dctx->ddictIsCold, nbSeq, + dctx->workspace, sizeof(dctx->workspace), + ZSTD_DCtx_get_bmi2(dctx)); + RETURN_ERROR_IF(ZSTD_isError(ofhSize), corruption_detected, "ZSTD_buildSeqTable failed"); + ip += ofhSize; + } + + { size_t const mlhSize = ZSTD_buildSeqTable(dctx->entropy.MLTable, &dctx->MLTptr, + MLtype, MaxML, MLFSELog, + ip, iend-ip, + ML_base, ML_bits, + ML_defaultDTable, dctx->fseEntropy, + dctx->ddictIsCold, nbSeq, + dctx->workspace, sizeof(dctx->workspace), + ZSTD_DCtx_get_bmi2(dctx)); + RETURN_ERROR_IF(ZSTD_isError(mlhSize), corruption_detected, "ZSTD_buildSeqTable failed"); + ip += mlhSize; + } + } + + return ip-istart; +} + + +typedef struct { + size_t litLength; + size_t matchLength; + size_t offset; +} seq_t; + +typedef struct { + size_t state; + const ZSTD_seqSymbol* table; +} ZSTD_fseState; + +typedef struct { + BIT_DStream_t DStream; + ZSTD_fseState stateLL; + ZSTD_fseState stateOffb; + ZSTD_fseState stateML; + size_t prevOffset[ZSTD_REP_NUM]; +} seqState_t; + +/*! ZSTD_overlapCopy8() : + * Copies 8 bytes from ip to op and updates op and ip where ip <= op. + * If the offset is < 8 then the offset is spread to at least 8 bytes. + * + * Precondition: *ip <= *op + * Postcondition: *op - *op >= 8 + */ +HINT_INLINE void ZSTD_overlapCopy8(BYTE** op, BYTE const** ip, size_t offset) { + assert(*ip <= *op); + if (offset < 8) { + /* close range match, overlap */ + static const U32 dec32table[] = { 0, 1, 2, 1, 4, 4, 4, 4 }; /* added */ + static const int dec64table[] = { 8, 8, 8, 7, 8, 9,10,11 }; /* subtracted */ + int const sub2 = dec64table[offset]; + (*op)[0] = (*ip)[0]; + (*op)[1] = (*ip)[1]; + (*op)[2] = (*ip)[2]; + (*op)[3] = (*ip)[3]; + *ip += dec32table[offset]; + ZSTD_copy4(*op+4, *ip); + *ip -= sub2; + } else { + ZSTD_copy8(*op, *ip); + } + *ip += 8; + *op += 8; + assert(*op - *ip >= 8); +} + +/*! ZSTD_safecopy() : + * Specialized version of memcpy() that is allowed to READ up to WILDCOPY_OVERLENGTH past the input buffer + * and write up to 16 bytes past oend_w (op >= oend_w is allowed). + * This function is only called in the uncommon case where the sequence is near the end of the block. It + * should be fast for a single long sequence, but can be slow for several short sequences. + * + * @param ovtype controls the overlap detection + * - ZSTD_no_overlap: The source and destination are guaranteed to be at least WILDCOPY_VECLEN bytes apart. + * - ZSTD_overlap_src_before_dst: The src and dst may overlap and may be any distance apart. + * The src buffer must be before the dst buffer. + */ +static void ZSTD_safecopy(BYTE* op, const BYTE* const oend_w, BYTE const* ip, ptrdiff_t length, ZSTD_overlap_e ovtype) { + ptrdiff_t const diff = op - ip; + BYTE* const oend = op + length; + + assert((ovtype == ZSTD_no_overlap && (diff <= -8 || diff >= 8 || op >= oend_w)) || + (ovtype == ZSTD_overlap_src_before_dst && diff >= 0)); + + if (length < 8) { + /* Handle short lengths. */ + while (op < oend) *op++ = *ip++; + return; + } + if (ovtype == ZSTD_overlap_src_before_dst) { + /* Copy 8 bytes and ensure the offset >= 8 when there can be overlap. */ + assert(length >= 8); + ZSTD_overlapCopy8(&op, &ip, diff); + length -= 8; + assert(op - ip >= 8); + assert(op <= oend); + } + + if (oend <= oend_w) { + /* No risk of overwrite. */ + ZSTD_wildcopy(op, ip, length, ovtype); + return; + } + if (op <= oend_w) { + /* Wildcopy until we get close to the end. */ + assert(oend > oend_w); + ZSTD_wildcopy(op, ip, oend_w - op, ovtype); + ip += oend_w - op; + op += oend_w - op; + } + /* Handle the leftovers. */ + while (op < oend) *op++ = *ip++; +} + +/* ZSTD_safecopyDstBeforeSrc(): + * This version allows overlap with dst before src, or handles the non-overlap case with dst after src + * Kept separate from more common ZSTD_safecopy case to avoid performance impact to the safecopy common case */ +static void ZSTD_safecopyDstBeforeSrc(BYTE* op, BYTE const* ip, ptrdiff_t length) { + ptrdiff_t const diff = op - ip; + BYTE* const oend = op + length; + + if (length < 8 || diff > -8) { + /* Handle short lengths, close overlaps, and dst not before src. */ + while (op < oend) *op++ = *ip++; + return; + } + + if (op <= oend - WILDCOPY_OVERLENGTH && diff < -WILDCOPY_VECLEN) { + ZSTD_wildcopy(op, ip, oend - WILDCOPY_OVERLENGTH - op, ZSTD_no_overlap); + ip += oend - WILDCOPY_OVERLENGTH - op; + op += oend - WILDCOPY_OVERLENGTH - op; + } + + /* Handle the leftovers. */ + while (op < oend) *op++ = *ip++; +} + +/* ZSTD_execSequenceEnd(): + * This version handles cases that are near the end of the output buffer. It requires + * more careful checks to make sure there is no overflow. By separating out these hard + * and unlikely cases, we can speed up the common cases. + * + * NOTE: This function needs to be fast for a single long sequence, but doesn't need + * to be optimized for many small sequences, since those fall into ZSTD_execSequence(). + */ +FORCE_NOINLINE +size_t ZSTD_execSequenceEnd(BYTE* op, + BYTE* const oend, seq_t sequence, + const BYTE** litPtr, const BYTE* const litLimit, + const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) +{ + BYTE* const oLitEnd = op + sequence.litLength; + size_t const sequenceLength = sequence.litLength + sequence.matchLength; + const BYTE* const iLitEnd = *litPtr + sequence.litLength; + const BYTE* match = oLitEnd - sequence.offset; + BYTE* const oend_w = oend - WILDCOPY_OVERLENGTH; + + /* bounds checks : careful of address space overflow in 32-bit mode */ + RETURN_ERROR_IF(sequenceLength > (size_t)(oend - op), dstSize_tooSmall, "last match must fit within dstBuffer"); + RETURN_ERROR_IF(sequence.litLength > (size_t)(litLimit - *litPtr), corruption_detected, "try to read beyond literal buffer"); + assert(op < op + sequenceLength); + assert(oLitEnd < op + sequenceLength); + + /* copy literals */ + ZSTD_safecopy(op, oend_w, *litPtr, sequence.litLength, ZSTD_no_overlap); + op = oLitEnd; + *litPtr = iLitEnd; + + /* copy Match */ + if (sequence.offset > (size_t)(oLitEnd - prefixStart)) { + /* offset beyond prefix */ + RETURN_ERROR_IF(sequence.offset > (size_t)(oLitEnd - virtualStart), corruption_detected, ""); + match = dictEnd - (prefixStart - match); + if (match + sequence.matchLength <= dictEnd) { + ZSTD_memmove(oLitEnd, match, sequence.matchLength); + return sequenceLength; + } + /* span extDict & currentPrefixSegment */ + { size_t const length1 = dictEnd - match; + ZSTD_memmove(oLitEnd, match, length1); + op = oLitEnd + length1; + sequence.matchLength -= length1; + match = prefixStart; + } + } + ZSTD_safecopy(op, oend_w, match, sequence.matchLength, ZSTD_overlap_src_before_dst); + return sequenceLength; +} + +/* ZSTD_execSequenceEndSplitLitBuffer(): + * This version is intended to be used during instances where the litBuffer is still split. It is kept separate to avoid performance impact for the good case. + */ +FORCE_NOINLINE +size_t ZSTD_execSequenceEndSplitLitBuffer(BYTE* op, + BYTE* const oend, const BYTE* const oend_w, seq_t sequence, + const BYTE** litPtr, const BYTE* const litLimit, + const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) +{ + BYTE* const oLitEnd = op + sequence.litLength; + size_t const sequenceLength = sequence.litLength + sequence.matchLength; + const BYTE* const iLitEnd = *litPtr + sequence.litLength; + const BYTE* match = oLitEnd - sequence.offset; + + + /* bounds checks : careful of address space overflow in 32-bit mode */ + RETURN_ERROR_IF(sequenceLength > (size_t)(oend - op), dstSize_tooSmall, "last match must fit within dstBuffer"); + RETURN_ERROR_IF(sequence.litLength > (size_t)(litLimit - *litPtr), corruption_detected, "try to read beyond literal buffer"); + assert(op < op + sequenceLength); + assert(oLitEnd < op + sequenceLength); + + /* copy literals */ + RETURN_ERROR_IF(op > *litPtr && op < *litPtr + sequence.litLength, dstSize_tooSmall, "output should not catch up to and overwrite literal buffer"); + ZSTD_safecopyDstBeforeSrc(op, *litPtr, sequence.litLength); + op = oLitEnd; + *litPtr = iLitEnd; + + /* copy Match */ + if (sequence.offset > (size_t)(oLitEnd - prefixStart)) { + /* offset beyond prefix */ + RETURN_ERROR_IF(sequence.offset > (size_t)(oLitEnd - virtualStart), corruption_detected, ""); + match = dictEnd - (prefixStart - match); + if (match + sequence.matchLength <= dictEnd) { + ZSTD_memmove(oLitEnd, match, sequence.matchLength); + return sequenceLength; + } + /* span extDict & currentPrefixSegment */ + { size_t const length1 = dictEnd - match; + ZSTD_memmove(oLitEnd, match, length1); + op = oLitEnd + length1; + sequence.matchLength -= length1; + match = prefixStart; + } + } + ZSTD_safecopy(op, oend_w, match, sequence.matchLength, ZSTD_overlap_src_before_dst); + return sequenceLength; +} + +HINT_INLINE +size_t ZSTD_execSequence(BYTE* op, + BYTE* const oend, seq_t sequence, + const BYTE** litPtr, const BYTE* const litLimit, + const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) +{ + BYTE* const oLitEnd = op + sequence.litLength; + size_t const sequenceLength = sequence.litLength + sequence.matchLength; + BYTE* const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */ + BYTE* const oend_w = oend - WILDCOPY_OVERLENGTH; /* risk : address space underflow on oend=NULL */ + const BYTE* const iLitEnd = *litPtr + sequence.litLength; + const BYTE* match = oLitEnd - sequence.offset; + + assert(op != NULL /* Precondition */); + assert(oend_w < oend /* No underflow */); + +#if defined(__aarch64__) + /* prefetch sequence starting from match that will be used for copy later */ + PREFETCH_L1(match); +#endif + /* Handle edge cases in a slow path: + * - Read beyond end of literals + * - Match end is within WILDCOPY_OVERLIMIT of oend + * - 32-bit mode and the match length overflows + */ + if (UNLIKELY( + iLitEnd > litLimit || + oMatchEnd > oend_w || + (MEM_32bits() && (size_t)(oend - op) < sequenceLength + WILDCOPY_OVERLENGTH))) + return ZSTD_execSequenceEnd(op, oend, sequence, litPtr, litLimit, prefixStart, virtualStart, dictEnd); + + /* Assumptions (everything else goes into ZSTD_execSequenceEnd()) */ + assert(op <= oLitEnd /* No overflow */); + assert(oLitEnd < oMatchEnd /* Non-zero match & no overflow */); + assert(oMatchEnd <= oend /* No underflow */); + assert(iLitEnd <= litLimit /* Literal length is in bounds */); + assert(oLitEnd <= oend_w /* Can wildcopy literals */); + assert(oMatchEnd <= oend_w /* Can wildcopy matches */); + + /* Copy Literals: + * Split out litLength <= 16 since it is nearly always true. +1.6% on gcc-9. + * We likely don't need the full 32-byte wildcopy. + */ + assert(WILDCOPY_OVERLENGTH >= 16); + ZSTD_copy16(op, (*litPtr)); + if (UNLIKELY(sequence.litLength > 16)) { + ZSTD_wildcopy(op + 16, (*litPtr) + 16, sequence.litLength - 16, ZSTD_no_overlap); + } + op = oLitEnd; + *litPtr = iLitEnd; /* update for next sequence */ + + /* Copy Match */ + if (sequence.offset > (size_t)(oLitEnd - prefixStart)) { + /* offset beyond prefix -> go into extDict */ + RETURN_ERROR_IF(UNLIKELY(sequence.offset > (size_t)(oLitEnd - virtualStart)), corruption_detected, ""); + match = dictEnd + (match - prefixStart); + if (match + sequence.matchLength <= dictEnd) { + ZSTD_memmove(oLitEnd, match, sequence.matchLength); + return sequenceLength; + } + /* span extDict & currentPrefixSegment */ + { size_t const length1 = dictEnd - match; + ZSTD_memmove(oLitEnd, match, length1); + op = oLitEnd + length1; + sequence.matchLength -= length1; + match = prefixStart; + } + } + /* Match within prefix of 1 or more bytes */ + assert(op <= oMatchEnd); + assert(oMatchEnd <= oend_w); + assert(match >= prefixStart); + assert(sequence.matchLength >= 1); + + /* Nearly all offsets are >= WILDCOPY_VECLEN bytes, which means we can use wildcopy + * without overlap checking. + */ + if (LIKELY(sequence.offset >= WILDCOPY_VECLEN)) { + /* We bet on a full wildcopy for matches, since we expect matches to be + * longer than literals (in general). In silesia, ~10% of matches are longer + * than 16 bytes. + */ + ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength, ZSTD_no_overlap); + return sequenceLength; + } + assert(sequence.offset < WILDCOPY_VECLEN); + + /* Copy 8 bytes and spread the offset to be >= 8. */ + ZSTD_overlapCopy8(&op, &match, sequence.offset); + + /* If the match length is > 8 bytes, then continue with the wildcopy. */ + if (sequence.matchLength > 8) { + assert(op < oMatchEnd); + ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength - 8, ZSTD_overlap_src_before_dst); + } + return sequenceLength; +} + +HINT_INLINE +size_t ZSTD_execSequenceSplitLitBuffer(BYTE* op, + BYTE* const oend, const BYTE* const oend_w, seq_t sequence, + const BYTE** litPtr, const BYTE* const litLimit, + const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) +{ + BYTE* const oLitEnd = op + sequence.litLength; + size_t const sequenceLength = sequence.litLength + sequence.matchLength; + BYTE* const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */ + const BYTE* const iLitEnd = *litPtr + sequence.litLength; + const BYTE* match = oLitEnd - sequence.offset; + + assert(op != NULL /* Precondition */); + assert(oend_w < oend /* No underflow */); + /* Handle edge cases in a slow path: + * - Read beyond end of literals + * - Match end is within WILDCOPY_OVERLIMIT of oend + * - 32-bit mode and the match length overflows + */ + if (UNLIKELY( + iLitEnd > litLimit || + oMatchEnd > oend_w || + (MEM_32bits() && (size_t)(oend - op) < sequenceLength + WILDCOPY_OVERLENGTH))) + return ZSTD_execSequenceEndSplitLitBuffer(op, oend, oend_w, sequence, litPtr, litLimit, prefixStart, virtualStart, dictEnd); + + /* Assumptions (everything else goes into ZSTD_execSequenceEnd()) */ + assert(op <= oLitEnd /* No overflow */); + assert(oLitEnd < oMatchEnd /* Non-zero match & no overflow */); + assert(oMatchEnd <= oend /* No underflow */); + assert(iLitEnd <= litLimit /* Literal length is in bounds */); + assert(oLitEnd <= oend_w /* Can wildcopy literals */); + assert(oMatchEnd <= oend_w /* Can wildcopy matches */); + + /* Copy Literals: + * Split out litLength <= 16 since it is nearly always true. +1.6% on gcc-9. + * We likely don't need the full 32-byte wildcopy. + */ + assert(WILDCOPY_OVERLENGTH >= 16); + ZSTD_copy16(op, (*litPtr)); + if (UNLIKELY(sequence.litLength > 16)) { + ZSTD_wildcopy(op+16, (*litPtr)+16, sequence.litLength-16, ZSTD_no_overlap); + } + op = oLitEnd; + *litPtr = iLitEnd; /* update for next sequence */ + + /* Copy Match */ + if (sequence.offset > (size_t)(oLitEnd - prefixStart)) { + /* offset beyond prefix -> go into extDict */ + RETURN_ERROR_IF(UNLIKELY(sequence.offset > (size_t)(oLitEnd - virtualStart)), corruption_detected, ""); + match = dictEnd + (match - prefixStart); + if (match + sequence.matchLength <= dictEnd) { + ZSTD_memmove(oLitEnd, match, sequence.matchLength); + return sequenceLength; + } + /* span extDict & currentPrefixSegment */ + { size_t const length1 = dictEnd - match; + ZSTD_memmove(oLitEnd, match, length1); + op = oLitEnd + length1; + sequence.matchLength -= length1; + match = prefixStart; + } } + /* Match within prefix of 1 or more bytes */ + assert(op <= oMatchEnd); + assert(oMatchEnd <= oend_w); + assert(match >= prefixStart); + assert(sequence.matchLength >= 1); + + /* Nearly all offsets are >= WILDCOPY_VECLEN bytes, which means we can use wildcopy + * without overlap checking. + */ + if (LIKELY(sequence.offset >= WILDCOPY_VECLEN)) { + /* We bet on a full wildcopy for matches, since we expect matches to be + * longer than literals (in general). In silesia, ~10% of matches are longer + * than 16 bytes. + */ + ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength, ZSTD_no_overlap); + return sequenceLength; + } + assert(sequence.offset < WILDCOPY_VECLEN); + + /* Copy 8 bytes and spread the offset to be >= 8. */ + ZSTD_overlapCopy8(&op, &match, sequence.offset); + + /* If the match length is > 8 bytes, then continue with the wildcopy. */ + if (sequence.matchLength > 8) { + assert(op < oMatchEnd); + ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength-8, ZSTD_overlap_src_before_dst); + } + return sequenceLength; +} + + +static void +ZSTD_initFseState(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, const ZSTD_seqSymbol* dt) +{ + const void* ptr = dt; + const ZSTD_seqSymbol_header* const DTableH = (const ZSTD_seqSymbol_header*)ptr; + DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog); + DEBUGLOG(6, "ZSTD_initFseState : val=%u using %u bits", + (U32)DStatePtr->state, DTableH->tableLog); + BIT_reloadDStream(bitD); + DStatePtr->table = dt + 1; +} + +FORCE_INLINE_TEMPLATE void +ZSTD_updateFseStateWithDInfo(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, U16 nextState, U32 nbBits) +{ + size_t const lowBits = BIT_readBits(bitD, nbBits); + DStatePtr->state = nextState + lowBits; +} + +/* We need to add at most (ZSTD_WINDOWLOG_MAX_32 - 1) bits to read the maximum + * offset bits. But we can only read at most STREAM_ACCUMULATOR_MIN_32 + * bits before reloading. This value is the maximum number of bytes we read + * after reloading when we are decoding long offsets. + */ +#define LONG_OFFSETS_MAX_EXTRA_BITS_32 \ + (ZSTD_WINDOWLOG_MAX_32 > STREAM_ACCUMULATOR_MIN_32 \ + ? ZSTD_WINDOWLOG_MAX_32 - STREAM_ACCUMULATOR_MIN_32 \ + : 0) + +typedef enum { ZSTD_lo_isRegularOffset, ZSTD_lo_isLongOffset=1 } ZSTD_longOffset_e; + +FORCE_INLINE_TEMPLATE seq_t +ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets) +{ + seq_t seq; + /* + * ZSTD_seqSymbol is a structure with a total of 64 bits wide. So it can be + * loaded in one operation and extracted its fields by simply shifting or + * bit-extracting on aarch64. + * GCC doesn't recognize this and generates more unnecessary ldr/ldrb/ldrh + * operations that cause performance drop. This can be avoided by using this + * ZSTD_memcpy hack. + */ +#if defined(__aarch64__) && (defined(__GNUC__) && !defined(__clang__)) + ZSTD_seqSymbol llDInfoS, mlDInfoS, ofDInfoS; + ZSTD_seqSymbol* const llDInfo = &llDInfoS; + ZSTD_seqSymbol* const mlDInfo = &mlDInfoS; + ZSTD_seqSymbol* const ofDInfo = &ofDInfoS; + ZSTD_memcpy(llDInfo, seqState->stateLL.table + seqState->stateLL.state, sizeof(ZSTD_seqSymbol)); + ZSTD_memcpy(mlDInfo, seqState->stateML.table + seqState->stateML.state, sizeof(ZSTD_seqSymbol)); + ZSTD_memcpy(ofDInfo, seqState->stateOffb.table + seqState->stateOffb.state, sizeof(ZSTD_seqSymbol)); +#else + const ZSTD_seqSymbol* const llDInfo = seqState->stateLL.table + seqState->stateLL.state; + const ZSTD_seqSymbol* const mlDInfo = seqState->stateML.table + seqState->stateML.state; + const ZSTD_seqSymbol* const ofDInfo = seqState->stateOffb.table + seqState->stateOffb.state; +#endif + seq.matchLength = mlDInfo->baseValue; + seq.litLength = llDInfo->baseValue; + { U32 const ofBase = ofDInfo->baseValue; + BYTE const llBits = llDInfo->nbAdditionalBits; + BYTE const mlBits = mlDInfo->nbAdditionalBits; + BYTE const ofBits = ofDInfo->nbAdditionalBits; + BYTE const totalBits = llBits+mlBits+ofBits; + + U16 const llNext = llDInfo->nextState; + U16 const mlNext = mlDInfo->nextState; + U16 const ofNext = ofDInfo->nextState; + U32 const llnbBits = llDInfo->nbBits; + U32 const mlnbBits = mlDInfo->nbBits; + U32 const ofnbBits = ofDInfo->nbBits; + + assert(llBits <= MaxLLBits); + assert(mlBits <= MaxMLBits); + assert(ofBits <= MaxOff); + /* + * As gcc has better branch and block analyzers, sometimes it is only + * valuable to mark likeliness for clang, it gives around 3-4% of + * performance. + */ + + /* sequence */ + { size_t offset; + if (ofBits > 1) { + ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1); + ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5); + ZSTD_STATIC_ASSERT(STREAM_ACCUMULATOR_MIN_32 > LONG_OFFSETS_MAX_EXTRA_BITS_32); + ZSTD_STATIC_ASSERT(STREAM_ACCUMULATOR_MIN_32 - LONG_OFFSETS_MAX_EXTRA_BITS_32 >= MaxMLBits); + if (MEM_32bits() && longOffsets && (ofBits >= STREAM_ACCUMULATOR_MIN_32)) { + /* Always read extra bits, this keeps the logic simple, + * avoids branches, and avoids accidentally reading 0 bits. + */ + U32 const extraBits = LONG_OFFSETS_MAX_EXTRA_BITS_32; + offset = ofBase + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits); + BIT_reloadDStream(&seqState->DStream); + offset += BIT_readBitsFast(&seqState->DStream, extraBits); + } else { + offset = ofBase + BIT_readBitsFast(&seqState->DStream, ofBits/*>0*/); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */ + if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); + } + seqState->prevOffset[2] = seqState->prevOffset[1]; + seqState->prevOffset[1] = seqState->prevOffset[0]; + seqState->prevOffset[0] = offset; + } else { + U32 const ll0 = (llDInfo->baseValue == 0); + if (LIKELY((ofBits == 0))) { + offset = seqState->prevOffset[ll0]; + seqState->prevOffset[1] = seqState->prevOffset[!ll0]; + seqState->prevOffset[0] = offset; + } else { + offset = ofBase + ll0 + BIT_readBitsFast(&seqState->DStream, 1); + { size_t temp = (offset==3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset]; + temp += !temp; /* 0 is not valid; input is corrupted; force offset to 1 */ + if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1]; + seqState->prevOffset[1] = seqState->prevOffset[0]; + seqState->prevOffset[0] = offset = temp; + } } } + seq.offset = offset; + } + + if (mlBits > 0) + seq.matchLength += BIT_readBitsFast(&seqState->DStream, mlBits/*>0*/); + + if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32)) + BIT_reloadDStream(&seqState->DStream); + if (MEM_64bits() && UNLIKELY(totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog))) + BIT_reloadDStream(&seqState->DStream); + /* Ensure there are enough bits to read the rest of data in 64-bit mode. */ + ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64); + + if (llBits > 0) + seq.litLength += BIT_readBitsFast(&seqState->DStream, llBits/*>0*/); + + if (MEM_32bits()) + BIT_reloadDStream(&seqState->DStream); + + DEBUGLOG(6, "seq: litL=%u, matchL=%u, offset=%u", + (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset); + + ZSTD_updateFseStateWithDInfo(&seqState->stateLL, &seqState->DStream, llNext, llnbBits); /* <= 9 bits */ + ZSTD_updateFseStateWithDInfo(&seqState->stateML, &seqState->DStream, mlNext, mlnbBits); /* <= 9 bits */ + if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */ + ZSTD_updateFseStateWithDInfo(&seqState->stateOffb, &seqState->DStream, ofNext, ofnbBits); /* <= 8 bits */ + } + + return seq; +} + +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION +MEM_STATIC int ZSTD_dictionaryIsActive(ZSTD_DCtx const* dctx, BYTE const* prefixStart, BYTE const* oLitEnd) +{ + size_t const windowSize = dctx->fParams.windowSize; + /* No dictionary used. */ + if (dctx->dictContentEndForFuzzing == NULL) return 0; + /* Dictionary is our prefix. */ + if (prefixStart == dctx->dictContentBeginForFuzzing) return 1; + /* Dictionary is not our ext-dict. */ + if (dctx->dictEnd != dctx->dictContentEndForFuzzing) return 0; + /* Dictionary is not within our window size. */ + if ((size_t)(oLitEnd - prefixStart) >= windowSize) return 0; + /* Dictionary is active. */ + return 1; +} + +MEM_STATIC void ZSTD_assertValidSequence( + ZSTD_DCtx const* dctx, + BYTE const* op, BYTE const* oend, + seq_t const seq, + BYTE const* prefixStart, BYTE const* virtualStart) +{ +#if DEBUGLEVEL >= 1 + size_t const windowSize = dctx->fParams.windowSize; + size_t const sequenceSize = seq.litLength + seq.matchLength; + BYTE const* const oLitEnd = op + seq.litLength; + DEBUGLOG(6, "Checking sequence: litL=%u matchL=%u offset=%u", + (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset); + assert(op <= oend); + assert((size_t)(oend - op) >= sequenceSize); + assert(sequenceSize <= ZSTD_BLOCKSIZE_MAX); + if (ZSTD_dictionaryIsActive(dctx, prefixStart, oLitEnd)) { + size_t const dictSize = (size_t)((char const*)dctx->dictContentEndForFuzzing - (char const*)dctx->dictContentBeginForFuzzing); + /* Offset must be within the dictionary. */ + assert(seq.offset <= (size_t)(oLitEnd - virtualStart)); + assert(seq.offset <= windowSize + dictSize); + } else { + /* Offset must be within our window. */ + assert(seq.offset <= windowSize); + } +#else + (void)dctx, (void)op, (void)oend, (void)seq, (void)prefixStart, (void)virtualStart; +#endif +} +#endif + +#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG + + +FORCE_INLINE_TEMPLATE size_t +DONT_VECTORIZE +ZSTD_decompressSequences_bodySplitLitBuffer( ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + const BYTE* ip = (const BYTE*)seqStart; + const BYTE* const iend = ip + seqSize; + BYTE* const ostart = (BYTE*)dst; + BYTE* const oend = ostart + maxDstSize; + BYTE* op = ostart; + const BYTE* litPtr = dctx->litPtr; + const BYTE* litBufferEnd = dctx->litBufferEnd; + const BYTE* const prefixStart = (const BYTE*) (dctx->prefixStart); + const BYTE* const vBase = (const BYTE*) (dctx->virtualStart); + const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd); + DEBUGLOG(5, "ZSTD_decompressSequences_bodySplitLitBuffer"); + (void)frame; + + /* Regen sequences */ + if (nbSeq) { + seqState_t seqState; + dctx->fseEntropy = 1; + { U32 i; for (i=0; ientropy.rep[i]; } + RETURN_ERROR_IF( + ERR_isError(BIT_initDStream(&seqState.DStream, ip, iend-ip)), + corruption_detected, ""); + ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr); + ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr); + ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr); + assert(dst != NULL); + + ZSTD_STATIC_ASSERT( + BIT_DStream_unfinished < BIT_DStream_completed && + BIT_DStream_endOfBuffer < BIT_DStream_completed && + BIT_DStream_completed < BIT_DStream_overflow); + + /* decompress without overrunning litPtr begins */ + { + seq_t sequence = ZSTD_decodeSequence(&seqState, isLongOffset); + /* Align the decompression loop to 32 + 16 bytes. + * + * zstd compiled with gcc-9 on an Intel i9-9900k shows 10% decompression + * speed swings based on the alignment of the decompression loop. This + * performance swing is caused by parts of the decompression loop falling + * out of the DSB. The entire decompression loop should fit in the DSB, + * when it can't we get much worse performance. You can measure if you've + * hit the good case or the bad case with this perf command for some + * compressed file test.zst: + * + * perf stat -e cycles -e instructions -e idq.all_dsb_cycles_any_uops \ + * -e idq.all_mite_cycles_any_uops -- ./zstd -tq test.zst + * + * If you see most cycles served out of the MITE you've hit the bad case. + * If you see most cycles served out of the DSB you've hit the good case. + * If it is pretty even then you may be in an okay case. + * + * This issue has been reproduced on the following CPUs: + * - Kabylake: Macbook Pro (15-inch, 2019) 2.4 GHz Intel Core i9 + * Use Instruments->Counters to get DSB/MITE cycles. + * I never got performance swings, but I was able to + * go from the good case of mostly DSB to half of the + * cycles served from MITE. + * - Coffeelake: Intel i9-9900k + * - Coffeelake: Intel i7-9700k + * + * I haven't been able to reproduce the instability or DSB misses on any + * of the following CPUS: + * - Haswell + * - Broadwell: Intel(R) Xeon(R) CPU E5-2680 v4 @ 2.40GH + * - Skylake + * + * Alignment is done for each of the three major decompression loops: + * - ZSTD_decompressSequences_bodySplitLitBuffer - presplit section of the literal buffer + * - ZSTD_decompressSequences_bodySplitLitBuffer - postsplit section of the literal buffer + * - ZSTD_decompressSequences_body + * Alignment choices are made to minimize large swings on bad cases and influence on performance + * from changes external to this code, rather than to overoptimize on the current commit. + * + * If you are seeing performance stability this script can help test. + * It tests on 4 commits in zstd where I saw performance change. + * + * https://gist.github.com/terrelln/9889fc06a423fd5ca6e99351564473f4 + */ +#if defined(__GNUC__) && defined(__x86_64__) + __asm__(".p2align 6"); +# if __GNUC__ >= 7 + /* good for gcc-7, gcc-9, and gcc-11 */ + __asm__("nop"); + __asm__(".p2align 5"); + __asm__("nop"); + __asm__(".p2align 4"); +# if __GNUC__ == 8 || __GNUC__ == 10 + /* good for gcc-8 and gcc-10 */ + __asm__("nop"); + __asm__(".p2align 3"); +# endif +# endif +#endif + + /* Handle the initial state where litBuffer is currently split between dst and litExtraBuffer */ + for (; litPtr + sequence.litLength <= dctx->litBufferEnd; ) { + size_t const oneSeqSize = ZSTD_execSequenceSplitLitBuffer(op, oend, litPtr + sequence.litLength - WILDCOPY_OVERLENGTH, sequence, &litPtr, litBufferEnd, prefixStart, vBase, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); +#endif + if (UNLIKELY(ZSTD_isError(oneSeqSize))) + return oneSeqSize; + DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); + op += oneSeqSize; + if (UNLIKELY(!--nbSeq)) + break; + BIT_reloadDStream(&(seqState.DStream)); + sequence = ZSTD_decodeSequence(&seqState, isLongOffset); + } + + /* If there are more sequences, they will need to read literals from litExtraBuffer; copy over the remainder from dst and update litPtr and litEnd */ + if (nbSeq > 0) { + const size_t leftoverLit = dctx->litBufferEnd - litPtr; + if (leftoverLit) + { + RETURN_ERROR_IF(leftoverLit > (size_t)(oend - op), dstSize_tooSmall, "remaining lit must fit within dstBuffer"); + ZSTD_safecopyDstBeforeSrc(op, litPtr, leftoverLit); + sequence.litLength -= leftoverLit; + op += leftoverLit; + } + litPtr = dctx->litExtraBuffer; + litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; + dctx->litBufferLocation = ZSTD_not_in_dst; + { + size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litBufferEnd, prefixStart, vBase, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); +#endif + if (UNLIKELY(ZSTD_isError(oneSeqSize))) + return oneSeqSize; + DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); + op += oneSeqSize; + if (--nbSeq) + BIT_reloadDStream(&(seqState.DStream)); + } + } + } + + if (nbSeq > 0) /* there is remaining lit from extra buffer */ + { + +#if defined(__GNUC__) && defined(__x86_64__) + __asm__(".p2align 6"); + __asm__("nop"); +# if __GNUC__ != 7 + /* worse for gcc-7 better for gcc-8, gcc-9, and gcc-10 and clang */ + __asm__(".p2align 4"); + __asm__("nop"); + __asm__(".p2align 3"); +# elif __GNUC__ >= 11 + __asm__(".p2align 3"); +# else + __asm__(".p2align 5"); + __asm__("nop"); + __asm__(".p2align 3"); +# endif +#endif + + for (; ; ) { + seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset); + size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litBufferEnd, prefixStart, vBase, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); +#endif + if (UNLIKELY(ZSTD_isError(oneSeqSize))) + return oneSeqSize; + DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); + op += oneSeqSize; + if (UNLIKELY(!--nbSeq)) + break; + BIT_reloadDStream(&(seqState.DStream)); + } + } + + /* check if reached exact end */ + DEBUGLOG(5, "ZSTD_decompressSequences_bodySplitLitBuffer: after decode loop, remaining nbSeq : %i", nbSeq); + RETURN_ERROR_IF(nbSeq, corruption_detected, ""); + RETURN_ERROR_IF(BIT_reloadDStream(&seqState.DStream) < BIT_DStream_completed, corruption_detected, ""); + /* save reps for next block */ + { U32 i; for (i=0; ientropy.rep[i] = (U32)(seqState.prevOffset[i]); } + } + + /* last literal segment */ + if (dctx->litBufferLocation == ZSTD_split) /* split hasn't been reached yet, first get dst then copy litExtraBuffer */ + { + size_t const lastLLSize = litBufferEnd - litPtr; + RETURN_ERROR_IF(lastLLSize > (size_t)(oend - op), dstSize_tooSmall, ""); + if (op != NULL) { + ZSTD_memmove(op, litPtr, lastLLSize); + op += lastLLSize; + } + litPtr = dctx->litExtraBuffer; + litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; + dctx->litBufferLocation = ZSTD_not_in_dst; + } + { size_t const lastLLSize = litBufferEnd - litPtr; + RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, ""); + if (op != NULL) { + ZSTD_memcpy(op, litPtr, lastLLSize); + op += lastLLSize; + } + } + + return op-ostart; +} + +FORCE_INLINE_TEMPLATE size_t +DONT_VECTORIZE +ZSTD_decompressSequences_body(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + const BYTE* ip = (const BYTE*)seqStart; + const BYTE* const iend = ip + seqSize; + BYTE* const ostart = (BYTE*)dst; + BYTE* const oend = dctx->litBufferLocation == ZSTD_not_in_dst ? ostart + maxDstSize : dctx->litBuffer; + BYTE* op = ostart; + const BYTE* litPtr = dctx->litPtr; + const BYTE* const litEnd = litPtr + dctx->litSize; + const BYTE* const prefixStart = (const BYTE*)(dctx->prefixStart); + const BYTE* const vBase = (const BYTE*)(dctx->virtualStart); + const BYTE* const dictEnd = (const BYTE*)(dctx->dictEnd); + DEBUGLOG(5, "ZSTD_decompressSequences_body: nbSeq = %d", nbSeq); + (void)frame; + + /* Regen sequences */ + if (nbSeq) { + seqState_t seqState; + dctx->fseEntropy = 1; + { U32 i; for (i = 0; i < ZSTD_REP_NUM; i++) seqState.prevOffset[i] = dctx->entropy.rep[i]; } + RETURN_ERROR_IF( + ERR_isError(BIT_initDStream(&seqState.DStream, ip, iend - ip)), + corruption_detected, ""); + ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr); + ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr); + ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr); + assert(dst != NULL); + + ZSTD_STATIC_ASSERT( + BIT_DStream_unfinished < BIT_DStream_completed && + BIT_DStream_endOfBuffer < BIT_DStream_completed && + BIT_DStream_completed < BIT_DStream_overflow); + +#if defined(__GNUC__) && defined(__x86_64__) + __asm__(".p2align 6"); + __asm__("nop"); +# if __GNUC__ >= 7 + __asm__(".p2align 5"); + __asm__("nop"); + __asm__(".p2align 3"); +# else + __asm__(".p2align 4"); + __asm__("nop"); + __asm__(".p2align 3"); +# endif +#endif + + for ( ; ; ) { + seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset); + size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, prefixStart, vBase, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); +#endif + if (UNLIKELY(ZSTD_isError(oneSeqSize))) + return oneSeqSize; + DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); + op += oneSeqSize; + if (UNLIKELY(!--nbSeq)) + break; + BIT_reloadDStream(&(seqState.DStream)); + } + + /* check if reached exact end */ + DEBUGLOG(5, "ZSTD_decompressSequences_body: after decode loop, remaining nbSeq : %i", nbSeq); + RETURN_ERROR_IF(nbSeq, corruption_detected, ""); + RETURN_ERROR_IF(BIT_reloadDStream(&seqState.DStream) < BIT_DStream_completed, corruption_detected, ""); + /* save reps for next block */ + { U32 i; for (i=0; ientropy.rep[i] = (U32)(seqState.prevOffset[i]); } + } + + /* last literal segment */ + { size_t const lastLLSize = litEnd - litPtr; + RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, ""); + if (op != NULL) { + ZSTD_memcpy(op, litPtr, lastLLSize); + op += lastLLSize; + } + } + + return op-ostart; +} + +static size_t +ZSTD_decompressSequences_default(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} + +static size_t +ZSTD_decompressSequencesSplitLitBuffer_default(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + return ZSTD_decompressSequences_bodySplitLitBuffer(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} +#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */ + +#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT + +FORCE_INLINE_TEMPLATE size_t +ZSTD_prefetchMatch(size_t prefetchPos, seq_t const sequence, + const BYTE* const prefixStart, const BYTE* const dictEnd) +{ + prefetchPos += sequence.litLength; + { const BYTE* const matchBase = (sequence.offset > prefetchPos) ? dictEnd : prefixStart; + const BYTE* const match = matchBase + prefetchPos - sequence.offset; /* note : this operation can overflow when seq.offset is really too large, which can only happen when input is corrupted. + * No consequence though : memory address is only used for prefetching, not for dereferencing */ + PREFETCH_L1(match); PREFETCH_L1(match+CACHELINE_SIZE); /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */ + } + return prefetchPos + sequence.matchLength; +} + +/* This decoding function employs prefetching + * to reduce latency impact of cache misses. + * It's generally employed when block contains a significant portion of long-distance matches + * or when coupled with a "cold" dictionary */ +FORCE_INLINE_TEMPLATE size_t +ZSTD_decompressSequencesLong_body( + ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + const BYTE* ip = (const BYTE*)seqStart; + const BYTE* const iend = ip + seqSize; + BYTE* const ostart = (BYTE*)dst; + BYTE* const oend = dctx->litBufferLocation == ZSTD_in_dst ? dctx->litBuffer : ostart + maxDstSize; + BYTE* op = ostart; + const BYTE* litPtr = dctx->litPtr; + const BYTE* litBufferEnd = dctx->litBufferEnd; + const BYTE* const prefixStart = (const BYTE*) (dctx->prefixStart); + const BYTE* const dictStart = (const BYTE*) (dctx->virtualStart); + const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd); + (void)frame; + + /* Regen sequences */ + if (nbSeq) { +#define STORED_SEQS 8 +#define STORED_SEQS_MASK (STORED_SEQS-1) +#define ADVANCED_SEQS STORED_SEQS + seq_t sequences[STORED_SEQS]; + int const seqAdvance = MIN(nbSeq, ADVANCED_SEQS); + seqState_t seqState; + int seqNb; + size_t prefetchPos = (size_t)(op-prefixStart); /* track position relative to prefixStart */ + + dctx->fseEntropy = 1; + { int i; for (i=0; ientropy.rep[i]; } + assert(dst != NULL); + assert(iend >= ip); + RETURN_ERROR_IF( + ERR_isError(BIT_initDStream(&seqState.DStream, ip, iend-ip)), + corruption_detected, ""); + ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr); + ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr); + ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr); + + /* prepare in advance */ + for (seqNb=0; (BIT_reloadDStream(&seqState.DStream) <= BIT_DStream_completed) && (seqNblitBufferLocation == ZSTD_split && litPtr + sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK].litLength > dctx->litBufferEnd) + { + /* lit buffer is reaching split point, empty out the first buffer and transition to litExtraBuffer */ + const size_t leftoverLit = dctx->litBufferEnd - litPtr; + if (leftoverLit) + { + RETURN_ERROR_IF(leftoverLit > (size_t)(oend - op), dstSize_tooSmall, "remaining lit must fit within dstBuffer"); + ZSTD_safecopyDstBeforeSrc(op, litPtr, leftoverLit); + sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK].litLength -= leftoverLit; + op += leftoverLit; + } + litPtr = dctx->litExtraBuffer; + litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; + dctx->litBufferLocation = ZSTD_not_in_dst; + oneSeqSize = ZSTD_execSequence(op, oend, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], prefixStart, dictStart); +#endif + if (ZSTD_isError(oneSeqSize)) return oneSeqSize; + + prefetchPos = ZSTD_prefetchMatch(prefetchPos, sequence, prefixStart, dictEnd); + sequences[seqNb & STORED_SEQS_MASK] = sequence; + op += oneSeqSize; + } + else + { + /* lit buffer is either wholly contained in first or second split, or not split at all*/ + oneSeqSize = dctx->litBufferLocation == ZSTD_split ? + ZSTD_execSequenceSplitLitBuffer(op, oend, litPtr + sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK].litLength - WILDCOPY_OVERLENGTH, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd) : + ZSTD_execSequence(op, oend, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], prefixStart, dictStart); +#endif + if (ZSTD_isError(oneSeqSize)) return oneSeqSize; + + prefetchPos = ZSTD_prefetchMatch(prefetchPos, sequence, prefixStart, dictEnd); + sequences[seqNb & STORED_SEQS_MASK] = sequence; + op += oneSeqSize; + } + } + RETURN_ERROR_IF(seqNblitBufferLocation == ZSTD_split && litPtr + sequence->litLength > dctx->litBufferEnd) + { + const size_t leftoverLit = dctx->litBufferEnd - litPtr; + if (leftoverLit) + { + RETURN_ERROR_IF(leftoverLit > (size_t)(oend - op), dstSize_tooSmall, "remaining lit must fit within dstBuffer"); + ZSTD_safecopyDstBeforeSrc(op, litPtr, leftoverLit); + sequence->litLength -= leftoverLit; + op += leftoverLit; + } + litPtr = dctx->litExtraBuffer; + litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; + dctx->litBufferLocation = ZSTD_not_in_dst; + { + size_t const oneSeqSize = ZSTD_execSequence(op, oend, *sequence, &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[seqNb&STORED_SEQS_MASK], prefixStart, dictStart); +#endif + if (ZSTD_isError(oneSeqSize)) return oneSeqSize; + op += oneSeqSize; + } + } + else + { + size_t const oneSeqSize = dctx->litBufferLocation == ZSTD_split ? + ZSTD_execSequenceSplitLitBuffer(op, oend, litPtr + sequence->litLength - WILDCOPY_OVERLENGTH, *sequence, &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd) : + ZSTD_execSequence(op, oend, *sequence, &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[seqNb&STORED_SEQS_MASK], prefixStart, dictStart); +#endif + if (ZSTD_isError(oneSeqSize)) return oneSeqSize; + op += oneSeqSize; + } + } + + /* save reps for next block */ + { U32 i; for (i=0; ientropy.rep[i] = (U32)(seqState.prevOffset[i]); } + } + + /* last literal segment */ + if (dctx->litBufferLocation == ZSTD_split) /* first deplete literal buffer in dst, then copy litExtraBuffer */ + { + size_t const lastLLSize = litBufferEnd - litPtr; + RETURN_ERROR_IF(lastLLSize > (size_t)(oend - op), dstSize_tooSmall, ""); + if (op != NULL) { + ZSTD_memmove(op, litPtr, lastLLSize); + op += lastLLSize; + } + litPtr = dctx->litExtraBuffer; + litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; + } + { size_t const lastLLSize = litBufferEnd - litPtr; + RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, ""); + if (op != NULL) { + ZSTD_memmove(op, litPtr, lastLLSize); + op += lastLLSize; + } + } + + return op-ostart; +} + +static size_t +ZSTD_decompressSequencesLong_default(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} +#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */ + + + +#if DYNAMIC_BMI2 + +#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG +static BMI2_TARGET_ATTRIBUTE size_t +DONT_VECTORIZE +ZSTD_decompressSequences_bmi2(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} +static BMI2_TARGET_ATTRIBUTE size_t +DONT_VECTORIZE +ZSTD_decompressSequencesSplitLitBuffer_bmi2(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + return ZSTD_decompressSequences_bodySplitLitBuffer(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} +#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */ + +#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT +static BMI2_TARGET_ATTRIBUTE size_t +ZSTD_decompressSequencesLong_bmi2(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} +#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */ + +#endif /* DYNAMIC_BMI2 */ + +typedef size_t (*ZSTD_decompressSequences_t)( + ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame); + +#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG +static size_t +ZSTD_decompressSequences(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + DEBUGLOG(5, "ZSTD_decompressSequences"); +#if DYNAMIC_BMI2 + if (ZSTD_DCtx_get_bmi2(dctx)) { + return ZSTD_decompressSequences_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); + } +#endif + return ZSTD_decompressSequences_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} +static size_t +ZSTD_decompressSequencesSplitLitBuffer(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + DEBUGLOG(5, "ZSTD_decompressSequencesSplitLitBuffer"); +#if DYNAMIC_BMI2 + if (ZSTD_DCtx_get_bmi2(dctx)) { + return ZSTD_decompressSequencesSplitLitBuffer_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); + } +#endif + return ZSTD_decompressSequencesSplitLitBuffer_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} +#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */ + + +#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT +/* ZSTD_decompressSequencesLong() : + * decompression function triggered when a minimum share of offsets is considered "long", + * aka out of cache. + * note : "long" definition seems overloaded here, sometimes meaning "wider than bitstream register", and sometimes meaning "farther than memory cache distance". + * This function will try to mitigate main memory latency through the use of prefetching */ +static size_t +ZSTD_decompressSequencesLong(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + DEBUGLOG(5, "ZSTD_decompressSequencesLong"); +#if DYNAMIC_BMI2 + if (ZSTD_DCtx_get_bmi2(dctx)) { + return ZSTD_decompressSequencesLong_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); + } +#endif + return ZSTD_decompressSequencesLong_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} +#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */ + + +/** + * @returns The total size of the history referenceable by zstd, including + * both the prefix and the extDict. At @p op any offset larger than this + * is invalid. + */ +static size_t ZSTD_totalHistorySize(BYTE* op, BYTE const* virtualStart) +{ + return (size_t)(op - virtualStart); +} + +typedef struct { + unsigned longOffsetShare; + unsigned maxNbAdditionalBits; +} ZSTD_OffsetInfo; + +/* ZSTD_getOffsetInfo() : + * condition : offTable must be valid + * @return : "share" of long offsets (arbitrarily defined as > (1<<23)) + * compared to maximum possible of (1< 22) info.longOffsetShare += 1; + } + + assert(tableLog <= OffFSELog); + info.longOffsetShare <<= (OffFSELog - tableLog); /* scale to OffFSELog */ + } + + return info; +} + +/** + * @returns The maximum offset we can decode in one read of our bitstream, without + * reloading more bits in the middle of the offset bits read. Any offsets larger + * than this must use the long offset decoder. + */ +static size_t ZSTD_maxShortOffset(void) +{ + if (MEM_64bits()) { + /* We can decode any offset without reloading bits. + * This might change if the max window size grows. + */ + ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31); + return (size_t)-1; + } else { + /* The maximum offBase is (1 << (STREAM_ACCUMULATOR_MIN + 1)) - 1. + * This offBase would require STREAM_ACCUMULATOR_MIN extra bits. + * Then we have to subtract ZSTD_REP_NUM to get the maximum possible offset. + */ + size_t const maxOffbase = ((size_t)1 << (STREAM_ACCUMULATOR_MIN + 1)) - 1; + size_t const maxOffset = maxOffbase - ZSTD_REP_NUM; + assert(ZSTD_highbit32((U32)maxOffbase) == STREAM_ACCUMULATOR_MIN); + return maxOffset; + } +} + +size_t +ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, const int frame, const streaming_operation streaming) +{ /* blockType == blockCompressed */ + const BYTE* ip = (const BYTE*)src; + DEBUGLOG(5, "ZSTD_decompressBlock_internal (size : %u)", (U32)srcSize); + + /* Note : the wording of the specification + * allows compressed block to be sized exactly ZSTD_BLOCKSIZE_MAX. + * This generally does not happen, as it makes little sense, + * since an uncompressed block would feature same size and have no decompression cost. + * Also, note that decoder from reference libzstd before < v1.5.4 + * would consider this edge case as an error. + * As a consequence, avoid generating compressed blocks of size ZSTD_BLOCKSIZE_MAX + * for broader compatibility with the deployed ecosystem of zstd decoders */ + RETURN_ERROR_IF(srcSize > ZSTD_BLOCKSIZE_MAX, srcSize_wrong, ""); + + /* Decode literals section */ + { size_t const litCSize = ZSTD_decodeLiteralsBlock(dctx, src, srcSize, dst, dstCapacity, streaming); + DEBUGLOG(5, "ZSTD_decodeLiteralsBlock : cSize=%u, nbLiterals=%zu", (U32)litCSize, dctx->litSize); + if (ZSTD_isError(litCSize)) return litCSize; + ip += litCSize; + srcSize -= litCSize; + } + + /* Build Decoding Tables */ + { + /* Compute the maximum block size, which must also work when !frame and fParams are unset. + * Additionally, take the min with dstCapacity to ensure that the totalHistorySize fits in a size_t. + */ + size_t const blockSizeMax = MIN(dstCapacity, (frame ? dctx->fParams.blockSizeMax : ZSTD_BLOCKSIZE_MAX)); + size_t const totalHistorySize = ZSTD_totalHistorySize((BYTE*)dst + blockSizeMax, (BYTE const*)dctx->virtualStart); + /* isLongOffset must be true if there are long offsets. + * Offsets are long if they are larger than ZSTD_maxShortOffset(). + * We don't expect that to be the case in 64-bit mode. + * + * We check here to see if our history is large enough to allow long offsets. + * If it isn't, then we can't possible have (valid) long offsets. If the offset + * is invalid, then it is okay to read it incorrectly. + * + * If isLongOffsets is true, then we will later check our decoding table to see + * if it is even possible to generate long offsets. + */ + ZSTD_longOffset_e isLongOffset = (ZSTD_longOffset_e)(MEM_32bits() && (totalHistorySize > ZSTD_maxShortOffset())); + /* These macros control at build-time which decompressor implementation + * we use. If neither is defined, we do some inspection and dispatch at + * runtime. + */ +#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \ + !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG) + int usePrefetchDecoder = dctx->ddictIsCold; +#else + /* Set to 1 to avoid computing offset info if we don't need to. + * Otherwise this value is ignored. + */ + int usePrefetchDecoder = 1; +#endif + int nbSeq; + size_t const seqHSize = ZSTD_decodeSeqHeaders(dctx, &nbSeq, ip, srcSize); + if (ZSTD_isError(seqHSize)) return seqHSize; + ip += seqHSize; + srcSize -= seqHSize; + + RETURN_ERROR_IF((dst == NULL || dstCapacity == 0) && nbSeq > 0, dstSize_tooSmall, "NULL not handled"); + RETURN_ERROR_IF(MEM_64bits() && sizeof(size_t) == sizeof(void*) && (size_t)(-1) - (size_t)dst < (size_t)(1 << 20), dstSize_tooSmall, + "invalid dst"); + + /* If we could potentially have long offsets, or we might want to use the prefetch decoder, + * compute information about the share of long offsets, and the maximum nbAdditionalBits. + * NOTE: could probably use a larger nbSeq limit + */ + if (isLongOffset || (!usePrefetchDecoder && (totalHistorySize > (1u << 24)) && (nbSeq > 8))) { + ZSTD_OffsetInfo const info = ZSTD_getOffsetInfo(dctx->OFTptr, nbSeq); + if (isLongOffset && info.maxNbAdditionalBits <= STREAM_ACCUMULATOR_MIN) { + /* If isLongOffset, but the maximum number of additional bits that we see in our table is small + * enough, then we know it is impossible to have too long an offset in this block, so we can + * use the regular offset decoder. + */ + isLongOffset = ZSTD_lo_isRegularOffset; + } + if (!usePrefetchDecoder) { + U32 const minShare = MEM_64bits() ? 7 : 20; /* heuristic values, correspond to 2.73% and 7.81% */ + usePrefetchDecoder = (info.longOffsetShare >= minShare); + } + } + + dctx->ddictIsCold = 0; + +#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \ + !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG) + if (usePrefetchDecoder) { +#else + (void)usePrefetchDecoder; + { +#endif +#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT + return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset, frame); +#endif + } + +#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG + /* else */ + if (dctx->litBufferLocation == ZSTD_split) + return ZSTD_decompressSequencesSplitLitBuffer(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset, frame); + else + return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset, frame); +#endif + } +} + + +void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst, size_t dstSize) +{ + if (dst != dctx->previousDstEnd && dstSize > 0) { /* not contiguous */ + dctx->dictEnd = dctx->previousDstEnd; + dctx->virtualStart = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart)); + dctx->prefixStart = dst; + dctx->previousDstEnd = dst; + } +} + + +size_t ZSTD_decompressBlock_deprecated(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize) +{ + size_t dSize; + ZSTD_checkContinuity(dctx, dst, dstCapacity); + dSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 0, not_streaming); + dctx->previousDstEnd = (char*)dst + dSize; + return dSize; +} + + +/* NOTE: Must just wrap ZSTD_decompressBlock_deprecated() */ +size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize) +{ + return ZSTD_decompressBlock_deprecated(dctx, dst, dstCapacity, src, srcSize); +} diff --git a/lib/zstd/lib/decompress/zstd_decompress_block.h b/lib/zstd/lib/decompress/zstd_decompress_block.h new file mode 100644 index 0000000..9d13188 --- /dev/null +++ b/lib/zstd/lib/decompress/zstd_decompress_block.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + + +#ifndef ZSTD_DEC_BLOCK_H +#define ZSTD_DEC_BLOCK_H + +/*-******************************************************* + * Dependencies + *********************************************************/ +#include "../common/zstd_deps.h" /* size_t */ +#include "../zstd.h" /* DCtx, and some public functions */ +#include "../common/zstd_internal.h" /* blockProperties_t, and some public functions */ +#include "zstd_decompress_internal.h" /* ZSTD_seqSymbol */ + + +/* === Prototypes === */ + +/* note: prototypes already published within `zstd.h` : + * ZSTD_decompressBlock() + */ + +/* note: prototypes already published within `zstd_internal.h` : + * ZSTD_getcBlockSize() + * ZSTD_decodeSeqHeaders() + */ + + + /* Streaming state is used to inform allocation of the literal buffer */ +typedef enum { + not_streaming = 0, + is_streaming = 1 +} streaming_operation; + +/* ZSTD_decompressBlock_internal() : + * decompress block, starting at `src`, + * into destination buffer `dst`. + * @return : decompressed block size, + * or an error code (which can be tested using ZSTD_isError()) + */ +size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, const int frame, const streaming_operation streaming); + +/* ZSTD_buildFSETable() : + * generate FSE decoding table for one symbol (ll, ml or off) + * this function must be called with valid parameters only + * (dt is large enough, normalizedCounter distribution total is a power of 2, max is within range, etc.) + * in which case it cannot fail. + * The workspace must be 4-byte aligned and at least ZSTD_BUILD_FSE_TABLE_WKSP_SIZE bytes, which is + * defined in zstd_decompress_internal.h. + * Internal use only. + */ +void ZSTD_buildFSETable(ZSTD_seqSymbol* dt, + const short* normalizedCounter, unsigned maxSymbolValue, + const U32* baseValue, const U8* nbAdditionalBits, + unsigned tableLog, void* wksp, size_t wkspSize, + int bmi2); + +/* Internal definition of ZSTD_decompressBlock() to avoid deprecation warnings. */ +size_t ZSTD_decompressBlock_deprecated(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize); + + +#endif /* ZSTD_DEC_BLOCK_H */ diff --git a/lib/zstd/lib/decompress/zstd_decompress_internal.h b/lib/zstd/lib/decompress/zstd_decompress_internal.h new file mode 100644 index 0000000..c2ec5d9 --- /dev/null +++ b/lib/zstd/lib/decompress/zstd_decompress_internal.h @@ -0,0 +1,238 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + + +/* zstd_decompress_internal: + * objects and definitions shared within lib/decompress modules */ + + #ifndef ZSTD_DECOMPRESS_INTERNAL_H + #define ZSTD_DECOMPRESS_INTERNAL_H + + +/*-******************************************************* + * Dependencies + *********************************************************/ +#include "../common/mem.h" /* BYTE, U16, U32 */ +#include "../common/zstd_internal.h" /* constants : MaxLL, MaxML, MaxOff, LLFSELog, etc. */ + + + +/*-******************************************************* + * Constants + *********************************************************/ +static UNUSED_ATTR const U32 LL_base[MaxLL+1] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 18, 20, 22, 24, 28, 32, 40, + 48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, + 0x2000, 0x4000, 0x8000, 0x10000 }; + +static UNUSED_ATTR const U32 OF_base[MaxOff+1] = { + 0, 1, 1, 5, 0xD, 0x1D, 0x3D, 0x7D, + 0xFD, 0x1FD, 0x3FD, 0x7FD, 0xFFD, 0x1FFD, 0x3FFD, 0x7FFD, + 0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD, 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD, + 0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD, 0x1FFFFFFD, 0x3FFFFFFD, 0x7FFFFFFD }; + +static UNUSED_ATTR const U8 OF_bits[MaxOff+1] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31 }; + +static UNUSED_ATTR const U32 ML_base[MaxML+1] = { + 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, + 35, 37, 39, 41, 43, 47, 51, 59, + 67, 83, 99, 0x83, 0x103, 0x203, 0x403, 0x803, + 0x1003, 0x2003, 0x4003, 0x8003, 0x10003 }; + + +/*-******************************************************* + * Decompression types + *********************************************************/ + typedef struct { + U32 fastMode; + U32 tableLog; + } ZSTD_seqSymbol_header; + + typedef struct { + U16 nextState; + BYTE nbAdditionalBits; + BYTE nbBits; + U32 baseValue; + } ZSTD_seqSymbol; + + #define SEQSYMBOL_TABLE_SIZE(log) (1 + (1 << (log))) + +#define ZSTD_BUILD_FSE_TABLE_WKSP_SIZE (sizeof(S16) * (MaxSeq + 1) + (1u << MaxFSELog) + sizeof(U64)) +#define ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32 ((ZSTD_BUILD_FSE_TABLE_WKSP_SIZE + sizeof(U32) - 1) / sizeof(U32)) +#define ZSTD_HUFFDTABLE_CAPACITY_LOG 12 + +typedef struct { + ZSTD_seqSymbol LLTable[SEQSYMBOL_TABLE_SIZE(LLFSELog)]; /* Note : Space reserved for FSE Tables */ + ZSTD_seqSymbol OFTable[SEQSYMBOL_TABLE_SIZE(OffFSELog)]; /* is also used as temporary workspace while building hufTable during DDict creation */ + ZSTD_seqSymbol MLTable[SEQSYMBOL_TABLE_SIZE(MLFSELog)]; /* and therefore must be at least HUF_DECOMPRESS_WORKSPACE_SIZE large */ + HUF_DTable hufTable[HUF_DTABLE_SIZE(ZSTD_HUFFDTABLE_CAPACITY_LOG)]; /* can accommodate HUF_decompress4X */ + U32 rep[ZSTD_REP_NUM]; + U32 workspace[ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32]; +} ZSTD_entropyDTables_t; + +typedef enum { ZSTDds_getFrameHeaderSize, ZSTDds_decodeFrameHeader, + ZSTDds_decodeBlockHeader, ZSTDds_decompressBlock, + ZSTDds_decompressLastBlock, ZSTDds_checkChecksum, + ZSTDds_decodeSkippableHeader, ZSTDds_skipFrame } ZSTD_dStage; + +typedef enum { zdss_init=0, zdss_loadHeader, + zdss_read, zdss_load, zdss_flush } ZSTD_dStreamStage; + +typedef enum { + ZSTD_use_indefinitely = -1, /* Use the dictionary indefinitely */ + ZSTD_dont_use = 0, /* Do not use the dictionary (if one exists free it) */ + ZSTD_use_once = 1 /* Use the dictionary once and set to ZSTD_dont_use */ +} ZSTD_dictUses_e; + +/* Hashset for storing references to multiple ZSTD_DDict within ZSTD_DCtx */ +typedef struct { + const ZSTD_DDict** ddictPtrTable; + size_t ddictPtrTableSize; + size_t ddictPtrCount; +} ZSTD_DDictHashSet; + +#ifndef ZSTD_DECODER_INTERNAL_BUFFER +# define ZSTD_DECODER_INTERNAL_BUFFER (1 << 16) +#endif + +#define ZSTD_LBMIN 64 +#define ZSTD_LBMAX (128 << 10) + +/* extra buffer, compensates when dst is not large enough to store litBuffer */ +#define ZSTD_LITBUFFEREXTRASIZE BOUNDED(ZSTD_LBMIN, ZSTD_DECODER_INTERNAL_BUFFER, ZSTD_LBMAX) + +typedef enum { + ZSTD_not_in_dst = 0, /* Stored entirely within litExtraBuffer */ + ZSTD_in_dst = 1, /* Stored entirely within dst (in memory after current output write) */ + ZSTD_split = 2 /* Split between litExtraBuffer and dst */ +} ZSTD_litLocation_e; + +struct ZSTD_DCtx_s +{ + const ZSTD_seqSymbol* LLTptr; + const ZSTD_seqSymbol* MLTptr; + const ZSTD_seqSymbol* OFTptr; + const HUF_DTable* HUFptr; + ZSTD_entropyDTables_t entropy; + U32 workspace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; /* space needed when building huffman tables */ + const void* previousDstEnd; /* detect continuity */ + const void* prefixStart; /* start of current segment */ + const void* virtualStart; /* virtual start of previous segment if it was just before current one */ + const void* dictEnd; /* end of previous segment */ + size_t expected; + ZSTD_frameHeader fParams; + U64 processedCSize; + U64 decodedSize; + blockType_e bType; /* used in ZSTD_decompressContinue(), store blockType between block header decoding and block decompression stages */ + ZSTD_dStage stage; + U32 litEntropy; + U32 fseEntropy; + XXH64_state_t xxhState; + size_t headerSize; + ZSTD_format_e format; + ZSTD_forceIgnoreChecksum_e forceIgnoreChecksum; /* User specified: if == 1, will ignore checksums in compressed frame. Default == 0 */ + U32 validateChecksum; /* if == 1, will validate checksum. Is == 1 if (fParams.checksumFlag == 1) and (forceIgnoreChecksum == 0). */ + const BYTE* litPtr; + ZSTD_customMem customMem; + size_t litSize; + size_t rleSize; + size_t staticSize; +#if DYNAMIC_BMI2 != 0 + int bmi2; /* == 1 if the CPU supports BMI2 and 0 otherwise. CPU support is determined dynamically once per context lifetime. */ +#endif + + /* dictionary */ + ZSTD_DDict* ddictLocal; + const ZSTD_DDict* ddict; /* set by ZSTD_initDStream_usingDDict(), or ZSTD_DCtx_refDDict() */ + U32 dictID; + int ddictIsCold; /* if == 1 : dictionary is "new" for working context, and presumed "cold" (not in cpu cache) */ + ZSTD_dictUses_e dictUses; + ZSTD_DDictHashSet* ddictSet; /* Hash set for multiple ddicts */ + ZSTD_refMultipleDDicts_e refMultipleDDicts; /* User specified: if == 1, will allow references to multiple DDicts. Default == 0 (disabled) */ + int disableHufAsm; + + /* streaming */ + ZSTD_dStreamStage streamStage; + char* inBuff; + size_t inBuffSize; + size_t inPos; + size_t maxWindowSize; + char* outBuff; + size_t outBuffSize; + size_t outStart; + size_t outEnd; + size_t lhSize; +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) + void* legacyContext; + U32 previousLegacyVersion; + U32 legacyVersion; +#endif + U32 hostageByte; + int noForwardProgress; + ZSTD_bufferMode_e outBufferMode; + ZSTD_outBuffer expectedOutBuffer; + + /* workspace */ + BYTE* litBuffer; + const BYTE* litBufferEnd; + ZSTD_litLocation_e litBufferLocation; + BYTE litExtraBuffer[ZSTD_LITBUFFEREXTRASIZE + WILDCOPY_OVERLENGTH]; /* literal buffer can be split between storage within dst and within this scratch buffer */ + BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX]; + + size_t oversizedDuration; + +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + void const* dictContentBeginForFuzzing; + void const* dictContentEndForFuzzing; +#endif + + /* Tracing */ +#if ZSTD_TRACE + ZSTD_TraceCtx traceCtx; +#endif +}; /* typedef'd to ZSTD_DCtx within "zstd.h" */ + +MEM_STATIC int ZSTD_DCtx_get_bmi2(const struct ZSTD_DCtx_s *dctx) { +#if DYNAMIC_BMI2 != 0 + return dctx->bmi2; +#else + (void)dctx; + return 0; +#endif +} + +/*-******************************************************* + * Shared internal functions + *********************************************************/ + +/*! ZSTD_loadDEntropy() : + * dict : must point at beginning of a valid zstd dictionary. + * @return : size of dictionary header (size of magic number + dict ID + entropy tables) */ +size_t ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy, + const void* const dict, size_t const dictSize); + +/*! ZSTD_checkContinuity() : + * check if next `dst` follows previous position, where decompression ended. + * If yes, do nothing (continue on current segment). + * If not, classify previous segment as "external dictionary", and start a new segment. + * This function cannot fail. */ +void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst, size_t dstSize); + + +#endif /* ZSTD_DECOMPRESS_INTERNAL_H */ diff --git a/lib/zstd/lib/zdict.h b/lib/zstd/lib/zdict.h new file mode 100644 index 0000000..2268f94 --- /dev/null +++ b/lib/zstd/lib/zdict.h @@ -0,0 +1,474 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#if defined (__cplusplus) +extern "C" { +#endif + +#ifndef ZSTD_ZDICT_H +#define ZSTD_ZDICT_H + +/*====== Dependencies ======*/ +#include /* size_t */ + + +/* ===== ZDICTLIB_API : control library symbols visibility ===== */ +#ifndef ZDICTLIB_VISIBLE + /* Backwards compatibility with old macro name */ +# ifdef ZDICTLIB_VISIBILITY +# define ZDICTLIB_VISIBLE ZDICTLIB_VISIBILITY +# elif defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) +# define ZDICTLIB_VISIBLE __attribute__ ((visibility ("default"))) +# else +# define ZDICTLIB_VISIBLE +# endif +#endif + +#ifndef ZDICTLIB_HIDDEN +# if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) +# define ZDICTLIB_HIDDEN __attribute__ ((visibility ("hidden"))) +# else +# define ZDICTLIB_HIDDEN +# endif +#endif + +#if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) +# define ZDICTLIB_API __declspec(dllexport) ZDICTLIB_VISIBLE +#elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) +# define ZDICTLIB_API __declspec(dllimport) ZDICTLIB_VISIBLE /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ +#else +# define ZDICTLIB_API ZDICTLIB_VISIBLE +#endif + +/******************************************************************************* + * Zstd dictionary builder + * + * FAQ + * === + * Why should I use a dictionary? + * ------------------------------ + * + * Zstd can use dictionaries to improve compression ratio of small data. + * Traditionally small files don't compress well because there is very little + * repetition in a single sample, since it is small. But, if you are compressing + * many similar files, like a bunch of JSON records that share the same + * structure, you can train a dictionary on ahead of time on some samples of + * these files. Then, zstd can use the dictionary to find repetitions that are + * present across samples. This can vastly improve compression ratio. + * + * When is a dictionary useful? + * ---------------------------- + * + * Dictionaries are useful when compressing many small files that are similar. + * The larger a file is, the less benefit a dictionary will have. Generally, + * we don't expect dictionary compression to be effective past 100KB. And the + * smaller a file is, the more we would expect the dictionary to help. + * + * How do I use a dictionary? + * -------------------------- + * + * Simply pass the dictionary to the zstd compressor with + * `ZSTD_CCtx_loadDictionary()`. The same dictionary must then be passed to + * the decompressor, using `ZSTD_DCtx_loadDictionary()`. There are other + * more advanced functions that allow selecting some options, see zstd.h for + * complete documentation. + * + * What is a zstd dictionary? + * -------------------------- + * + * A zstd dictionary has two pieces: Its header, and its content. The header + * contains a magic number, the dictionary ID, and entropy tables. These + * entropy tables allow zstd to save on header costs in the compressed file, + * which really matters for small data. The content is just bytes, which are + * repeated content that is common across many samples. + * + * What is a raw content dictionary? + * --------------------------------- + * + * A raw content dictionary is just bytes. It doesn't have a zstd dictionary + * header, a dictionary ID, or entropy tables. Any buffer is a valid raw + * content dictionary. + * + * How do I train a dictionary? + * ---------------------------- + * + * Gather samples from your use case. These samples should be similar to each + * other. If you have several use cases, you could try to train one dictionary + * per use case. + * + * Pass those samples to `ZDICT_trainFromBuffer()` and that will train your + * dictionary. There are a few advanced versions of this function, but this + * is a great starting point. If you want to further tune your dictionary + * you could try `ZDICT_optimizeTrainFromBuffer_cover()`. If that is too slow + * you can try `ZDICT_optimizeTrainFromBuffer_fastCover()`. + * + * If the dictionary training function fails, that is likely because you + * either passed too few samples, or a dictionary would not be effective + * for your data. Look at the messages that the dictionary trainer printed, + * if it doesn't say too few samples, then a dictionary would not be effective. + * + * How large should my dictionary be? + * ---------------------------------- + * + * A reasonable dictionary size, the `dictBufferCapacity`, is about 100KB. + * The zstd CLI defaults to a 110KB dictionary. You likely don't need a + * dictionary larger than that. But, most use cases can get away with a + * smaller dictionary. The advanced dictionary builders can automatically + * shrink the dictionary for you, and select the smallest size that doesn't + * hurt compression ratio too much. See the `shrinkDict` parameter. + * A smaller dictionary can save memory, and potentially speed up + * compression. + * + * How many samples should I provide to the dictionary builder? + * ------------------------------------------------------------ + * + * We generally recommend passing ~100x the size of the dictionary + * in samples. A few thousand should suffice. Having too few samples + * can hurt the dictionaries effectiveness. Having more samples will + * only improve the dictionaries effectiveness. But having too many + * samples can slow down the dictionary builder. + * + * How do I determine if a dictionary will be effective? + * ----------------------------------------------------- + * + * Simply train a dictionary and try it out. You can use zstd's built in + * benchmarking tool to test the dictionary effectiveness. + * + * # Benchmark levels 1-3 without a dictionary + * zstd -b1e3 -r /path/to/my/files + * # Benchmark levels 1-3 with a dictionary + * zstd -b1e3 -r /path/to/my/files -D /path/to/my/dictionary + * + * When should I retrain a dictionary? + * ----------------------------------- + * + * You should retrain a dictionary when its effectiveness drops. Dictionary + * effectiveness drops as the data you are compressing changes. Generally, we do + * expect dictionaries to "decay" over time, as your data changes, but the rate + * at which they decay depends on your use case. Internally, we regularly + * retrain dictionaries, and if the new dictionary performs significantly + * better than the old dictionary, we will ship the new dictionary. + * + * I have a raw content dictionary, how do I turn it into a zstd dictionary? + * ------------------------------------------------------------------------- + * + * If you have a raw content dictionary, e.g. by manually constructing it, or + * using a third-party dictionary builder, you can turn it into a zstd + * dictionary by using `ZDICT_finalizeDictionary()`. You'll also have to + * provide some samples of the data. It will add the zstd header to the + * raw content, which contains a dictionary ID and entropy tables, which + * will improve compression ratio, and allow zstd to write the dictionary ID + * into the frame, if you so choose. + * + * Do I have to use zstd's dictionary builder? + * ------------------------------------------- + * + * No! You can construct dictionary content however you please, it is just + * bytes. It will always be valid as a raw content dictionary. If you want + * a zstd dictionary, which can improve compression ratio, use + * `ZDICT_finalizeDictionary()`. + * + * What is the attack surface of a zstd dictionary? + * ------------------------------------------------ + * + * Zstd is heavily fuzz tested, including loading fuzzed dictionaries, so + * zstd should never crash, or access out-of-bounds memory no matter what + * the dictionary is. However, if an attacker can control the dictionary + * during decompression, they can cause zstd to generate arbitrary bytes, + * just like if they controlled the compressed data. + * + ******************************************************************************/ + + +/*! ZDICT_trainFromBuffer(): + * Train a dictionary from an array of samples. + * Redirect towards ZDICT_optimizeTrainFromBuffer_fastCover() single-threaded, with d=8, steps=4, + * f=20, and accel=1. + * Samples must be stored concatenated in a single flat buffer `samplesBuffer`, + * supplied with an array of sizes `samplesSizes`, providing the size of each sample, in order. + * The resulting dictionary will be saved into `dictBuffer`. + * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`) + * or an error code, which can be tested with ZDICT_isError(). + * Note: Dictionary training will fail if there are not enough samples to construct a + * dictionary, or if most of the samples are too small (< 8 bytes being the lower limit). + * If dictionary training fails, you should use zstd without a dictionary, as the dictionary + * would've been ineffective anyways. If you believe your samples would benefit from a dictionary + * please open an issue with details, and we can look into it. + * Note: ZDICT_trainFromBuffer()'s memory usage is about 6 MB. + * Tips: In general, a reasonable dictionary has a size of ~ 100 KB. + * It's possible to select smaller or larger size, just by specifying `dictBufferCapacity`. + * In general, it's recommended to provide a few thousands samples, though this can vary a lot. + * It's recommended that total size of all samples be about ~x100 times the target size of dictionary. + */ +ZDICTLIB_API size_t ZDICT_trainFromBuffer(void* dictBuffer, size_t dictBufferCapacity, + const void* samplesBuffer, + const size_t* samplesSizes, unsigned nbSamples); + +typedef struct { + int compressionLevel; /**< optimize for a specific zstd compression level; 0 means default */ + unsigned notificationLevel; /**< Write log to stderr; 0 = none (default); 1 = errors; 2 = progression; 3 = details; 4 = debug; */ + unsigned dictID; /**< force dictID value; 0 means auto mode (32-bits random value) + * NOTE: The zstd format reserves some dictionary IDs for future use. + * You may use them in private settings, but be warned that they + * may be used by zstd in a public dictionary registry in the future. + * These dictionary IDs are: + * - low range : <= 32767 + * - high range : >= (2^31) + */ +} ZDICT_params_t; + +/*! ZDICT_finalizeDictionary(): + * Given a custom content as a basis for dictionary, and a set of samples, + * finalize dictionary by adding headers and statistics according to the zstd + * dictionary format. + * + * Samples must be stored concatenated in a flat buffer `samplesBuffer`, + * supplied with an array of sizes `samplesSizes`, providing the size of each + * sample in order. The samples are used to construct the statistics, so they + * should be representative of what you will compress with this dictionary. + * + * The compression level can be set in `parameters`. You should pass the + * compression level you expect to use in production. The statistics for each + * compression level differ, so tuning the dictionary for the compression level + * can help quite a bit. + * + * You can set an explicit dictionary ID in `parameters`, or allow us to pick + * a random dictionary ID for you, but we can't guarantee no collisions. + * + * The dstDictBuffer and the dictContent may overlap, and the content will be + * appended to the end of the header. If the header + the content doesn't fit in + * maxDictSize the beginning of the content is truncated to make room, since it + * is presumed that the most profitable content is at the end of the dictionary, + * since that is the cheapest to reference. + * + * `maxDictSize` must be >= max(dictContentSize, ZSTD_DICTSIZE_MIN). + * + * @return: size of dictionary stored into `dstDictBuffer` (<= `maxDictSize`), + * or an error code, which can be tested by ZDICT_isError(). + * Note: ZDICT_finalizeDictionary() will push notifications into stderr if + * instructed to, using notificationLevel>0. + * NOTE: This function currently may fail in several edge cases including: + * * Not enough samples + * * Samples are uncompressible + * * Samples are all exactly the same + */ +ZDICTLIB_API size_t ZDICT_finalizeDictionary(void* dstDictBuffer, size_t maxDictSize, + const void* dictContent, size_t dictContentSize, + const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, + ZDICT_params_t parameters); + + +/*====== Helper functions ======*/ +ZDICTLIB_API unsigned ZDICT_getDictID(const void* dictBuffer, size_t dictSize); /**< extracts dictID; @return zero if error (not a valid dictionary) */ +ZDICTLIB_API size_t ZDICT_getDictHeaderSize(const void* dictBuffer, size_t dictSize); /* returns dict header size; returns a ZSTD error code on failure */ +ZDICTLIB_API unsigned ZDICT_isError(size_t errorCode); +ZDICTLIB_API const char* ZDICT_getErrorName(size_t errorCode); + +#endif /* ZSTD_ZDICT_H */ + +#if defined(ZDICT_STATIC_LINKING_ONLY) && !defined(ZSTD_ZDICT_H_STATIC) +#define ZSTD_ZDICT_H_STATIC + +/* This can be overridden externally to hide static symbols. */ +#ifndef ZDICTLIB_STATIC_API +# if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) +# define ZDICTLIB_STATIC_API __declspec(dllexport) ZDICTLIB_VISIBLE +# elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) +# define ZDICTLIB_STATIC_API __declspec(dllimport) ZDICTLIB_VISIBLE +# else +# define ZDICTLIB_STATIC_API ZDICTLIB_VISIBLE +# endif +#endif + +/* ==================================================================================== + * The definitions in this section are considered experimental. + * They should never be used with a dynamic library, as they may change in the future. + * They are provided for advanced usages. + * Use them only in association with static linking. + * ==================================================================================== */ + +#define ZDICT_DICTSIZE_MIN 256 +/* Deprecated: Remove in v1.6.0 */ +#define ZDICT_CONTENTSIZE_MIN 128 + +/*! ZDICT_cover_params_t: + * k and d are the only required parameters. + * For others, value 0 means default. + */ +typedef struct { + unsigned k; /* Segment size : constraint: 0 < k : Reasonable range [16, 2048+] */ + unsigned d; /* dmer size : constraint: 0 < d <= k : Reasonable range [6, 16] */ + unsigned steps; /* Number of steps : Only used for optimization : 0 means default (40) : Higher means more parameters checked */ + unsigned nbThreads; /* Number of threads : constraint: 0 < nbThreads : 1 means single-threaded : Only used for optimization : Ignored if ZSTD_MULTITHREAD is not defined */ + double splitPoint; /* Percentage of samples used for training: Only used for optimization : the first nbSamples * splitPoint samples will be used to training, the last nbSamples * (1 - splitPoint) samples will be used for testing, 0 means default (1.0), 1.0 when all samples are used for both training and testing */ + unsigned shrinkDict; /* Train dictionaries to shrink in size starting from the minimum size and selects the smallest dictionary that is shrinkDictMaxRegression% worse than the largest dictionary. 0 means no shrinking and 1 means shrinking */ + unsigned shrinkDictMaxRegression; /* Sets shrinkDictMaxRegression so that a smaller dictionary can be at worse shrinkDictMaxRegression% worse than the max dict size dictionary. */ + ZDICT_params_t zParams; +} ZDICT_cover_params_t; + +typedef struct { + unsigned k; /* Segment size : constraint: 0 < k : Reasonable range [16, 2048+] */ + unsigned d; /* dmer size : constraint: 0 < d <= k : Reasonable range [6, 16] */ + unsigned f; /* log of size of frequency array : constraint: 0 < f <= 31 : 1 means default(20)*/ + unsigned steps; /* Number of steps : Only used for optimization : 0 means default (40) : Higher means more parameters checked */ + unsigned nbThreads; /* Number of threads : constraint: 0 < nbThreads : 1 means single-threaded : Only used for optimization : Ignored if ZSTD_MULTITHREAD is not defined */ + double splitPoint; /* Percentage of samples used for training: Only used for optimization : the first nbSamples * splitPoint samples will be used to training, the last nbSamples * (1 - splitPoint) samples will be used for testing, 0 means default (0.75), 1.0 when all samples are used for both training and testing */ + unsigned accel; /* Acceleration level: constraint: 0 < accel <= 10, higher means faster and less accurate, 0 means default(1) */ + unsigned shrinkDict; /* Train dictionaries to shrink in size starting from the minimum size and selects the smallest dictionary that is shrinkDictMaxRegression% worse than the largest dictionary. 0 means no shrinking and 1 means shrinking */ + unsigned shrinkDictMaxRegression; /* Sets shrinkDictMaxRegression so that a smaller dictionary can be at worse shrinkDictMaxRegression% worse than the max dict size dictionary. */ + + ZDICT_params_t zParams; +} ZDICT_fastCover_params_t; + +/*! ZDICT_trainFromBuffer_cover(): + * Train a dictionary from an array of samples using the COVER algorithm. + * Samples must be stored concatenated in a single flat buffer `samplesBuffer`, + * supplied with an array of sizes `samplesSizes`, providing the size of each sample, in order. + * The resulting dictionary will be saved into `dictBuffer`. + * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`) + * or an error code, which can be tested with ZDICT_isError(). + * See ZDICT_trainFromBuffer() for details on failure modes. + * Note: ZDICT_trainFromBuffer_cover() requires about 9 bytes of memory for each input byte. + * Tips: In general, a reasonable dictionary has a size of ~ 100 KB. + * It's possible to select smaller or larger size, just by specifying `dictBufferCapacity`. + * In general, it's recommended to provide a few thousands samples, though this can vary a lot. + * It's recommended that total size of all samples be about ~x100 times the target size of dictionary. + */ +ZDICTLIB_STATIC_API size_t ZDICT_trainFromBuffer_cover( + void *dictBuffer, size_t dictBufferCapacity, + const void *samplesBuffer, const size_t *samplesSizes, unsigned nbSamples, + ZDICT_cover_params_t parameters); + +/*! ZDICT_optimizeTrainFromBuffer_cover(): + * The same requirements as above hold for all the parameters except `parameters`. + * This function tries many parameter combinations and picks the best parameters. + * `*parameters` is filled with the best parameters found, + * dictionary constructed with those parameters is stored in `dictBuffer`. + * + * All of the parameters d, k, steps are optional. + * If d is non-zero then we don't check multiple values of d, otherwise we check d = {6, 8}. + * if steps is zero it defaults to its default value. + * If k is non-zero then we don't check multiple values of k, otherwise we check steps values in [50, 2000]. + * + * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`) + * or an error code, which can be tested with ZDICT_isError(). + * On success `*parameters` contains the parameters selected. + * See ZDICT_trainFromBuffer() for details on failure modes. + * Note: ZDICT_optimizeTrainFromBuffer_cover() requires about 8 bytes of memory for each input byte and additionally another 5 bytes of memory for each byte of memory for each thread. + */ +ZDICTLIB_STATIC_API size_t ZDICT_optimizeTrainFromBuffer_cover( + void* dictBuffer, size_t dictBufferCapacity, + const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, + ZDICT_cover_params_t* parameters); + +/*! ZDICT_trainFromBuffer_fastCover(): + * Train a dictionary from an array of samples using a modified version of COVER algorithm. + * Samples must be stored concatenated in a single flat buffer `samplesBuffer`, + * supplied with an array of sizes `samplesSizes`, providing the size of each sample, in order. + * d and k are required. + * All other parameters are optional, will use default values if not provided + * The resulting dictionary will be saved into `dictBuffer`. + * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`) + * or an error code, which can be tested with ZDICT_isError(). + * See ZDICT_trainFromBuffer() for details on failure modes. + * Note: ZDICT_trainFromBuffer_fastCover() requires 6 * 2^f bytes of memory. + * Tips: In general, a reasonable dictionary has a size of ~ 100 KB. + * It's possible to select smaller or larger size, just by specifying `dictBufferCapacity`. + * In general, it's recommended to provide a few thousands samples, though this can vary a lot. + * It's recommended that total size of all samples be about ~x100 times the target size of dictionary. + */ +ZDICTLIB_STATIC_API size_t ZDICT_trainFromBuffer_fastCover(void *dictBuffer, + size_t dictBufferCapacity, const void *samplesBuffer, + const size_t *samplesSizes, unsigned nbSamples, + ZDICT_fastCover_params_t parameters); + +/*! ZDICT_optimizeTrainFromBuffer_fastCover(): + * The same requirements as above hold for all the parameters except `parameters`. + * This function tries many parameter combinations (specifically, k and d combinations) + * and picks the best parameters. `*parameters` is filled with the best parameters found, + * dictionary constructed with those parameters is stored in `dictBuffer`. + * All of the parameters d, k, steps, f, and accel are optional. + * If d is non-zero then we don't check multiple values of d, otherwise we check d = {6, 8}. + * if steps is zero it defaults to its default value. + * If k is non-zero then we don't check multiple values of k, otherwise we check steps values in [50, 2000]. + * If f is zero, default value of 20 is used. + * If accel is zero, default value of 1 is used. + * + * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`) + * or an error code, which can be tested with ZDICT_isError(). + * On success `*parameters` contains the parameters selected. + * See ZDICT_trainFromBuffer() for details on failure modes. + * Note: ZDICT_optimizeTrainFromBuffer_fastCover() requires about 6 * 2^f bytes of memory for each thread. + */ +ZDICTLIB_STATIC_API size_t ZDICT_optimizeTrainFromBuffer_fastCover(void* dictBuffer, + size_t dictBufferCapacity, const void* samplesBuffer, + const size_t* samplesSizes, unsigned nbSamples, + ZDICT_fastCover_params_t* parameters); + +typedef struct { + unsigned selectivityLevel; /* 0 means default; larger => select more => larger dictionary */ + ZDICT_params_t zParams; +} ZDICT_legacy_params_t; + +/*! ZDICT_trainFromBuffer_legacy(): + * Train a dictionary from an array of samples. + * Samples must be stored concatenated in a single flat buffer `samplesBuffer`, + * supplied with an array of sizes `samplesSizes`, providing the size of each sample, in order. + * The resulting dictionary will be saved into `dictBuffer`. + * `parameters` is optional and can be provided with values set to 0 to mean "default". + * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`) + * or an error code, which can be tested with ZDICT_isError(). + * See ZDICT_trainFromBuffer() for details on failure modes. + * Tips: In general, a reasonable dictionary has a size of ~ 100 KB. + * It's possible to select smaller or larger size, just by specifying `dictBufferCapacity`. + * In general, it's recommended to provide a few thousands samples, though this can vary a lot. + * It's recommended that total size of all samples be about ~x100 times the target size of dictionary. + * Note: ZDICT_trainFromBuffer_legacy() will send notifications into stderr if instructed to, using notificationLevel>0. + */ +ZDICTLIB_STATIC_API size_t ZDICT_trainFromBuffer_legacy( + void* dictBuffer, size_t dictBufferCapacity, + const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, + ZDICT_legacy_params_t parameters); + + +/* Deprecation warnings */ +/* It is generally possible to disable deprecation warnings from compiler, + for example with -Wno-deprecated-declarations for gcc + or _CRT_SECURE_NO_WARNINGS in Visual. + Otherwise, it's also possible to manually define ZDICT_DISABLE_DEPRECATE_WARNINGS */ +#ifdef ZDICT_DISABLE_DEPRECATE_WARNINGS +# define ZDICT_DEPRECATED(message) /* disable deprecation warnings */ +#else +# define ZDICT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +# if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */ +# define ZDICT_DEPRECATED(message) [[deprecated(message)]] +# elif defined(__clang__) || (ZDICT_GCC_VERSION >= 405) +# define ZDICT_DEPRECATED(message) __attribute__((deprecated(message))) +# elif (ZDICT_GCC_VERSION >= 301) +# define ZDICT_DEPRECATED(message) __attribute__((deprecated)) +# elif defined(_MSC_VER) +# define ZDICT_DEPRECATED(message) __declspec(deprecated(message)) +# else +# pragma message("WARNING: You need to implement ZDICT_DEPRECATED for this compiler") +# define ZDICT_DEPRECATED(message) +# endif +#endif /* ZDICT_DISABLE_DEPRECATE_WARNINGS */ + +ZDICT_DEPRECATED("use ZDICT_finalizeDictionary() instead") +ZDICTLIB_STATIC_API +size_t ZDICT_addEntropyTablesFromBuffer(void* dictBuffer, size_t dictContentSize, size_t dictBufferCapacity, + const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples); + + +#endif /* ZSTD_ZDICT_H_STATIC */ + +#if defined (__cplusplus) +} +#endif diff --git a/lib/zstd/lib/zstd.h b/lib/zstd/lib/zstd.h new file mode 100644 index 0000000..e5c3f8b --- /dev/null +++ b/lib/zstd/lib/zstd.h @@ -0,0 +1,3020 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ +#if defined (__cplusplus) +extern "C" { +#endif + +#ifndef ZSTD_H_235446 +#define ZSTD_H_235446 + +/* ====== Dependencies ======*/ +#include /* INT_MAX */ +#include /* size_t */ + + +/* ===== ZSTDLIB_API : control library symbols visibility ===== */ +#ifndef ZSTDLIB_VISIBLE + /* Backwards compatibility with old macro name */ +# ifdef ZSTDLIB_VISIBILITY +# define ZSTDLIB_VISIBLE ZSTDLIB_VISIBILITY +# elif defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) +# define ZSTDLIB_VISIBLE __attribute__ ((visibility ("default"))) +# else +# define ZSTDLIB_VISIBLE +# endif +#endif + +#ifndef ZSTDLIB_HIDDEN +# if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) +# define ZSTDLIB_HIDDEN __attribute__ ((visibility ("hidden"))) +# else +# define ZSTDLIB_HIDDEN +# endif +#endif + +#if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) +# define ZSTDLIB_API __declspec(dllexport) ZSTDLIB_VISIBLE +#elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) +# define ZSTDLIB_API __declspec(dllimport) ZSTDLIB_VISIBLE /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ +#else +# define ZSTDLIB_API ZSTDLIB_VISIBLE +#endif + +/* Deprecation warnings : + * Should these warnings be a problem, it is generally possible to disable them, + * typically with -Wno-deprecated-declarations for gcc or _CRT_SECURE_NO_WARNINGS in Visual. + * Otherwise, it's also possible to define ZSTD_DISABLE_DEPRECATE_WARNINGS. + */ +#ifdef ZSTD_DISABLE_DEPRECATE_WARNINGS +# define ZSTD_DEPRECATED(message) /* disable deprecation warnings */ +#else +# if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */ +# define ZSTD_DEPRECATED(message) [[deprecated(message)]] +# elif (defined(GNUC) && (GNUC > 4 || (GNUC == 4 && GNUC_MINOR >= 5))) || defined(__clang__) +# define ZSTD_DEPRECATED(message) __attribute__((deprecated(message))) +# elif defined(__GNUC__) && (__GNUC__ >= 3) +# define ZSTD_DEPRECATED(message) __attribute__((deprecated)) +# elif defined(_MSC_VER) +# define ZSTD_DEPRECATED(message) __declspec(deprecated(message)) +# else +# pragma message("WARNING: You need to implement ZSTD_DEPRECATED for this compiler") +# define ZSTD_DEPRECATED(message) +# endif +#endif /* ZSTD_DISABLE_DEPRECATE_WARNINGS */ + + +/******************************************************************************* + Introduction + + zstd, short for Zstandard, is a fast lossless compression algorithm, targeting + real-time compression scenarios at zlib-level and better compression ratios. + The zstd compression library provides in-memory compression and decompression + functions. + + The library supports regular compression levels from 1 up to ZSTD_maxCLevel(), + which is currently 22. Levels >= 20, labeled `--ultra`, should be used with + caution, as they require more memory. The library also offers negative + compression levels, which extend the range of speed vs. ratio preferences. + The lower the level, the faster the speed (at the cost of compression). + + Compression can be done in: + - a single step (described as Simple API) + - a single step, reusing a context (described as Explicit context) + - unbounded multiple steps (described as Streaming compression) + + The compression ratio achievable on small data can be highly improved using + a dictionary. Dictionary compression can be performed in: + - a single step (described as Simple dictionary API) + - a single step, reusing a dictionary (described as Bulk-processing + dictionary API) + + Advanced experimental functions can be accessed using + `#define ZSTD_STATIC_LINKING_ONLY` before including zstd.h. + + Advanced experimental APIs should never be used with a dynamically-linked + library. They are not "stable"; their definitions or signatures may change in + the future. Only static linking is allowed. +*******************************************************************************/ + +/*------ Version ------*/ +#define ZSTD_VERSION_MAJOR 1 +#define ZSTD_VERSION_MINOR 5 +#define ZSTD_VERSION_RELEASE 5 +#define ZSTD_VERSION_NUMBER (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE) + +/*! ZSTD_versionNumber() : + * Return runtime library version, the value is (MAJOR*100*100 + MINOR*100 + RELEASE). */ +ZSTDLIB_API unsigned ZSTD_versionNumber(void); + +#define ZSTD_LIB_VERSION ZSTD_VERSION_MAJOR.ZSTD_VERSION_MINOR.ZSTD_VERSION_RELEASE +#define ZSTD_QUOTE(str) #str +#define ZSTD_EXPAND_AND_QUOTE(str) ZSTD_QUOTE(str) +#define ZSTD_VERSION_STRING ZSTD_EXPAND_AND_QUOTE(ZSTD_LIB_VERSION) + +/*! ZSTD_versionString() : + * Return runtime library version, like "1.4.5". Requires v1.3.0+. */ +ZSTDLIB_API const char* ZSTD_versionString(void); + +/* ************************************* + * Default constant + ***************************************/ +#ifndef ZSTD_CLEVEL_DEFAULT +# define ZSTD_CLEVEL_DEFAULT 3 +#endif + +/* ************************************* + * Constants + ***************************************/ + +/* All magic numbers are supposed read/written to/from files/memory using little-endian convention */ +#define ZSTD_MAGICNUMBER 0xFD2FB528 /* valid since v0.8.0 */ +#define ZSTD_MAGIC_DICTIONARY 0xEC30A437 /* valid since v0.7.0 */ +#define ZSTD_MAGIC_SKIPPABLE_START 0x184D2A50 /* all 16 values, from 0x184D2A50 to 0x184D2A5F, signal the beginning of a skippable frame */ +#define ZSTD_MAGIC_SKIPPABLE_MASK 0xFFFFFFF0 + +#define ZSTD_BLOCKSIZELOG_MAX 17 +#define ZSTD_BLOCKSIZE_MAX (1<= ZSTD_compressBound(srcSize)` guarantees that zstd will have + * enough space to successfully compress the data. + * @return : compressed size written into `dst` (<= `dstCapacity), + * or an error code if it fails (which can be tested using ZSTD_isError()). */ +ZSTDLIB_API size_t ZSTD_compress( void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + int compressionLevel); + +/*! ZSTD_decompress() : + * `compressedSize` : must be the _exact_ size of some number of compressed and/or skippable frames. + * `dstCapacity` is an upper bound of originalSize to regenerate. + * If user cannot imply a maximum upper bound, it's better to use streaming mode to decompress data. + * @return : the number of bytes decompressed into `dst` (<= `dstCapacity`), + * or an errorCode if it fails (which can be tested using ZSTD_isError()). */ +ZSTDLIB_API size_t ZSTD_decompress( void* dst, size_t dstCapacity, + const void* src, size_t compressedSize); + +/*! ZSTD_getFrameContentSize() : requires v1.3.0+ + * `src` should point to the start of a ZSTD encoded frame. + * `srcSize` must be at least as large as the frame header. + * hint : any size >= `ZSTD_frameHeaderSize_max` is large enough. + * @return : - decompressed size of `src` frame content, if known + * - ZSTD_CONTENTSIZE_UNKNOWN if the size cannot be determined + * - ZSTD_CONTENTSIZE_ERROR if an error occurred (e.g. invalid magic number, srcSize too small) + * note 1 : a 0 return value means the frame is valid but "empty". + * note 2 : decompressed size is an optional field, it may not be present, typically in streaming mode. + * When `return==ZSTD_CONTENTSIZE_UNKNOWN`, data to decompress could be any size. + * In which case, it's necessary to use streaming mode to decompress data. + * Optionally, application can rely on some implicit limit, + * as ZSTD_decompress() only needs an upper bound of decompressed size. + * (For example, data could be necessarily cut into blocks <= 16 KB). + * note 3 : decompressed size is always present when compression is completed using single-pass functions, + * such as ZSTD_compress(), ZSTD_compressCCtx() ZSTD_compress_usingDict() or ZSTD_compress_usingCDict(). + * note 4 : decompressed size can be very large (64-bits value), + * potentially larger than what local system can handle as a single memory segment. + * In which case, it's necessary to use streaming mode to decompress data. + * note 5 : If source is untrusted, decompressed size could be wrong or intentionally modified. + * Always ensure return value fits within application's authorized limits. + * Each application can set its own limits. + * note 6 : This function replaces ZSTD_getDecompressedSize() */ +#define ZSTD_CONTENTSIZE_UNKNOWN (0ULL - 1) +#define ZSTD_CONTENTSIZE_ERROR (0ULL - 2) +ZSTDLIB_API unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize); + +/*! ZSTD_getDecompressedSize() : + * NOTE: This function is now obsolete, in favor of ZSTD_getFrameContentSize(). + * Both functions work the same way, but ZSTD_getDecompressedSize() blends + * "empty", "unknown" and "error" results to the same return value (0), + * while ZSTD_getFrameContentSize() gives them separate return values. + * @return : decompressed size of `src` frame content _if known and not empty_, 0 otherwise. */ +ZSTD_DEPRECATED("Replaced by ZSTD_getFrameContentSize") +ZSTDLIB_API +unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize); + +/*! ZSTD_findFrameCompressedSize() : Requires v1.4.0+ + * `src` should point to the start of a ZSTD frame or skippable frame. + * `srcSize` must be >= first frame size + * @return : the compressed size of the first frame starting at `src`, + * suitable to pass as `srcSize` to `ZSTD_decompress` or similar, + * or an error code if input is invalid */ +ZSTDLIB_API size_t ZSTD_findFrameCompressedSize(const void* src, size_t srcSize); + + +/*====== Helper functions ======*/ +/* ZSTD_compressBound() : + * maximum compressed size in worst case single-pass scenario. + * When invoking `ZSTD_compress()` or any other one-pass compression function, + * it's recommended to provide @dstCapacity >= ZSTD_compressBound(srcSize) + * as it eliminates one potential failure scenario, + * aka not enough room in dst buffer to write the compressed frame. + * Note : ZSTD_compressBound() itself can fail, if @srcSize > ZSTD_MAX_INPUT_SIZE . + * In which case, ZSTD_compressBound() will return an error code + * which can be tested using ZSTD_isError(). + * + * ZSTD_COMPRESSBOUND() : + * same as ZSTD_compressBound(), but as a macro. + * It can be used to produce constants, which can be useful for static allocation, + * for example to size a static array on stack. + * Will produce constant value 0 if srcSize too large. + */ +#define ZSTD_MAX_INPUT_SIZE ((sizeof(size_t)==8) ? 0xFF00FF00FF00FF00LLU : 0xFF00FF00U) +#define ZSTD_COMPRESSBOUND(srcSize) (((size_t)(srcSize) >= ZSTD_MAX_INPUT_SIZE) ? 0 : (srcSize) + ((srcSize)>>8) + (((srcSize) < (128<<10)) ? (((128<<10) - (srcSize)) >> 11) /* margin, from 64 to 0 */ : 0)) /* this formula ensures that bound(A) + bound(B) <= bound(A+B) as long as A and B >= 128 KB */ +ZSTDLIB_API size_t ZSTD_compressBound(size_t srcSize); /*!< maximum compressed size in worst case single-pass scenario */ +/* ZSTD_isError() : + * Most ZSTD_* functions returning a size_t value can be tested for error, + * using ZSTD_isError(). + * @return 1 if error, 0 otherwise + */ +ZSTDLIB_API unsigned ZSTD_isError(size_t code); /*!< tells if a `size_t` function result is an error code */ +ZSTDLIB_API const char* ZSTD_getErrorName(size_t code); /*!< provides readable string from an error code */ +ZSTDLIB_API int ZSTD_minCLevel(void); /*!< minimum negative compression level allowed, requires v1.4.0+ */ +ZSTDLIB_API int ZSTD_maxCLevel(void); /*!< maximum compression level available */ +ZSTDLIB_API int ZSTD_defaultCLevel(void); /*!< default compression level, specified by ZSTD_CLEVEL_DEFAULT, requires v1.5.0+ */ + + +/*************************************** +* Explicit context +***************************************/ +/*= Compression context + * When compressing many times, + * it is recommended to allocate a context just once, + * and re-use it for each successive compression operation. + * This will make workload friendlier for system's memory. + * Note : re-using context is just a speed / resource optimization. + * It doesn't change the compression ratio, which remains identical. + * Note 2 : In multi-threaded environments, + * use one different context per thread for parallel execution. + */ +typedef struct ZSTD_CCtx_s ZSTD_CCtx; +ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx(void); +ZSTDLIB_API size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx); /* accept NULL pointer */ + +/*! ZSTD_compressCCtx() : + * Same as ZSTD_compress(), using an explicit ZSTD_CCtx. + * Important : in order to behave similarly to `ZSTD_compress()`, + * this function compresses at requested compression level, + * __ignoring any other parameter__ . + * If any advanced parameter was set using the advanced API, + * they will all be reset. Only `compressionLevel` remains. + */ +ZSTDLIB_API size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + int compressionLevel); + +/*= Decompression context + * When decompressing many times, + * it is recommended to allocate a context only once, + * and re-use it for each successive compression operation. + * This will make workload friendlier for system's memory. + * Use one context per thread for parallel execution. */ +typedef struct ZSTD_DCtx_s ZSTD_DCtx; +ZSTDLIB_API ZSTD_DCtx* ZSTD_createDCtx(void); +ZSTDLIB_API size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx); /* accept NULL pointer */ + +/*! ZSTD_decompressDCtx() : + * Same as ZSTD_decompress(), + * requires an allocated ZSTD_DCtx. + * Compatible with sticky parameters. + */ +ZSTDLIB_API size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize); + + +/********************************************* +* Advanced compression API (Requires v1.4.0+) +**********************************************/ + +/* API design : + * Parameters are pushed one by one into an existing context, + * using ZSTD_CCtx_set*() functions. + * Pushed parameters are sticky : they are valid for next compressed frame, and any subsequent frame. + * "sticky" parameters are applicable to `ZSTD_compress2()` and `ZSTD_compressStream*()` ! + * __They do not apply to "simple" one-shot variants such as ZSTD_compressCCtx()__ . + * + * It's possible to reset all parameters to "default" using ZSTD_CCtx_reset(). + * + * This API supersedes all other "advanced" API entry points in the experimental section. + * In the future, we expect to remove from experimental API entry points which are redundant with this API. + */ + + +/* Compression strategies, listed from fastest to strongest */ +typedef enum { ZSTD_fast=1, + ZSTD_dfast=2, + ZSTD_greedy=3, + ZSTD_lazy=4, + ZSTD_lazy2=5, + ZSTD_btlazy2=6, + ZSTD_btopt=7, + ZSTD_btultra=8, + ZSTD_btultra2=9 + /* note : new strategies _might_ be added in the future. + Only the order (from fast to strong) is guaranteed */ +} ZSTD_strategy; + +typedef enum { + + /* compression parameters + * Note: When compressing with a ZSTD_CDict these parameters are superseded + * by the parameters used to construct the ZSTD_CDict. + * See ZSTD_CCtx_refCDict() for more info (superseded-by-cdict). */ + ZSTD_c_compressionLevel=100, /* Set compression parameters according to pre-defined cLevel table. + * Note that exact compression parameters are dynamically determined, + * depending on both compression level and srcSize (when known). + * Default level is ZSTD_CLEVEL_DEFAULT==3. + * Special: value 0 means default, which is controlled by ZSTD_CLEVEL_DEFAULT. + * Note 1 : it's possible to pass a negative compression level. + * Note 2 : setting a level does not automatically set all other compression parameters + * to default. Setting this will however eventually dynamically impact the compression + * parameters which have not been manually set. The manually set + * ones will 'stick'. */ + /* Advanced compression parameters : + * It's possible to pin down compression parameters to some specific values. + * In which case, these values are no longer dynamically selected by the compressor */ + ZSTD_c_windowLog=101, /* Maximum allowed back-reference distance, expressed as power of 2. + * This will set a memory budget for streaming decompression, + * with larger values requiring more memory + * and typically compressing more. + * Must be clamped between ZSTD_WINDOWLOG_MIN and ZSTD_WINDOWLOG_MAX. + * Special: value 0 means "use default windowLog". + * Note: Using a windowLog greater than ZSTD_WINDOWLOG_LIMIT_DEFAULT + * requires explicitly allowing such size at streaming decompression stage. */ + ZSTD_c_hashLog=102, /* Size of the initial probe table, as a power of 2. + * Resulting memory usage is (1 << (hashLog+2)). + * Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX. + * Larger tables improve compression ratio of strategies <= dFast, + * and improve speed of strategies > dFast. + * Special: value 0 means "use default hashLog". */ + ZSTD_c_chainLog=103, /* Size of the multi-probe search table, as a power of 2. + * Resulting memory usage is (1 << (chainLog+2)). + * Must be clamped between ZSTD_CHAINLOG_MIN and ZSTD_CHAINLOG_MAX. + * Larger tables result in better and slower compression. + * This parameter is useless for "fast" strategy. + * It's still useful when using "dfast" strategy, + * in which case it defines a secondary probe table. + * Special: value 0 means "use default chainLog". */ + ZSTD_c_searchLog=104, /* Number of search attempts, as a power of 2. + * More attempts result in better and slower compression. + * This parameter is useless for "fast" and "dFast" strategies. + * Special: value 0 means "use default searchLog". */ + ZSTD_c_minMatch=105, /* Minimum size of searched matches. + * Note that Zstandard can still find matches of smaller size, + * it just tweaks its search algorithm to look for this size and larger. + * Larger values increase compression and decompression speed, but decrease ratio. + * Must be clamped between ZSTD_MINMATCH_MIN and ZSTD_MINMATCH_MAX. + * Note that currently, for all strategies < btopt, effective minimum is 4. + * , for all strategies > fast, effective maximum is 6. + * Special: value 0 means "use default minMatchLength". */ + ZSTD_c_targetLength=106, /* Impact of this field depends on strategy. + * For strategies btopt, btultra & btultra2: + * Length of Match considered "good enough" to stop search. + * Larger values make compression stronger, and slower. + * For strategy fast: + * Distance between match sampling. + * Larger values make compression faster, and weaker. + * Special: value 0 means "use default targetLength". */ + ZSTD_c_strategy=107, /* See ZSTD_strategy enum definition. + * The higher the value of selected strategy, the more complex it is, + * resulting in stronger and slower compression. + * Special: value 0 means "use default strategy". */ + /* LDM mode parameters */ + ZSTD_c_enableLongDistanceMatching=160, /* Enable long distance matching. + * This parameter is designed to improve compression ratio + * for large inputs, by finding large matches at long distance. + * It increases memory usage and window size. + * Note: enabling this parameter increases default ZSTD_c_windowLog to 128 MB + * except when expressly set to a different value. + * Note: will be enabled by default if ZSTD_c_windowLog >= 128 MB and + * compression strategy >= ZSTD_btopt (== compression level 16+) */ + ZSTD_c_ldmHashLog=161, /* Size of the table for long distance matching, as a power of 2. + * Larger values increase memory usage and compression ratio, + * but decrease compression speed. + * Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX + * default: windowlog - 7. + * Special: value 0 means "automatically determine hashlog". */ + ZSTD_c_ldmMinMatch=162, /* Minimum match size for long distance matcher. + * Larger/too small values usually decrease compression ratio. + * Must be clamped between ZSTD_LDM_MINMATCH_MIN and ZSTD_LDM_MINMATCH_MAX. + * Special: value 0 means "use default value" (default: 64). */ + ZSTD_c_ldmBucketSizeLog=163, /* Log size of each bucket in the LDM hash table for collision resolution. + * Larger values improve collision resolution but decrease compression speed. + * The maximum value is ZSTD_LDM_BUCKETSIZELOG_MAX. + * Special: value 0 means "use default value" (default: 3). */ + ZSTD_c_ldmHashRateLog=164, /* Frequency of inserting/looking up entries into the LDM hash table. + * Must be clamped between 0 and (ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN). + * Default is MAX(0, (windowLog - ldmHashLog)), optimizing hash table usage. + * Larger values improve compression speed. + * Deviating far from default value will likely result in a compression ratio decrease. + * Special: value 0 means "automatically determine hashRateLog". */ + + /* frame parameters */ + ZSTD_c_contentSizeFlag=200, /* Content size will be written into frame header _whenever known_ (default:1) + * Content size must be known at the beginning of compression. + * This is automatically the case when using ZSTD_compress2(), + * For streaming scenarios, content size must be provided with ZSTD_CCtx_setPledgedSrcSize() */ + ZSTD_c_checksumFlag=201, /* A 32-bits checksum of content is written at end of frame (default:0) */ + ZSTD_c_dictIDFlag=202, /* When applicable, dictionary's ID is written into frame header (default:1) */ + + /* multi-threading parameters */ + /* These parameters are only active if multi-threading is enabled (compiled with build macro ZSTD_MULTITHREAD). + * Otherwise, trying to set any other value than default (0) will be a no-op and return an error. + * In a situation where it's unknown if the linked library supports multi-threading or not, + * setting ZSTD_c_nbWorkers to any value >= 1 and consulting the return value provides a quick way to check this property. + */ + ZSTD_c_nbWorkers=400, /* Select how many threads will be spawned to compress in parallel. + * When nbWorkers >= 1, triggers asynchronous mode when invoking ZSTD_compressStream*() : + * ZSTD_compressStream*() consumes input and flush output if possible, but immediately gives back control to caller, + * while compression is performed in parallel, within worker thread(s). + * (note : a strong exception to this rule is when first invocation of ZSTD_compressStream2() sets ZSTD_e_end : + * in which case, ZSTD_compressStream2() delegates to ZSTD_compress2(), which is always a blocking call). + * More workers improve speed, but also increase memory usage. + * Default value is `0`, aka "single-threaded mode" : no worker is spawned, + * compression is performed inside Caller's thread, and all invocations are blocking */ + ZSTD_c_jobSize=401, /* Size of a compression job. This value is enforced only when nbWorkers >= 1. + * Each compression job is completed in parallel, so this value can indirectly impact the nb of active threads. + * 0 means default, which is dynamically determined based on compression parameters. + * Job size must be a minimum of overlap size, or ZSTDMT_JOBSIZE_MIN (= 512 KB), whichever is largest. + * The minimum size is automatically and transparently enforced. */ + ZSTD_c_overlapLog=402, /* Control the overlap size, as a fraction of window size. + * The overlap size is an amount of data reloaded from previous job at the beginning of a new job. + * It helps preserve compression ratio, while each job is compressed in parallel. + * This value is enforced only when nbWorkers >= 1. + * Larger values increase compression ratio, but decrease speed. + * Possible values range from 0 to 9 : + * - 0 means "default" : value will be determined by the library, depending on strategy + * - 1 means "no overlap" + * - 9 means "full overlap", using a full window size. + * Each intermediate rank increases/decreases load size by a factor 2 : + * 9: full window; 8: w/2; 7: w/4; 6: w/8; 5:w/16; 4: w/32; 3:w/64; 2:w/128; 1:no overlap; 0:default + * default value varies between 6 and 9, depending on strategy */ + + /* note : additional experimental parameters are also available + * within the experimental section of the API. + * At the time of this writing, they include : + * ZSTD_c_rsyncable + * ZSTD_c_format + * ZSTD_c_forceMaxWindow + * ZSTD_c_forceAttachDict + * ZSTD_c_literalCompressionMode + * ZSTD_c_targetCBlockSize + * ZSTD_c_srcSizeHint + * ZSTD_c_enableDedicatedDictSearch + * ZSTD_c_stableInBuffer + * ZSTD_c_stableOutBuffer + * ZSTD_c_blockDelimiters + * ZSTD_c_validateSequences + * ZSTD_c_useBlockSplitter + * ZSTD_c_useRowMatchFinder + * ZSTD_c_prefetchCDictTables + * ZSTD_c_enableSeqProducerFallback + * ZSTD_c_maxBlockSize + * Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them. + * note : never ever use experimentalParam? names directly; + * also, the enums values themselves are unstable and can still change. + */ + ZSTD_c_experimentalParam1=500, + ZSTD_c_experimentalParam2=10, + ZSTD_c_experimentalParam3=1000, + ZSTD_c_experimentalParam4=1001, + ZSTD_c_experimentalParam5=1002, + ZSTD_c_experimentalParam6=1003, + ZSTD_c_experimentalParam7=1004, + ZSTD_c_experimentalParam8=1005, + ZSTD_c_experimentalParam9=1006, + ZSTD_c_experimentalParam10=1007, + ZSTD_c_experimentalParam11=1008, + ZSTD_c_experimentalParam12=1009, + ZSTD_c_experimentalParam13=1010, + ZSTD_c_experimentalParam14=1011, + ZSTD_c_experimentalParam15=1012, + ZSTD_c_experimentalParam16=1013, + ZSTD_c_experimentalParam17=1014, + ZSTD_c_experimentalParam18=1015, + ZSTD_c_experimentalParam19=1016 +} ZSTD_cParameter; + +typedef struct { + size_t error; + int lowerBound; + int upperBound; +} ZSTD_bounds; + +/*! ZSTD_cParam_getBounds() : + * All parameters must belong to an interval with lower and upper bounds, + * otherwise they will either trigger an error or be automatically clamped. + * @return : a structure, ZSTD_bounds, which contains + * - an error status field, which must be tested using ZSTD_isError() + * - lower and upper bounds, both inclusive + */ +ZSTDLIB_API ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter cParam); + +/*! ZSTD_CCtx_setParameter() : + * Set one compression parameter, selected by enum ZSTD_cParameter. + * All parameters have valid bounds. Bounds can be queried using ZSTD_cParam_getBounds(). + * Providing a value beyond bound will either clamp it, or trigger an error (depending on parameter). + * Setting a parameter is generally only possible during frame initialization (before starting compression). + * Exception : when using multi-threading mode (nbWorkers >= 1), + * the following parameters can be updated _during_ compression (within same frame): + * => compressionLevel, hashLog, chainLog, searchLog, minMatch, targetLength and strategy. + * new parameters will be active for next job only (after a flush()). + * @return : an error code (which can be tested using ZSTD_isError()). + */ +ZSTDLIB_API size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value); + +/*! ZSTD_CCtx_setPledgedSrcSize() : + * Total input data size to be compressed as a single frame. + * Value will be written in frame header, unless if explicitly forbidden using ZSTD_c_contentSizeFlag. + * This value will also be controlled at end of frame, and trigger an error if not respected. + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + * Note 1 : pledgedSrcSize==0 actually means zero, aka an empty frame. + * In order to mean "unknown content size", pass constant ZSTD_CONTENTSIZE_UNKNOWN. + * ZSTD_CONTENTSIZE_UNKNOWN is default value for any new frame. + * Note 2 : pledgedSrcSize is only valid once, for the next frame. + * It's discarded at the end of the frame, and replaced by ZSTD_CONTENTSIZE_UNKNOWN. + * Note 3 : Whenever all input data is provided and consumed in a single round, + * for example with ZSTD_compress2(), + * or invoking immediately ZSTD_compressStream2(,,,ZSTD_e_end), + * this value is automatically overridden by srcSize instead. + */ +ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize); + +typedef enum { + ZSTD_reset_session_only = 1, + ZSTD_reset_parameters = 2, + ZSTD_reset_session_and_parameters = 3 +} ZSTD_ResetDirective; + +/*! ZSTD_CCtx_reset() : + * There are 2 different things that can be reset, independently or jointly : + * - The session : will stop compressing current frame, and make CCtx ready to start a new one. + * Useful after an error, or to interrupt any ongoing compression. + * Any internal data not yet flushed is cancelled. + * Compression parameters and dictionary remain unchanged. + * They will be used to compress next frame. + * Resetting session never fails. + * - The parameters : changes all parameters back to "default". + * This also removes any reference to any dictionary or external sequence producer. + * Parameters can only be changed between 2 sessions (i.e. no compression is currently ongoing) + * otherwise the reset fails, and function returns an error value (which can be tested using ZSTD_isError()) + * - Both : similar to resetting the session, followed by resetting parameters. + */ +ZSTDLIB_API size_t ZSTD_CCtx_reset(ZSTD_CCtx* cctx, ZSTD_ResetDirective reset); + +/*! ZSTD_compress2() : + * Behave the same as ZSTD_compressCCtx(), but compression parameters are set using the advanced API. + * ZSTD_compress2() always starts a new frame. + * Should cctx hold data from a previously unfinished frame, everything about it is forgotten. + * - Compression parameters are pushed into CCtx before starting compression, using ZSTD_CCtx_set*() + * - The function is always blocking, returns when compression is completed. + * NOTE: Providing `dstCapacity >= ZSTD_compressBound(srcSize)` guarantees that zstd will have + * enough space to successfully compress the data, though it is possible it fails for other reasons. + * @return : compressed size written into `dst` (<= `dstCapacity), + * or an error code if it fails (which can be tested using ZSTD_isError()). + */ +ZSTDLIB_API size_t ZSTD_compress2( ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize); + + +/*********************************************** +* Advanced decompression API (Requires v1.4.0+) +************************************************/ + +/* The advanced API pushes parameters one by one into an existing DCtx context. + * Parameters are sticky, and remain valid for all following frames + * using the same DCtx context. + * It's possible to reset parameters to default values using ZSTD_DCtx_reset(). + * Note : This API is compatible with existing ZSTD_decompressDCtx() and ZSTD_decompressStream(). + * Therefore, no new decompression function is necessary. + */ + +typedef enum { + + ZSTD_d_windowLogMax=100, /* Select a size limit (in power of 2) beyond which + * the streaming API will refuse to allocate memory buffer + * in order to protect the host from unreasonable memory requirements. + * This parameter is only useful in streaming mode, since no internal buffer is allocated in single-pass mode. + * By default, a decompression context accepts window sizes <= (1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT). + * Special: value 0 means "use default maximum windowLog". */ + + /* note : additional experimental parameters are also available + * within the experimental section of the API. + * At the time of this writing, they include : + * ZSTD_d_format + * ZSTD_d_stableOutBuffer + * ZSTD_d_forceIgnoreChecksum + * ZSTD_d_refMultipleDDicts + * ZSTD_d_disableHuffmanAssembly + * Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them. + * note : never ever use experimentalParam? names directly + */ + ZSTD_d_experimentalParam1=1000, + ZSTD_d_experimentalParam2=1001, + ZSTD_d_experimentalParam3=1002, + ZSTD_d_experimentalParam4=1003, + ZSTD_d_experimentalParam5=1004 + +} ZSTD_dParameter; + +/*! ZSTD_dParam_getBounds() : + * All parameters must belong to an interval with lower and upper bounds, + * otherwise they will either trigger an error or be automatically clamped. + * @return : a structure, ZSTD_bounds, which contains + * - an error status field, which must be tested using ZSTD_isError() + * - both lower and upper bounds, inclusive + */ +ZSTDLIB_API ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam); + +/*! ZSTD_DCtx_setParameter() : + * Set one compression parameter, selected by enum ZSTD_dParameter. + * All parameters have valid bounds. Bounds can be queried using ZSTD_dParam_getBounds(). + * Providing a value beyond bound will either clamp it, or trigger an error (depending on parameter). + * Setting a parameter is only possible during frame initialization (before starting decompression). + * @return : 0, or an error code (which can be tested using ZSTD_isError()). + */ +ZSTDLIB_API size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int value); + +/*! ZSTD_DCtx_reset() : + * Return a DCtx to clean state. + * Session and parameters can be reset jointly or separately. + * Parameters can only be reset when no active frame is being decompressed. + * @return : 0, or an error code, which can be tested with ZSTD_isError() + */ +ZSTDLIB_API size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset); + + +/**************************** +* Streaming +****************************/ + +typedef struct ZSTD_inBuffer_s { + const void* src; /**< start of input buffer */ + size_t size; /**< size of input buffer */ + size_t pos; /**< position where reading stopped. Will be updated. Necessarily 0 <= pos <= size */ +} ZSTD_inBuffer; + +typedef struct ZSTD_outBuffer_s { + void* dst; /**< start of output buffer */ + size_t size; /**< size of output buffer */ + size_t pos; /**< position where writing stopped. Will be updated. Necessarily 0 <= pos <= size */ +} ZSTD_outBuffer; + + + +/*-*********************************************************************** +* Streaming compression - HowTo +* +* A ZSTD_CStream object is required to track streaming operation. +* Use ZSTD_createCStream() and ZSTD_freeCStream() to create/release resources. +* ZSTD_CStream objects can be reused multiple times on consecutive compression operations. +* It is recommended to re-use ZSTD_CStream since it will play nicer with system's memory, by re-using already allocated memory. +* +* For parallel execution, use one separate ZSTD_CStream per thread. +* +* note : since v1.3.0, ZSTD_CStream and ZSTD_CCtx are the same thing. +* +* Parameters are sticky : when starting a new compression on the same context, +* it will re-use the same sticky parameters as previous compression session. +* When in doubt, it's recommended to fully initialize the context before usage. +* Use ZSTD_CCtx_reset() to reset the context and ZSTD_CCtx_setParameter(), +* ZSTD_CCtx_setPledgedSrcSize(), or ZSTD_CCtx_loadDictionary() and friends to +* set more specific parameters, the pledged source size, or load a dictionary. +* +* Use ZSTD_compressStream2() with ZSTD_e_continue as many times as necessary to +* consume input stream. The function will automatically update both `pos` +* fields within `input` and `output`. +* Note that the function may not consume the entire input, for example, because +* the output buffer is already full, in which case `input.pos < input.size`. +* The caller must check if input has been entirely consumed. +* If not, the caller must make some room to receive more compressed data, +* and then present again remaining input data. +* note: ZSTD_e_continue is guaranteed to make some forward progress when called, +* but doesn't guarantee maximal forward progress. This is especially relevant +* when compressing with multiple threads. The call won't block if it can +* consume some input, but if it can't it will wait for some, but not all, +* output to be flushed. +* @return : provides a minimum amount of data remaining to be flushed from internal buffers +* or an error code, which can be tested using ZSTD_isError(). +* +* At any moment, it's possible to flush whatever data might remain stuck within internal buffer, +* using ZSTD_compressStream2() with ZSTD_e_flush. `output->pos` will be updated. +* Note that, if `output->size` is too small, a single invocation with ZSTD_e_flush might not be enough (return code > 0). +* In which case, make some room to receive more compressed data, and call again ZSTD_compressStream2() with ZSTD_e_flush. +* You must continue calling ZSTD_compressStream2() with ZSTD_e_flush until it returns 0, at which point you can change the +* operation. +* note: ZSTD_e_flush will flush as much output as possible, meaning when compressing with multiple threads, it will +* block until the flush is complete or the output buffer is full. +* @return : 0 if internal buffers are entirely flushed, +* >0 if some data still present within internal buffer (the value is minimal estimation of remaining size), +* or an error code, which can be tested using ZSTD_isError(). +* +* Calling ZSTD_compressStream2() with ZSTD_e_end instructs to finish a frame. +* It will perform a flush and write frame epilogue. +* The epilogue is required for decoders to consider a frame completed. +* flush operation is the same, and follows same rules as calling ZSTD_compressStream2() with ZSTD_e_flush. +* You must continue calling ZSTD_compressStream2() with ZSTD_e_end until it returns 0, at which point you are free to +* start a new frame. +* note: ZSTD_e_end will flush as much output as possible, meaning when compressing with multiple threads, it will +* block until the flush is complete or the output buffer is full. +* @return : 0 if frame fully completed and fully flushed, +* >0 if some data still present within internal buffer (the value is minimal estimation of remaining size), +* or an error code, which can be tested using ZSTD_isError(). +* +* *******************************************************************/ + +typedef ZSTD_CCtx ZSTD_CStream; /**< CCtx and CStream are now effectively same object (>= v1.3.0) */ + /* Continue to distinguish them for compatibility with older versions <= v1.2.0 */ +/*===== ZSTD_CStream management functions =====*/ +ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream(void); +ZSTDLIB_API size_t ZSTD_freeCStream(ZSTD_CStream* zcs); /* accept NULL pointer */ + +/*===== Streaming compression functions =====*/ +typedef enum { + ZSTD_e_continue=0, /* collect more data, encoder decides when to output compressed result, for optimal compression ratio */ + ZSTD_e_flush=1, /* flush any data provided so far, + * it creates (at least) one new block, that can be decoded immediately on reception; + * frame will continue: any future data can still reference previously compressed data, improving compression. + * note : multithreaded compression will block to flush as much output as possible. */ + ZSTD_e_end=2 /* flush any remaining data _and_ close current frame. + * note that frame is only closed after compressed data is fully flushed (return value == 0). + * After that point, any additional data starts a new frame. + * note : each frame is independent (does not reference any content from previous frame). + : note : multithreaded compression will block to flush as much output as possible. */ +} ZSTD_EndDirective; + +/*! ZSTD_compressStream2() : Requires v1.4.0+ + * Behaves about the same as ZSTD_compressStream, with additional control on end directive. + * - Compression parameters are pushed into CCtx before starting compression, using ZSTD_CCtx_set*() + * - Compression parameters cannot be changed once compression is started (save a list of exceptions in multi-threading mode) + * - output->pos must be <= dstCapacity, input->pos must be <= srcSize + * - output->pos and input->pos will be updated. They are guaranteed to remain below their respective limit. + * - endOp must be a valid directive + * - When nbWorkers==0 (default), function is blocking : it completes its job before returning to caller. + * - When nbWorkers>=1, function is non-blocking : it copies a portion of input, distributes jobs to internal worker threads, flush to output whatever is available, + * and then immediately returns, just indicating that there is some data remaining to be flushed. + * The function nonetheless guarantees forward progress : it will return only after it reads or write at least 1+ byte. + * - Exception : if the first call requests a ZSTD_e_end directive and provides enough dstCapacity, the function delegates to ZSTD_compress2() which is always blocking. + * - @return provides a minimum amount of data remaining to be flushed from internal buffers + * or an error code, which can be tested using ZSTD_isError(). + * if @return != 0, flush is not fully completed, there is still some data left within internal buffers. + * This is useful for ZSTD_e_flush, since in this case more flushes are necessary to empty all buffers. + * For ZSTD_e_end, @return == 0 when internal buffers are fully flushed and frame is completed. + * - after a ZSTD_e_end directive, if internal buffer is not fully flushed (@return != 0), + * only ZSTD_e_end or ZSTD_e_flush operations are allowed. + * Before starting a new compression job, or changing compression parameters, + * it is required to fully flush internal buffers. + */ +ZSTDLIB_API size_t ZSTD_compressStream2( ZSTD_CCtx* cctx, + ZSTD_outBuffer* output, + ZSTD_inBuffer* input, + ZSTD_EndDirective endOp); + + +/* These buffer sizes are softly recommended. + * They are not required : ZSTD_compressStream*() happily accepts any buffer size, for both input and output. + * Respecting the recommended size just makes it a bit easier for ZSTD_compressStream*(), + * reducing the amount of memory shuffling and buffering, resulting in minor performance savings. + * + * However, note that these recommendations are from the perspective of a C caller program. + * If the streaming interface is invoked from some other language, + * especially managed ones such as Java or Go, through a foreign function interface such as jni or cgo, + * a major performance rule is to reduce crossing such interface to an absolute minimum. + * It's not rare that performance ends being spent more into the interface, rather than compression itself. + * In which cases, prefer using large buffers, as large as practical, + * for both input and output, to reduce the nb of roundtrips. + */ +ZSTDLIB_API size_t ZSTD_CStreamInSize(void); /**< recommended size for input buffer */ +ZSTDLIB_API size_t ZSTD_CStreamOutSize(void); /**< recommended size for output buffer. Guarantee to successfully flush at least one complete compressed block. */ + + +/* ***************************************************************************** + * This following is a legacy streaming API, available since v1.0+ . + * It can be replaced by ZSTD_CCtx_reset() and ZSTD_compressStream2(). + * It is redundant, but remains fully supported. + ******************************************************************************/ + +/*! + * Equivalent to: + * + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * ZSTD_CCtx_refCDict(zcs, NULL); // clear the dictionary (if any) + * ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel); + * + * Note that ZSTD_initCStream() clears any previously set dictionary. Use the new API + * to compress with a dictionary. + */ +ZSTDLIB_API size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel); +/*! + * Alternative for ZSTD_compressStream2(zcs, output, input, ZSTD_e_continue). + * NOTE: The return value is different. ZSTD_compressStream() returns a hint for + * the next read size (if non-zero and not an error). ZSTD_compressStream2() + * returns the minimum nb of bytes left to flush (if non-zero and not an error). + */ +ZSTDLIB_API size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input); +/*! Equivalent to ZSTD_compressStream2(zcs, output, &emptyInput, ZSTD_e_flush). */ +ZSTDLIB_API size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output); +/*! Equivalent to ZSTD_compressStream2(zcs, output, &emptyInput, ZSTD_e_end). */ +ZSTDLIB_API size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output); + + +/*-*************************************************************************** +* Streaming decompression - HowTo +* +* A ZSTD_DStream object is required to track streaming operations. +* Use ZSTD_createDStream() and ZSTD_freeDStream() to create/release resources. +* ZSTD_DStream objects can be re-used multiple times. +* +* Use ZSTD_initDStream() to start a new decompression operation. +* @return : recommended first input size +* Alternatively, use advanced API to set specific properties. +* +* Use ZSTD_decompressStream() repetitively to consume your input. +* The function will update both `pos` fields. +* If `input.pos < input.size`, some input has not been consumed. +* It's up to the caller to present again remaining data. +* The function tries to flush all data decoded immediately, respecting output buffer size. +* If `output.pos < output.size`, decoder has flushed everything it could. +* But if `output.pos == output.size`, there might be some data left within internal buffers., +* In which case, call ZSTD_decompressStream() again to flush whatever remains in the buffer. +* Note : with no additional input provided, amount of data flushed is necessarily <= ZSTD_BLOCKSIZE_MAX. +* @return : 0 when a frame is completely decoded and fully flushed, +* or an error code, which can be tested using ZSTD_isError(), +* or any other value > 0, which means there is still some decoding or flushing to do to complete current frame : +* the return value is a suggested next input size (just a hint for better latency) +* that will never request more than the remaining frame size. +* *******************************************************************************/ + +typedef ZSTD_DCtx ZSTD_DStream; /**< DCtx and DStream are now effectively same object (>= v1.3.0) */ + /* For compatibility with versions <= v1.2.0, prefer differentiating them. */ +/*===== ZSTD_DStream management functions =====*/ +ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream(void); +ZSTDLIB_API size_t ZSTD_freeDStream(ZSTD_DStream* zds); /* accept NULL pointer */ + +/*===== Streaming decompression functions =====*/ + +/*! ZSTD_initDStream() : + * Initialize/reset DStream state for new decompression operation. + * Call before new decompression operation using same DStream. + * + * Note : This function is redundant with the advanced API and equivalent to: + * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); + * ZSTD_DCtx_refDDict(zds, NULL); + */ +ZSTDLIB_API size_t ZSTD_initDStream(ZSTD_DStream* zds); + +/*! ZSTD_decompressStream() : + * Streaming decompression function. + * Call repetitively to consume full input updating it as necessary. + * Function will update both input and output `pos` fields exposing current state via these fields: + * - `input.pos < input.size`, some input remaining and caller should provide remaining input + * on the next call. + * - `output.pos < output.size`, decoder finished and flushed all remaining buffers. + * - `output.pos == output.size`, potentially uncflushed data present in the internal buffers, + * call ZSTD_decompressStream() again to flush remaining data to output. + * Note : with no additional input, amount of data flushed <= ZSTD_BLOCKSIZE_MAX. + * + * @return : 0 when a frame is completely decoded and fully flushed, + * or an error code, which can be tested using ZSTD_isError(), + * or any other value > 0, which means there is some decoding or flushing to do to complete current frame. + */ +ZSTDLIB_API size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input); + +ZSTDLIB_API size_t ZSTD_DStreamInSize(void); /*!< recommended size for input buffer */ +ZSTDLIB_API size_t ZSTD_DStreamOutSize(void); /*!< recommended size for output buffer. Guarantee to successfully flush at least one complete block in all circumstances. */ + + +/************************** +* Simple dictionary API +***************************/ +/*! ZSTD_compress_usingDict() : + * Compression at an explicit compression level using a Dictionary. + * A dictionary can be any arbitrary data segment (also called a prefix), + * or a buffer with specified information (see zdict.h). + * Note : This function loads the dictionary, resulting in significant startup delay. + * It's intended for a dictionary used only once. + * Note 2 : When `dict == NULL || dictSize < 8` no dictionary is used. */ +ZSTDLIB_API size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const void* dict,size_t dictSize, + int compressionLevel); + +/*! ZSTD_decompress_usingDict() : + * Decompression using a known Dictionary. + * Dictionary must be identical to the one used during compression. + * Note : This function loads the dictionary, resulting in significant startup delay. + * It's intended for a dictionary used only once. + * Note : When `dict == NULL || dictSize < 8` no dictionary is used. */ +ZSTDLIB_API size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const void* dict,size_t dictSize); + + +/*********************************** + * Bulk processing dictionary API + **********************************/ +typedef struct ZSTD_CDict_s ZSTD_CDict; + +/*! ZSTD_createCDict() : + * When compressing multiple messages or blocks using the same dictionary, + * it's recommended to digest the dictionary only once, since it's a costly operation. + * ZSTD_createCDict() will create a state from digesting a dictionary. + * The resulting state can be used for future compression operations with very limited startup cost. + * ZSTD_CDict can be created once and shared by multiple threads concurrently, since its usage is read-only. + * @dictBuffer can be released after ZSTD_CDict creation, because its content is copied within CDict. + * Note 1 : Consider experimental function `ZSTD_createCDict_byReference()` if you prefer to not duplicate @dictBuffer content. + * Note 2 : A ZSTD_CDict can be created from an empty @dictBuffer, + * in which case the only thing that it transports is the @compressionLevel. + * This can be useful in a pipeline featuring ZSTD_compress_usingCDict() exclusively, + * expecting a ZSTD_CDict parameter with any data, including those without a known dictionary. */ +ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict(const void* dictBuffer, size_t dictSize, + int compressionLevel); + +/*! ZSTD_freeCDict() : + * Function frees memory allocated by ZSTD_createCDict(). + * If a NULL pointer is passed, no operation is performed. */ +ZSTDLIB_API size_t ZSTD_freeCDict(ZSTD_CDict* CDict); + +/*! ZSTD_compress_usingCDict() : + * Compression using a digested Dictionary. + * Recommended when same dictionary is used multiple times. + * Note : compression level is _decided at dictionary creation time_, + * and frame parameters are hardcoded (dictID=yes, contentSize=yes, checksum=no) */ +ZSTDLIB_API size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const ZSTD_CDict* cdict); + + +typedef struct ZSTD_DDict_s ZSTD_DDict; + +/*! ZSTD_createDDict() : + * Create a digested dictionary, ready to start decompression operation without startup delay. + * dictBuffer can be released after DDict creation, as its content is copied inside DDict. */ +ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict(const void* dictBuffer, size_t dictSize); + +/*! ZSTD_freeDDict() : + * Function frees memory allocated with ZSTD_createDDict() + * If a NULL pointer is passed, no operation is performed. */ +ZSTDLIB_API size_t ZSTD_freeDDict(ZSTD_DDict* ddict); + +/*! ZSTD_decompress_usingDDict() : + * Decompression using a digested Dictionary. + * Recommended when same dictionary is used multiple times. */ +ZSTDLIB_API size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const ZSTD_DDict* ddict); + + +/******************************** + * Dictionary helper functions + *******************************/ + +/*! ZSTD_getDictID_fromDict() : Requires v1.4.0+ + * Provides the dictID stored within dictionary. + * if @return == 0, the dictionary is not conformant with Zstandard specification. + * It can still be loaded, but as a content-only dictionary. */ +ZSTDLIB_API unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize); + +/*! ZSTD_getDictID_fromCDict() : Requires v1.5.0+ + * Provides the dictID of the dictionary loaded into `cdict`. + * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty. + * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */ +ZSTDLIB_API unsigned ZSTD_getDictID_fromCDict(const ZSTD_CDict* cdict); + +/*! ZSTD_getDictID_fromDDict() : Requires v1.4.0+ + * Provides the dictID of the dictionary loaded into `ddict`. + * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty. + * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */ +ZSTDLIB_API unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict); + +/*! ZSTD_getDictID_fromFrame() : Requires v1.4.0+ + * Provides the dictID required to decompressed the frame stored within `src`. + * If @return == 0, the dictID could not be decoded. + * This could for one of the following reasons : + * - The frame does not require a dictionary to be decoded (most common case). + * - The frame was built with dictID intentionally removed. Whatever dictionary is necessary is a hidden piece of information. + * Note : this use case also happens when using a non-conformant dictionary. + * - `srcSize` is too small, and as a result, the frame header could not be decoded (only possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`). + * - This is not a Zstandard frame. + * When identifying the exact failure cause, it's possible to use ZSTD_getFrameHeader(), which will provide a more precise error code. */ +ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize); + + +/******************************************************************************* + * Advanced dictionary and prefix API (Requires v1.4.0+) + * + * This API allows dictionaries to be used with ZSTD_compress2(), + * ZSTD_compressStream2(), and ZSTD_decompressDCtx(). + * Dictionaries are sticky, they remain valid when same context is re-used, + * they only reset when the context is reset + * with ZSTD_reset_parameters or ZSTD_reset_session_and_parameters. + * In contrast, Prefixes are single-use. + ******************************************************************************/ + + +/*! ZSTD_CCtx_loadDictionary() : Requires v1.4.0+ + * Create an internal CDict from `dict` buffer. + * Decompression will have to use same dictionary. + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + * Special: Loading a NULL (or 0-size) dictionary invalidates previous dictionary, + * meaning "return to no-dictionary mode". + * Note 1 : Dictionary is sticky, it will be used for all future compressed frames, + * until parameters are reset, a new dictionary is loaded, or the dictionary + * is explicitly invalidated by loading a NULL dictionary. + * Note 2 : Loading a dictionary involves building tables. + * It's also a CPU consuming operation, with non-negligible impact on latency. + * Tables are dependent on compression parameters, and for this reason, + * compression parameters can no longer be changed after loading a dictionary. + * Note 3 :`dict` content will be copied internally. + * Use experimental ZSTD_CCtx_loadDictionary_byReference() to reference content instead. + * In such a case, dictionary buffer must outlive its users. + * Note 4 : Use ZSTD_CCtx_loadDictionary_advanced() + * to precisely select how dictionary content must be interpreted. + * Note 5 : This method does not benefit from LDM (long distance mode). + * If you want to employ LDM on some large dictionary content, + * prefer employing ZSTD_CCtx_refPrefix() described below. + */ +ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize); + +/*! ZSTD_CCtx_refCDict() : Requires v1.4.0+ + * Reference a prepared dictionary, to be used for all future compressed frames. + * Note that compression parameters are enforced from within CDict, + * and supersede any compression parameter previously set within CCtx. + * The parameters ignored are labelled as "superseded-by-cdict" in the ZSTD_cParameter enum docs. + * The ignored parameters will be used again if the CCtx is returned to no-dictionary mode. + * The dictionary will remain valid for future compressed frames using same CCtx. + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + * Special : Referencing a NULL CDict means "return to no-dictionary mode". + * Note 1 : Currently, only one dictionary can be managed. + * Referencing a new dictionary effectively "discards" any previous one. + * Note 2 : CDict is just referenced, its lifetime must outlive its usage within CCtx. */ +ZSTDLIB_API size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); + +/*! ZSTD_CCtx_refPrefix() : Requires v1.4.0+ + * Reference a prefix (single-usage dictionary) for next compressed frame. + * A prefix is **only used once**. Tables are discarded at end of frame (ZSTD_e_end). + * Decompression will need same prefix to properly regenerate data. + * Compressing with a prefix is similar in outcome as performing a diff and compressing it, + * but performs much faster, especially during decompression (compression speed is tunable with compression level). + * This method is compatible with LDM (long distance mode). + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + * Special: Adding any prefix (including NULL) invalidates any previous prefix or dictionary + * Note 1 : Prefix buffer is referenced. It **must** outlive compression. + * Its content must remain unmodified during compression. + * Note 2 : If the intention is to diff some large src data blob with some prior version of itself, + * ensure that the window size is large enough to contain the entire source. + * See ZSTD_c_windowLog. + * Note 3 : Referencing a prefix involves building tables, which are dependent on compression parameters. + * It's a CPU consuming operation, with non-negligible impact on latency. + * If there is a need to use the same prefix multiple times, consider loadDictionary instead. + * Note 4 : By default, the prefix is interpreted as raw content (ZSTD_dct_rawContent). + * Use experimental ZSTD_CCtx_refPrefix_advanced() to alter dictionary interpretation. */ +ZSTDLIB_API size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, + const void* prefix, size_t prefixSize); + +/*! ZSTD_DCtx_loadDictionary() : Requires v1.4.0+ + * Create an internal DDict from dict buffer, to be used to decompress all future frames. + * The dictionary remains valid for all future frames, until explicitly invalidated, or + * a new dictionary is loaded. + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + * Special : Adding a NULL (or 0-size) dictionary invalidates any previous dictionary, + * meaning "return to no-dictionary mode". + * Note 1 : Loading a dictionary involves building tables, + * which has a non-negligible impact on CPU usage and latency. + * It's recommended to "load once, use many times", to amortize the cost + * Note 2 :`dict` content will be copied internally, so `dict` can be released after loading. + * Use ZSTD_DCtx_loadDictionary_byReference() to reference dictionary content instead. + * Note 3 : Use ZSTD_DCtx_loadDictionary_advanced() to take control of + * how dictionary content is loaded and interpreted. + */ +ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); + +/*! ZSTD_DCtx_refDDict() : Requires v1.4.0+ + * Reference a prepared dictionary, to be used to decompress next frames. + * The dictionary remains active for decompression of future frames using same DCtx. + * + * If called with ZSTD_d_refMultipleDDicts enabled, repeated calls of this function + * will store the DDict references in a table, and the DDict used for decompression + * will be determined at decompression time, as per the dict ID in the frame. + * The memory for the table is allocated on the first call to refDDict, and can be + * freed with ZSTD_freeDCtx(). + * + * If called with ZSTD_d_refMultipleDDicts disabled (the default), only one dictionary + * will be managed, and referencing a dictionary effectively "discards" any previous one. + * + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + * Special: referencing a NULL DDict means "return to no-dictionary mode". + * Note 2 : DDict is just referenced, its lifetime must outlive its usage from DCtx. + */ +ZSTDLIB_API size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); + +/*! ZSTD_DCtx_refPrefix() : Requires v1.4.0+ + * Reference a prefix (single-usage dictionary) to decompress next frame. + * This is the reverse operation of ZSTD_CCtx_refPrefix(), + * and must use the same prefix as the one used during compression. + * Prefix is **only used once**. Reference is discarded at end of frame. + * End of frame is reached when ZSTD_decompressStream() returns 0. + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + * Note 1 : Adding any prefix (including NULL) invalidates any previously set prefix or dictionary + * Note 2 : Prefix buffer is referenced. It **must** outlive decompression. + * Prefix buffer must remain unmodified up to the end of frame, + * reached when ZSTD_decompressStream() returns 0. + * Note 3 : By default, the prefix is treated as raw content (ZSTD_dct_rawContent). + * Use ZSTD_CCtx_refPrefix_advanced() to alter dictMode (Experimental section) + * Note 4 : Referencing a raw content prefix has almost no cpu nor memory cost. + * A full dictionary is more costly, as it requires building tables. + */ +ZSTDLIB_API size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, + const void* prefix, size_t prefixSize); + +/* === Memory management === */ + +/*! ZSTD_sizeof_*() : Requires v1.4.0+ + * These functions give the _current_ memory usage of selected object. + * Note that object memory usage can evolve (increase or decrease) over time. */ +ZSTDLIB_API size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx); +ZSTDLIB_API size_t ZSTD_sizeof_DCtx(const ZSTD_DCtx* dctx); +ZSTDLIB_API size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs); +ZSTDLIB_API size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds); +ZSTDLIB_API size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict); +ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict); + +#endif /* ZSTD_H_235446 */ + + +/* ************************************************************************************** + * ADVANCED AND EXPERIMENTAL FUNCTIONS + **************************************************************************************** + * The definitions in the following section are considered experimental. + * They are provided for advanced scenarios. + * They should never be used with a dynamic library, as prototypes may change in the future. + * Use them only in association with static linking. + * ***************************************************************************************/ + +#if defined(ZSTD_STATIC_LINKING_ONLY) && !defined(ZSTD_H_ZSTD_STATIC_LINKING_ONLY) +#define ZSTD_H_ZSTD_STATIC_LINKING_ONLY + +/* This can be overridden externally to hide static symbols. */ +#ifndef ZSTDLIB_STATIC_API +# if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) +# define ZSTDLIB_STATIC_API __declspec(dllexport) ZSTDLIB_VISIBLE +# elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) +# define ZSTDLIB_STATIC_API __declspec(dllimport) ZSTDLIB_VISIBLE +# else +# define ZSTDLIB_STATIC_API ZSTDLIB_VISIBLE +# endif +#endif + +/**************************************************************************************** + * experimental API (static linking only) + **************************************************************************************** + * The following symbols and constants + * are not planned to join "stable API" status in the near future. + * They can still change in future versions. + * Some of them are planned to remain in the static_only section indefinitely. + * Some of them might be removed in the future (especially when redundant with existing stable functions) + * ***************************************************************************************/ + +#define ZSTD_FRAMEHEADERSIZE_PREFIX(format) ((format) == ZSTD_f_zstd1 ? 5 : 1) /* minimum input size required to query frame header size */ +#define ZSTD_FRAMEHEADERSIZE_MIN(format) ((format) == ZSTD_f_zstd1 ? 6 : 2) +#define ZSTD_FRAMEHEADERSIZE_MAX 18 /* can be useful for static allocation */ +#define ZSTD_SKIPPABLEHEADERSIZE 8 + +/* compression parameter bounds */ +#define ZSTD_WINDOWLOG_MAX_32 30 +#define ZSTD_WINDOWLOG_MAX_64 31 +#define ZSTD_WINDOWLOG_MAX ((int)(sizeof(size_t) == 4 ? ZSTD_WINDOWLOG_MAX_32 : ZSTD_WINDOWLOG_MAX_64)) +#define ZSTD_WINDOWLOG_MIN 10 +#define ZSTD_HASHLOG_MAX ((ZSTD_WINDOWLOG_MAX < 30) ? ZSTD_WINDOWLOG_MAX : 30) +#define ZSTD_HASHLOG_MIN 6 +#define ZSTD_CHAINLOG_MAX_32 29 +#define ZSTD_CHAINLOG_MAX_64 30 +#define ZSTD_CHAINLOG_MAX ((int)(sizeof(size_t) == 4 ? ZSTD_CHAINLOG_MAX_32 : ZSTD_CHAINLOG_MAX_64)) +#define ZSTD_CHAINLOG_MIN ZSTD_HASHLOG_MIN +#define ZSTD_SEARCHLOG_MAX (ZSTD_WINDOWLOG_MAX-1) +#define ZSTD_SEARCHLOG_MIN 1 +#define ZSTD_MINMATCH_MAX 7 /* only for ZSTD_fast, other strategies are limited to 6 */ +#define ZSTD_MINMATCH_MIN 3 /* only for ZSTD_btopt+, faster strategies are limited to 4 */ +#define ZSTD_TARGETLENGTH_MAX ZSTD_BLOCKSIZE_MAX +#define ZSTD_TARGETLENGTH_MIN 0 /* note : comparing this constant to an unsigned results in a tautological test */ +#define ZSTD_STRATEGY_MIN ZSTD_fast +#define ZSTD_STRATEGY_MAX ZSTD_btultra2 +#define ZSTD_BLOCKSIZE_MAX_MIN (1 << 10) /* The minimum valid max blocksize. Maximum blocksizes smaller than this make compressBound() inaccurate. */ + + +#define ZSTD_OVERLAPLOG_MIN 0 +#define ZSTD_OVERLAPLOG_MAX 9 + +#define ZSTD_WINDOWLOG_LIMIT_DEFAULT 27 /* by default, the streaming decoder will refuse any frame + * requiring larger than (1< 0: + * If litLength != 0: + * rep == 1 --> offset == repeat_offset_1 + * rep == 2 --> offset == repeat_offset_2 + * rep == 3 --> offset == repeat_offset_3 + * If litLength == 0: + * rep == 1 --> offset == repeat_offset_2 + * rep == 2 --> offset == repeat_offset_3 + * rep == 3 --> offset == repeat_offset_1 - 1 + * + * Note: This field is optional. ZSTD_generateSequences() will calculate the value of + * 'rep', but repeat offsets do not necessarily need to be calculated from an external + * sequence provider's perspective. For example, ZSTD_compressSequences() does not + * use this 'rep' field at all (as of now). + */ +} ZSTD_Sequence; + +typedef struct { + unsigned windowLog; /**< largest match distance : larger == more compression, more memory needed during decompression */ + unsigned chainLog; /**< fully searched segment : larger == more compression, slower, more memory (useless for fast) */ + unsigned hashLog; /**< dispatch table : larger == faster, more memory */ + unsigned searchLog; /**< nb of searches : larger == more compression, slower */ + unsigned minMatch; /**< match length searched : larger == faster decompression, sometimes less compression */ + unsigned targetLength; /**< acceptable match size for optimal parser (only) : larger == more compression, slower */ + ZSTD_strategy strategy; /**< see ZSTD_strategy definition above */ +} ZSTD_compressionParameters; + +typedef struct { + int contentSizeFlag; /**< 1: content size will be in frame header (when known) */ + int checksumFlag; /**< 1: generate a 32-bits checksum using XXH64 algorithm at end of frame, for error detection */ + int noDictIDFlag; /**< 1: no dictID will be saved into frame header (dictID is only useful for dictionary compression) */ +} ZSTD_frameParameters; + +typedef struct { + ZSTD_compressionParameters cParams; + ZSTD_frameParameters fParams; +} ZSTD_parameters; + +typedef enum { + ZSTD_dct_auto = 0, /* dictionary is "full" when starting with ZSTD_MAGIC_DICTIONARY, otherwise it is "rawContent" */ + ZSTD_dct_rawContent = 1, /* ensures dictionary is always loaded as rawContent, even if it starts with ZSTD_MAGIC_DICTIONARY */ + ZSTD_dct_fullDict = 2 /* refuses to load a dictionary if it does not respect Zstandard's specification, starting with ZSTD_MAGIC_DICTIONARY */ +} ZSTD_dictContentType_e; + +typedef enum { + ZSTD_dlm_byCopy = 0, /**< Copy dictionary content internally */ + ZSTD_dlm_byRef = 1 /**< Reference dictionary content -- the dictionary buffer must outlive its users. */ +} ZSTD_dictLoadMethod_e; + +typedef enum { + ZSTD_f_zstd1 = 0, /* zstd frame format, specified in zstd_compression_format.md (default) */ + ZSTD_f_zstd1_magicless = 1 /* Variant of zstd frame format, without initial 4-bytes magic number. + * Useful to save 4 bytes per generated frame. + * Decoder cannot recognise automatically this format, requiring this instruction. */ +} ZSTD_format_e; + +typedef enum { + /* Note: this enum controls ZSTD_d_forceIgnoreChecksum */ + ZSTD_d_validateChecksum = 0, + ZSTD_d_ignoreChecksum = 1 +} ZSTD_forceIgnoreChecksum_e; + +typedef enum { + /* Note: this enum controls ZSTD_d_refMultipleDDicts */ + ZSTD_rmd_refSingleDDict = 0, + ZSTD_rmd_refMultipleDDicts = 1 +} ZSTD_refMultipleDDicts_e; + +typedef enum { + /* Note: this enum and the behavior it controls are effectively internal + * implementation details of the compressor. They are expected to continue + * to evolve and should be considered only in the context of extremely + * advanced performance tuning. + * + * Zstd currently supports the use of a CDict in three ways: + * + * - The contents of the CDict can be copied into the working context. This + * means that the compression can search both the dictionary and input + * while operating on a single set of internal tables. This makes + * the compression faster per-byte of input. However, the initial copy of + * the CDict's tables incurs a fixed cost at the beginning of the + * compression. For small compressions (< 8 KB), that copy can dominate + * the cost of the compression. + * + * - The CDict's tables can be used in-place. In this model, compression is + * slower per input byte, because the compressor has to search two sets of + * tables. However, this model incurs no start-up cost (as long as the + * working context's tables can be reused). For small inputs, this can be + * faster than copying the CDict's tables. + * + * - The CDict's tables are not used at all, and instead we use the working + * context alone to reload the dictionary and use params based on the source + * size. See ZSTD_compress_insertDictionary() and ZSTD_compress_usingDict(). + * This method is effective when the dictionary sizes are very small relative + * to the input size, and the input size is fairly large to begin with. + * + * Zstd has a simple internal heuristic that selects which strategy to use + * at the beginning of a compression. However, if experimentation shows that + * Zstd is making poor choices, it is possible to override that choice with + * this enum. + */ + ZSTD_dictDefaultAttach = 0, /* Use the default heuristic. */ + ZSTD_dictForceAttach = 1, /* Never copy the dictionary. */ + ZSTD_dictForceCopy = 2, /* Always copy the dictionary. */ + ZSTD_dictForceLoad = 3 /* Always reload the dictionary */ +} ZSTD_dictAttachPref_e; + +typedef enum { + ZSTD_lcm_auto = 0, /**< Automatically determine the compression mode based on the compression level. + * Negative compression levels will be uncompressed, and positive compression + * levels will be compressed. */ + ZSTD_lcm_huffman = 1, /**< Always attempt Huffman compression. Uncompressed literals will still be + * emitted if Huffman compression is not profitable. */ + ZSTD_lcm_uncompressed = 2 /**< Always emit uncompressed literals. */ +} ZSTD_literalCompressionMode_e; + +typedef enum { + /* Note: This enum controls features which are conditionally beneficial. Zstd typically will make a final + * decision on whether or not to enable the feature (ZSTD_ps_auto), but setting the switch to ZSTD_ps_enable + * or ZSTD_ps_disable allow for a force enable/disable the feature. + */ + ZSTD_ps_auto = 0, /* Let the library automatically determine whether the feature shall be enabled */ + ZSTD_ps_enable = 1, /* Force-enable the feature */ + ZSTD_ps_disable = 2 /* Do not use the feature */ +} ZSTD_paramSwitch_e; + +/*************************************** +* Frame header and size functions +***************************************/ + +/*! ZSTD_findDecompressedSize() : + * `src` should point to the start of a series of ZSTD encoded and/or skippable frames + * `srcSize` must be the _exact_ size of this series + * (i.e. there should be a frame boundary at `src + srcSize`) + * @return : - decompressed size of all data in all successive frames + * - if the decompressed size cannot be determined: ZSTD_CONTENTSIZE_UNKNOWN + * - if an error occurred: ZSTD_CONTENTSIZE_ERROR + * + * note 1 : decompressed size is an optional field, that may not be present, especially in streaming mode. + * When `return==ZSTD_CONTENTSIZE_UNKNOWN`, data to decompress could be any size. + * In which case, it's necessary to use streaming mode to decompress data. + * note 2 : decompressed size is always present when compression is done with ZSTD_compress() + * note 3 : decompressed size can be very large (64-bits value), + * potentially larger than what local system can handle as a single memory segment. + * In which case, it's necessary to use streaming mode to decompress data. + * note 4 : If source is untrusted, decompressed size could be wrong or intentionally modified. + * Always ensure result fits within application's authorized limits. + * Each application can set its own limits. + * note 5 : ZSTD_findDecompressedSize handles multiple frames, and so it must traverse the input to + * read each contained frame header. This is fast as most of the data is skipped, + * however it does mean that all frame data must be present and valid. */ +ZSTDLIB_STATIC_API unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize); + +/*! ZSTD_decompressBound() : + * `src` should point to the start of a series of ZSTD encoded and/or skippable frames + * `srcSize` must be the _exact_ size of this series + * (i.e. there should be a frame boundary at `src + srcSize`) + * @return : - upper-bound for the decompressed size of all data in all successive frames + * - if an error occurred: ZSTD_CONTENTSIZE_ERROR + * + * note 1 : an error can occur if `src` contains an invalid or incorrectly formatted frame. + * note 2 : the upper-bound is exact when the decompressed size field is available in every ZSTD encoded frame of `src`. + * in this case, `ZSTD_findDecompressedSize` and `ZSTD_decompressBound` return the same value. + * note 3 : when the decompressed size field isn't available, the upper-bound for that frame is calculated by: + * upper-bound = # blocks * min(128 KB, Window_Size) + */ +ZSTDLIB_STATIC_API unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize); + +/*! ZSTD_frameHeaderSize() : + * srcSize must be >= ZSTD_FRAMEHEADERSIZE_PREFIX. + * @return : size of the Frame Header, + * or an error code (if srcSize is too small) */ +ZSTDLIB_STATIC_API size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize); + +typedef enum { ZSTD_frame, ZSTD_skippableFrame } ZSTD_frameType_e; +typedef struct { + unsigned long long frameContentSize; /* if == ZSTD_CONTENTSIZE_UNKNOWN, it means this field is not available. 0 means "empty" */ + unsigned long long windowSize; /* can be very large, up to <= frameContentSize */ + unsigned blockSizeMax; + ZSTD_frameType_e frameType; /* if == ZSTD_skippableFrame, frameContentSize is the size of skippable content */ + unsigned headerSize; + unsigned dictID; + unsigned checksumFlag; + unsigned _reserved1; + unsigned _reserved2; +} ZSTD_frameHeader; + +/*! ZSTD_getFrameHeader() : + * decode Frame Header, or requires larger `srcSize`. + * @return : 0, `zfhPtr` is correctly filled, + * >0, `srcSize` is too small, value is wanted `srcSize` amount, + * or an error code, which can be tested using ZSTD_isError() */ +ZSTDLIB_STATIC_API size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize); /**< doesn't consume input */ +/*! ZSTD_getFrameHeader_advanced() : + * same as ZSTD_getFrameHeader(), + * with added capability to select a format (like ZSTD_f_zstd1_magicless) */ +ZSTDLIB_STATIC_API size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format); + +/*! ZSTD_decompressionMargin() : + * Zstd supports in-place decompression, where the input and output buffers overlap. + * In this case, the output buffer must be at least (Margin + Output_Size) bytes large, + * and the input buffer must be at the end of the output buffer. + * + * _______________________ Output Buffer ________________________ + * | | + * | ____ Input Buffer ____| + * | | | + * v v v + * |---------------------------------------|-----------|----------| + * ^ ^ ^ + * |___________________ Output_Size ___________________|_ Margin _| + * + * NOTE: See also ZSTD_DECOMPRESSION_MARGIN(). + * NOTE: This applies only to single-pass decompression through ZSTD_decompress() or + * ZSTD_decompressDCtx(). + * NOTE: This function supports multi-frame input. + * + * @param src The compressed frame(s) + * @param srcSize The size of the compressed frame(s) + * @returns The decompression margin or an error that can be checked with ZSTD_isError(). + */ +ZSTDLIB_STATIC_API size_t ZSTD_decompressionMargin(const void* src, size_t srcSize); + +/*! ZSTD_DECOMPRESS_MARGIN() : + * Similar to ZSTD_decompressionMargin(), but instead of computing the margin from + * the compressed frame, compute it from the original size and the blockSizeLog. + * See ZSTD_decompressionMargin() for details. + * + * WARNING: This macro does not support multi-frame input, the input must be a single + * zstd frame. If you need that support use the function, or implement it yourself. + * + * @param originalSize The original uncompressed size of the data. + * @param blockSize The block size == MIN(windowSize, ZSTD_BLOCKSIZE_MAX). + * Unless you explicitly set the windowLog smaller than + * ZSTD_BLOCKSIZELOG_MAX you can just use ZSTD_BLOCKSIZE_MAX. + */ +#define ZSTD_DECOMPRESSION_MARGIN(originalSize, blockSize) ((size_t)( \ + ZSTD_FRAMEHEADERSIZE_MAX /* Frame header */ + \ + 4 /* checksum */ + \ + ((originalSize) == 0 ? 0 : 3 * (((originalSize) + (blockSize) - 1) / blockSize)) /* 3 bytes per block */ + \ + (blockSize) /* One block of margin */ \ + )) + +typedef enum { + ZSTD_sf_noBlockDelimiters = 0, /* Representation of ZSTD_Sequence has no block delimiters, sequences only */ + ZSTD_sf_explicitBlockDelimiters = 1 /* Representation of ZSTD_Sequence contains explicit block delimiters */ +} ZSTD_sequenceFormat_e; + +/*! ZSTD_sequenceBound() : + * `srcSize` : size of the input buffer + * @return : upper-bound for the number of sequences that can be generated + * from a buffer of srcSize bytes + * + * note : returns number of sequences - to get bytes, multiply by sizeof(ZSTD_Sequence). + */ +ZSTDLIB_STATIC_API size_t ZSTD_sequenceBound(size_t srcSize); + +/*! ZSTD_generateSequences() : + * Generate sequences using ZSTD_compress2(), given a source buffer. + * + * Each block will end with a dummy sequence + * with offset == 0, matchLength == 0, and litLength == length of last literals. + * litLength may be == 0, and if so, then the sequence of (of: 0 ml: 0 ll: 0) + * simply acts as a block delimiter. + * + * @zc can be used to insert custom compression params. + * This function invokes ZSTD_compress2(). + * + * The output of this function can be fed into ZSTD_compressSequences() with CCtx + * setting of ZSTD_c_blockDelimiters as ZSTD_sf_explicitBlockDelimiters + * @return : number of sequences generated + */ + +ZSTDLIB_STATIC_API size_t +ZSTD_generateSequences( ZSTD_CCtx* zc, + ZSTD_Sequence* outSeqs, size_t outSeqsSize, + const void* src, size_t srcSize); + +/*! ZSTD_mergeBlockDelimiters() : + * Given an array of ZSTD_Sequence, remove all sequences that represent block delimiters/last literals + * by merging them into the literals of the next sequence. + * + * As such, the final generated result has no explicit representation of block boundaries, + * and the final last literals segment is not represented in the sequences. + * + * The output of this function can be fed into ZSTD_compressSequences() with CCtx + * setting of ZSTD_c_blockDelimiters as ZSTD_sf_noBlockDelimiters + * @return : number of sequences left after merging + */ +ZSTDLIB_STATIC_API size_t ZSTD_mergeBlockDelimiters(ZSTD_Sequence* sequences, size_t seqsSize); + +/*! ZSTD_compressSequences() : + * Compress an array of ZSTD_Sequence, associated with @src buffer, into dst. + * @src contains the entire input (not just the literals). + * If @srcSize > sum(sequence.length), the remaining bytes are considered all literals + * If a dictionary is included, then the cctx should reference the dict. (see: ZSTD_CCtx_refCDict(), ZSTD_CCtx_loadDictionary(), etc.) + * The entire source is compressed into a single frame. + * + * The compression behavior changes based on cctx params. In particular: + * If ZSTD_c_blockDelimiters == ZSTD_sf_noBlockDelimiters, the array of ZSTD_Sequence is expected to contain + * no block delimiters (defined in ZSTD_Sequence). Block boundaries are roughly determined based on + * the block size derived from the cctx, and sequences may be split. This is the default setting. + * + * If ZSTD_c_blockDelimiters == ZSTD_sf_explicitBlockDelimiters, the array of ZSTD_Sequence is expected to contain + * block delimiters (defined in ZSTD_Sequence). Behavior is undefined if no block delimiters are provided. + * + * If ZSTD_c_validateSequences == 0, this function will blindly accept the sequences provided. Invalid sequences cause undefined + * behavior. If ZSTD_c_validateSequences == 1, then if sequence is invalid (see doc/zstd_compression_format.md for + * specifics regarding offset/matchlength requirements) then the function will bail out and return an error. + * + * In addition to the two adjustable experimental params, there are other important cctx params. + * - ZSTD_c_minMatch MUST be set as less than or equal to the smallest match generated by the match finder. It has a minimum value of ZSTD_MINMATCH_MIN. + * - ZSTD_c_compressionLevel accordingly adjusts the strength of the entropy coder, as it would in typical compression. + * - ZSTD_c_windowLog affects offset validation: this function will return an error at higher debug levels if a provided offset + * is larger than what the spec allows for a given window log and dictionary (if present). See: doc/zstd_compression_format.md + * + * Note: Repcodes are, as of now, always re-calculated within this function, so ZSTD_Sequence::rep is unused. + * Note 2: Once we integrate ability to ingest repcodes, the explicit block delims mode must respect those repcodes exactly, + * and cannot emit an RLE block that disagrees with the repcode history + * @return : final compressed size, or a ZSTD error code. + */ +ZSTDLIB_STATIC_API size_t +ZSTD_compressSequences( ZSTD_CCtx* cctx, void* dst, size_t dstSize, + const ZSTD_Sequence* inSeqs, size_t inSeqsSize, + const void* src, size_t srcSize); + + +/*! ZSTD_writeSkippableFrame() : + * Generates a zstd skippable frame containing data given by src, and writes it to dst buffer. + * + * Skippable frames begin with a 4-byte magic number. There are 16 possible choices of magic number, + * ranging from ZSTD_MAGIC_SKIPPABLE_START to ZSTD_MAGIC_SKIPPABLE_START+15. + * As such, the parameter magicVariant controls the exact skippable frame magic number variant used, so + * the magic number used will be ZSTD_MAGIC_SKIPPABLE_START + magicVariant. + * + * Returns an error if destination buffer is not large enough, if the source size is not representable + * with a 4-byte unsigned int, or if the parameter magicVariant is greater than 15 (and therefore invalid). + * + * @return : number of bytes written or a ZSTD error. + */ +ZSTDLIB_STATIC_API size_t ZSTD_writeSkippableFrame(void* dst, size_t dstCapacity, + const void* src, size_t srcSize, unsigned magicVariant); + +/*! ZSTD_readSkippableFrame() : + * Retrieves a zstd skippable frame containing data given by src, and writes it to dst buffer. + * + * The parameter magicVariant will receive the magicVariant that was supplied when the frame was written, + * i.e. magicNumber - ZSTD_MAGIC_SKIPPABLE_START. This can be NULL if the caller is not interested + * in the magicVariant. + * + * Returns an error if destination buffer is not large enough, or if the frame is not skippable. + * + * @return : number of bytes written or a ZSTD error. + */ +ZSTDLIB_API size_t ZSTD_readSkippableFrame(void* dst, size_t dstCapacity, unsigned* magicVariant, + const void* src, size_t srcSize); + +/*! ZSTD_isSkippableFrame() : + * Tells if the content of `buffer` starts with a valid Frame Identifier for a skippable frame. + */ +ZSTDLIB_API unsigned ZSTD_isSkippableFrame(const void* buffer, size_t size); + + + +/*************************************** +* Memory management +***************************************/ + +/*! ZSTD_estimate*() : + * These functions make it possible to estimate memory usage + * of a future {D,C}Ctx, before its creation. + * + * ZSTD_estimateCCtxSize() will provide a memory budget large enough + * for any compression level up to selected one. + * Note : Unlike ZSTD_estimateCStreamSize*(), this estimate + * does not include space for a window buffer. + * Therefore, the estimation is only guaranteed for single-shot compressions, not streaming. + * The estimate will assume the input may be arbitrarily large, + * which is the worst case. + * + * When srcSize can be bound by a known and rather "small" value, + * this fact can be used to provide a tighter estimation + * because the CCtx compression context will need less memory. + * This tighter estimation can be provided by more advanced functions + * ZSTD_estimateCCtxSize_usingCParams(), which can be used in tandem with ZSTD_getCParams(), + * and ZSTD_estimateCCtxSize_usingCCtxParams(), which can be used in tandem with ZSTD_CCtxParams_setParameter(). + * Both can be used to estimate memory using custom compression parameters and arbitrary srcSize limits. + * + * Note : only single-threaded compression is supported. + * ZSTD_estimateCCtxSize_usingCCtxParams() will return an error code if ZSTD_c_nbWorkers is >= 1. + * + * Note 2 : ZSTD_estimateCCtxSize* functions are not compatible with the Block-Level Sequence Producer API at this time. + * Size estimates assume that no external sequence producer is registered. + */ +ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize(int compressionLevel); +ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams); +ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params); +ZSTDLIB_STATIC_API size_t ZSTD_estimateDCtxSize(void); + +/*! ZSTD_estimateCStreamSize() : + * ZSTD_estimateCStreamSize() will provide a budget large enough for any compression level up to selected one. + * It will also consider src size to be arbitrarily "large", which is worst case. + * If srcSize is known to always be small, ZSTD_estimateCStreamSize_usingCParams() can provide a tighter estimation. + * ZSTD_estimateCStreamSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. + * ZSTD_estimateCStreamSize_usingCCtxParams() can be used in tandem with ZSTD_CCtxParams_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_c_nbWorkers is >= 1. + * Note : CStream size estimation is only correct for single-threaded compression. + * ZSTD_DStream memory budget depends on window Size. + * This information can be passed manually, using ZSTD_estimateDStreamSize, + * or deducted from a valid frame Header, using ZSTD_estimateDStreamSize_fromFrame(); + * Note : if streaming is init with function ZSTD_init?Stream_usingDict(), + * an internal ?Dict will be created, which additional size is not estimated here. + * In this case, get total size by adding ZSTD_estimate?DictSize + * Note 2 : only single-threaded compression is supported. + * ZSTD_estimateCStreamSize_usingCCtxParams() will return an error code if ZSTD_c_nbWorkers is >= 1. + * Note 3 : ZSTD_estimateCStreamSize* functions are not compatible with the Block-Level Sequence Producer API at this time. + * Size estimates assume that no external sequence producer is registered. + */ +ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize(int compressionLevel); +ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams); +ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params); +ZSTDLIB_STATIC_API size_t ZSTD_estimateDStreamSize(size_t windowSize); +ZSTDLIB_STATIC_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize); + +/*! ZSTD_estimate?DictSize() : + * ZSTD_estimateCDictSize() will bet that src size is relatively "small", and content is copied, like ZSTD_createCDict(). + * ZSTD_estimateCDictSize_advanced() makes it possible to control compression parameters precisely, like ZSTD_createCDict_advanced(). + * Note : dictionaries created by reference (`ZSTD_dlm_byRef`) are logically smaller. + */ +ZSTDLIB_STATIC_API size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel); +ZSTDLIB_STATIC_API size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, ZSTD_dictLoadMethod_e dictLoadMethod); +ZSTDLIB_STATIC_API size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod); + +/*! ZSTD_initStatic*() : + * Initialize an object using a pre-allocated fixed-size buffer. + * workspace: The memory area to emplace the object into. + * Provided pointer *must be 8-bytes aligned*. + * Buffer must outlive object. + * workspaceSize: Use ZSTD_estimate*Size() to determine + * how large workspace must be to support target scenario. + * @return : pointer to object (same address as workspace, just different type), + * or NULL if error (size too small, incorrect alignment, etc.) + * Note : zstd will never resize nor malloc() when using a static buffer. + * If the object requires more memory than available, + * zstd will just error out (typically ZSTD_error_memory_allocation). + * Note 2 : there is no corresponding "free" function. + * Since workspace is allocated externally, it must be freed externally too. + * Note 3 : cParams : use ZSTD_getCParams() to convert a compression level + * into its associated cParams. + * Limitation 1 : currently not compatible with internal dictionary creation, triggered by + * ZSTD_CCtx_loadDictionary(), ZSTD_initCStream_usingDict() or ZSTD_initDStream_usingDict(). + * Limitation 2 : static cctx currently not compatible with multi-threading. + * Limitation 3 : static dctx is incompatible with legacy support. + */ +ZSTDLIB_STATIC_API ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize); +ZSTDLIB_STATIC_API ZSTD_CStream* ZSTD_initStaticCStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticCCtx() */ + +ZSTDLIB_STATIC_API ZSTD_DCtx* ZSTD_initStaticDCtx(void* workspace, size_t workspaceSize); +ZSTDLIB_STATIC_API ZSTD_DStream* ZSTD_initStaticDStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticDCtx() */ + +ZSTDLIB_STATIC_API const ZSTD_CDict* ZSTD_initStaticCDict( + void* workspace, size_t workspaceSize, + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType, + ZSTD_compressionParameters cParams); + +ZSTDLIB_STATIC_API const ZSTD_DDict* ZSTD_initStaticDDict( + void* workspace, size_t workspaceSize, + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType); + + +/*! Custom memory allocation : + * These prototypes make it possible to pass your own allocation/free functions. + * ZSTD_customMem is provided at creation time, using ZSTD_create*_advanced() variants listed below. + * All allocation/free operations will be completed using these custom variants instead of regular ones. + */ +typedef void* (*ZSTD_allocFunction) (void* opaque, size_t size); +typedef void (*ZSTD_freeFunction) (void* opaque, void* address); +typedef struct { ZSTD_allocFunction customAlloc; ZSTD_freeFunction customFree; void* opaque; } ZSTD_customMem; +static +#ifdef __GNUC__ +__attribute__((__unused__)) +#endif +ZSTD_customMem const ZSTD_defaultCMem = { NULL, NULL, NULL }; /**< this constant defers to stdlib's functions */ + +ZSTDLIB_STATIC_API ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem); +ZSTDLIB_STATIC_API ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem); +ZSTDLIB_STATIC_API ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem); +ZSTDLIB_STATIC_API ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem); + +ZSTDLIB_STATIC_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType, + ZSTD_compressionParameters cParams, + ZSTD_customMem customMem); + +/*! Thread pool : + * These prototypes make it possible to share a thread pool among multiple compression contexts. + * This can limit resources for applications with multiple threads where each one uses + * a threaded compression mode (via ZSTD_c_nbWorkers parameter). + * ZSTD_createThreadPool creates a new thread pool with a given number of threads. + * Note that the lifetime of such pool must exist while being used. + * ZSTD_CCtx_refThreadPool assigns a thread pool to a context (use NULL argument value + * to use an internal thread pool). + * ZSTD_freeThreadPool frees a thread pool, accepts NULL pointer. + */ +typedef struct POOL_ctx_s ZSTD_threadPool; +ZSTDLIB_STATIC_API ZSTD_threadPool* ZSTD_createThreadPool(size_t numThreads); +ZSTDLIB_STATIC_API void ZSTD_freeThreadPool (ZSTD_threadPool* pool); /* accept NULL pointer */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_refThreadPool(ZSTD_CCtx* cctx, ZSTD_threadPool* pool); + + +/* + * This API is temporary and is expected to change or disappear in the future! + */ +ZSTDLIB_STATIC_API ZSTD_CDict* ZSTD_createCDict_advanced2( + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType, + const ZSTD_CCtx_params* cctxParams, + ZSTD_customMem customMem); + +ZSTDLIB_STATIC_API ZSTD_DDict* ZSTD_createDDict_advanced( + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType, + ZSTD_customMem customMem); + + +/*************************************** +* Advanced compression functions +***************************************/ + +/*! ZSTD_createCDict_byReference() : + * Create a digested dictionary for compression + * Dictionary content is just referenced, not duplicated. + * As a consequence, `dictBuffer` **must** outlive CDict, + * and its content must remain unmodified throughout the lifetime of CDict. + * note: equivalent to ZSTD_createCDict_advanced(), with dictLoadMethod==ZSTD_dlm_byRef */ +ZSTDLIB_STATIC_API ZSTD_CDict* ZSTD_createCDict_byReference(const void* dictBuffer, size_t dictSize, int compressionLevel); + +/*! ZSTD_getCParams() : + * @return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize. + * `estimatedSrcSize` value is optional, select 0 if not known */ +ZSTDLIB_STATIC_API ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize); + +/*! ZSTD_getParams() : + * same as ZSTD_getCParams(), but @return a full `ZSTD_parameters` object instead of sub-component `ZSTD_compressionParameters`. + * All fields of `ZSTD_frameParameters` are set to default : contentSize=1, checksum=0, noDictID=0 */ +ZSTDLIB_STATIC_API ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize); + +/*! ZSTD_checkCParams() : + * Ensure param values remain within authorized range. + * @return 0 on success, or an error code (can be checked with ZSTD_isError()) */ +ZSTDLIB_STATIC_API size_t ZSTD_checkCParams(ZSTD_compressionParameters params); + +/*! ZSTD_adjustCParams() : + * optimize params for a given `srcSize` and `dictSize`. + * `srcSize` can be unknown, in which case use ZSTD_CONTENTSIZE_UNKNOWN. + * `dictSize` must be `0` when there is no dictionary. + * cPar can be invalid : all parameters will be clamped within valid range in the @return struct. + * This function never fails (wide contract) */ +ZSTDLIB_STATIC_API ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize); + +/*! ZSTD_CCtx_setCParams() : + * Set all parameters provided within @p cparams into the working @p cctx. + * Note : if modifying parameters during compression (MT mode only), + * note that changes to the .windowLog parameter will be ignored. + * @return 0 on success, or an error code (can be checked with ZSTD_isError()). + * On failure, no parameters are updated. + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_setCParams(ZSTD_CCtx* cctx, ZSTD_compressionParameters cparams); + +/*! ZSTD_CCtx_setFParams() : + * Set all parameters provided within @p fparams into the working @p cctx. + * @return 0 on success, or an error code (can be checked with ZSTD_isError()). + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_setFParams(ZSTD_CCtx* cctx, ZSTD_frameParameters fparams); + +/*! ZSTD_CCtx_setParams() : + * Set all parameters provided within @p params into the working @p cctx. + * @return 0 on success, or an error code (can be checked with ZSTD_isError()). + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_setParams(ZSTD_CCtx* cctx, ZSTD_parameters params); + +/*! ZSTD_compress_advanced() : + * Note : this function is now DEPRECATED. + * It can be replaced by ZSTD_compress2(), in combination with ZSTD_CCtx_setParameter() and other parameter setters. + * This prototype will generate compilation warnings. */ +ZSTD_DEPRECATED("use ZSTD_compress2") +ZSTDLIB_STATIC_API +size_t ZSTD_compress_advanced(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const void* dict,size_t dictSize, + ZSTD_parameters params); + +/*! ZSTD_compress_usingCDict_advanced() : + * Note : this function is now DEPRECATED. + * It can be replaced by ZSTD_compress2(), in combination with ZSTD_CCtx_loadDictionary() and other parameter setters. + * This prototype will generate compilation warnings. */ +ZSTD_DEPRECATED("use ZSTD_compress2 with ZSTD_CCtx_loadDictionary") +ZSTDLIB_STATIC_API +size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const ZSTD_CDict* cdict, + ZSTD_frameParameters fParams); + + +/*! ZSTD_CCtx_loadDictionary_byReference() : + * Same as ZSTD_CCtx_loadDictionary(), but dictionary content is referenced, instead of being copied into CCtx. + * It saves some memory, but also requires that `dict` outlives its usage within `cctx` */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_loadDictionary_byReference(ZSTD_CCtx* cctx, const void* dict, size_t dictSize); + +/*! ZSTD_CCtx_loadDictionary_advanced() : + * Same as ZSTD_CCtx_loadDictionary(), but gives finer control over + * how to load the dictionary (by copy ? by reference ?) + * and how to interpret it (automatic ? force raw mode ? full mode only ?) */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_loadDictionary_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType); + +/*! ZSTD_CCtx_refPrefix_advanced() : + * Same as ZSTD_CCtx_refPrefix(), but gives finer control over + * how to interpret prefix content (automatic ? force raw mode (default) ? full mode only ?) */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType); + +/* === experimental parameters === */ +/* these parameters can be used with ZSTD_setParameter() + * they are not guaranteed to remain supported in the future */ + + /* Enables rsyncable mode, + * which makes compressed files more rsync friendly + * by adding periodic synchronization points to the compressed data. + * The target average block size is ZSTD_c_jobSize / 2. + * It's possible to modify the job size to increase or decrease + * the granularity of the synchronization point. + * Once the jobSize is smaller than the window size, + * it will result in compression ratio degradation. + * NOTE 1: rsyncable mode only works when multithreading is enabled. + * NOTE 2: rsyncable performs poorly in combination with long range mode, + * since it will decrease the effectiveness of synchronization points, + * though mileage may vary. + * NOTE 3: Rsyncable mode limits maximum compression speed to ~400 MB/s. + * If the selected compression level is already running significantly slower, + * the overall speed won't be significantly impacted. + */ + #define ZSTD_c_rsyncable ZSTD_c_experimentalParam1 + +/* Select a compression format. + * The value must be of type ZSTD_format_e. + * See ZSTD_format_e enum definition for details */ +#define ZSTD_c_format ZSTD_c_experimentalParam2 + +/* Force back-reference distances to remain < windowSize, + * even when referencing into Dictionary content (default:0) */ +#define ZSTD_c_forceMaxWindow ZSTD_c_experimentalParam3 + +/* Controls whether the contents of a CDict + * are used in place, or copied into the working context. + * Accepts values from the ZSTD_dictAttachPref_e enum. + * See the comments on that enum for an explanation of the feature. */ +#define ZSTD_c_forceAttachDict ZSTD_c_experimentalParam4 + +/* Controlled with ZSTD_paramSwitch_e enum. + * Default is ZSTD_ps_auto. + * Set to ZSTD_ps_disable to never compress literals. + * Set to ZSTD_ps_enable to always compress literals. (Note: uncompressed literals + * may still be emitted if huffman is not beneficial to use.) + * + * By default, in ZSTD_ps_auto, the library will decide at runtime whether to use + * literals compression based on the compression parameters - specifically, + * negative compression levels do not use literal compression. + */ +#define ZSTD_c_literalCompressionMode ZSTD_c_experimentalParam5 + +/* Tries to fit compressed block size to be around targetCBlockSize. + * No target when targetCBlockSize == 0. + * There is no guarantee on compressed block size (default:0) */ +#define ZSTD_c_targetCBlockSize ZSTD_c_experimentalParam6 + +/* User's best guess of source size. + * Hint is not valid when srcSizeHint == 0. + * There is no guarantee that hint is close to actual source size, + * but compression ratio may regress significantly if guess considerably underestimates */ +#define ZSTD_c_srcSizeHint ZSTD_c_experimentalParam7 + +/* Controls whether the new and experimental "dedicated dictionary search + * structure" can be used. This feature is still rough around the edges, be + * prepared for surprising behavior! + * + * How to use it: + * + * When using a CDict, whether to use this feature or not is controlled at + * CDict creation, and it must be set in a CCtxParams set passed into that + * construction (via ZSTD_createCDict_advanced2()). A compression will then + * use the feature or not based on how the CDict was constructed; the value of + * this param, set in the CCtx, will have no effect. + * + * However, when a dictionary buffer is passed into a CCtx, such as via + * ZSTD_CCtx_loadDictionary(), this param can be set on the CCtx to control + * whether the CDict that is created internally can use the feature or not. + * + * What it does: + * + * Normally, the internal data structures of the CDict are analogous to what + * would be stored in a CCtx after compressing the contents of a dictionary. + * To an approximation, a compression using a dictionary can then use those + * data structures to simply continue what is effectively a streaming + * compression where the simulated compression of the dictionary left off. + * Which is to say, the search structures in the CDict are normally the same + * format as in the CCtx. + * + * It is possible to do better, since the CDict is not like a CCtx: the search + * structures are written once during CDict creation, and then are only read + * after that, while the search structures in the CCtx are both read and + * written as the compression goes along. This means we can choose a search + * structure for the dictionary that is read-optimized. + * + * This feature enables the use of that different structure. + * + * Note that some of the members of the ZSTD_compressionParameters struct have + * different semantics and constraints in the dedicated search structure. It is + * highly recommended that you simply set a compression level in the CCtxParams + * you pass into the CDict creation call, and avoid messing with the cParams + * directly. + * + * Effects: + * + * This will only have any effect when the selected ZSTD_strategy + * implementation supports this feature. Currently, that's limited to + * ZSTD_greedy, ZSTD_lazy, and ZSTD_lazy2. + * + * Note that this means that the CDict tables can no longer be copied into the + * CCtx, so the dict attachment mode ZSTD_dictForceCopy will no longer be + * usable. The dictionary can only be attached or reloaded. + * + * In general, you should expect compression to be faster--sometimes very much + * so--and CDict creation to be slightly slower. Eventually, we will probably + * make this mode the default. + */ +#define ZSTD_c_enableDedicatedDictSearch ZSTD_c_experimentalParam8 + +/* ZSTD_c_stableInBuffer + * Experimental parameter. + * Default is 0 == disabled. Set to 1 to enable. + * + * Tells the compressor that input data presented with ZSTD_inBuffer + * will ALWAYS be the same between calls. + * Technically, the @src pointer must never be changed, + * and the @pos field can only be updated by zstd. + * However, it's possible to increase the @size field, + * allowing scenarios where more data can be appended after compressions starts. + * These conditions are checked by the compressor, + * and compression will fail if they are not respected. + * Also, data in the ZSTD_inBuffer within the range [src, src + pos) + * MUST not be modified during compression or it will result in data corruption. + * + * When this flag is enabled zstd won't allocate an input window buffer, + * because the user guarantees it can reference the ZSTD_inBuffer until + * the frame is complete. But, it will still allocate an output buffer + * large enough to fit a block (see ZSTD_c_stableOutBuffer). This will also + * avoid the memcpy() from the input buffer to the input window buffer. + * + * NOTE: So long as the ZSTD_inBuffer always points to valid memory, using + * this flag is ALWAYS memory safe, and will never access out-of-bounds + * memory. However, compression WILL fail if conditions are not respected. + * + * WARNING: The data in the ZSTD_inBuffer in the range [src, src + pos) MUST + * not be modified during compression or it will result in data corruption. + * This is because zstd needs to reference data in the ZSTD_inBuffer to find + * matches. Normally zstd maintains its own window buffer for this purpose, + * but passing this flag tells zstd to rely on user provided buffer instead. + */ +#define ZSTD_c_stableInBuffer ZSTD_c_experimentalParam9 + +/* ZSTD_c_stableOutBuffer + * Experimental parameter. + * Default is 0 == disabled. Set to 1 to enable. + * + * Tells he compressor that the ZSTD_outBuffer will not be resized between + * calls. Specifically: (out.size - out.pos) will never grow. This gives the + * compressor the freedom to say: If the compressed data doesn't fit in the + * output buffer then return ZSTD_error_dstSizeTooSmall. This allows us to + * always decompress directly into the output buffer, instead of decompressing + * into an internal buffer and copying to the output buffer. + * + * When this flag is enabled zstd won't allocate an output buffer, because + * it can write directly to the ZSTD_outBuffer. It will still allocate the + * input window buffer (see ZSTD_c_stableInBuffer). + * + * Zstd will check that (out.size - out.pos) never grows and return an error + * if it does. While not strictly necessary, this should prevent surprises. + */ +#define ZSTD_c_stableOutBuffer ZSTD_c_experimentalParam10 + +/* ZSTD_c_blockDelimiters + * Default is 0 == ZSTD_sf_noBlockDelimiters. + * + * For use with sequence compression API: ZSTD_compressSequences(). + * + * Designates whether or not the given array of ZSTD_Sequence contains block delimiters + * and last literals, which are defined as sequences with offset == 0 and matchLength == 0. + * See the definition of ZSTD_Sequence for more specifics. + */ +#define ZSTD_c_blockDelimiters ZSTD_c_experimentalParam11 + +/* ZSTD_c_validateSequences + * Default is 0 == disabled. Set to 1 to enable sequence validation. + * + * For use with sequence compression API: ZSTD_compressSequences(). + * Designates whether or not we validate sequences provided to ZSTD_compressSequences() + * during function execution. + * + * Without validation, providing a sequence that does not conform to the zstd spec will cause + * undefined behavior, and may produce a corrupted block. + * + * With validation enabled, if sequence is invalid (see doc/zstd_compression_format.md for + * specifics regarding offset/matchlength requirements) then the function will bail out and + * return an error. + * + */ +#define ZSTD_c_validateSequences ZSTD_c_experimentalParam12 + +/* ZSTD_c_useBlockSplitter + * Controlled with ZSTD_paramSwitch_e enum. + * Default is ZSTD_ps_auto. + * Set to ZSTD_ps_disable to never use block splitter. + * Set to ZSTD_ps_enable to always use block splitter. + * + * By default, in ZSTD_ps_auto, the library will decide at runtime whether to use + * block splitting based on the compression parameters. + */ +#define ZSTD_c_useBlockSplitter ZSTD_c_experimentalParam13 + +/* ZSTD_c_useRowMatchFinder + * Controlled with ZSTD_paramSwitch_e enum. + * Default is ZSTD_ps_auto. + * Set to ZSTD_ps_disable to never use row-based matchfinder. + * Set to ZSTD_ps_enable to force usage of row-based matchfinder. + * + * By default, in ZSTD_ps_auto, the library will decide at runtime whether to use + * the row-based matchfinder based on support for SIMD instructions and the window log. + * Note that this only pertains to compression strategies: greedy, lazy, and lazy2 + */ +#define ZSTD_c_useRowMatchFinder ZSTD_c_experimentalParam14 + +/* ZSTD_c_deterministicRefPrefix + * Default is 0 == disabled. Set to 1 to enable. + * + * Zstd produces different results for prefix compression when the prefix is + * directly adjacent to the data about to be compressed vs. when it isn't. + * This is because zstd detects that the two buffers are contiguous and it can + * use a more efficient match finding algorithm. However, this produces different + * results than when the two buffers are non-contiguous. This flag forces zstd + * to always load the prefix in non-contiguous mode, even if it happens to be + * adjacent to the data, to guarantee determinism. + * + * If you really care about determinism when using a dictionary or prefix, + * like when doing delta compression, you should select this option. It comes + * at a speed penalty of about ~2.5% if the dictionary and data happened to be + * contiguous, and is free if they weren't contiguous. We don't expect that + * intentionally making the dictionary and data contiguous will be worth the + * cost to memcpy() the data. + */ +#define ZSTD_c_deterministicRefPrefix ZSTD_c_experimentalParam15 + +/* ZSTD_c_prefetchCDictTables + * Controlled with ZSTD_paramSwitch_e enum. Default is ZSTD_ps_auto. + * + * In some situations, zstd uses CDict tables in-place rather than copying them + * into the working context. (See docs on ZSTD_dictAttachPref_e above for details). + * In such situations, compression speed is seriously impacted when CDict tables are + * "cold" (outside CPU cache). This parameter instructs zstd to prefetch CDict tables + * when they are used in-place. + * + * For sufficiently small inputs, the cost of the prefetch will outweigh the benefit. + * For sufficiently large inputs, zstd will by default memcpy() CDict tables + * into the working context, so there is no need to prefetch. This parameter is + * targeted at a middle range of input sizes, where a prefetch is cheap enough to be + * useful but memcpy() is too expensive. The exact range of input sizes where this + * makes sense is best determined by careful experimentation. + * + * Note: for this parameter, ZSTD_ps_auto is currently equivalent to ZSTD_ps_disable, + * but in the future zstd may conditionally enable this feature via an auto-detection + * heuristic for cold CDicts. + * Use ZSTD_ps_disable to opt out of prefetching under any circumstances. + */ +#define ZSTD_c_prefetchCDictTables ZSTD_c_experimentalParam16 + +/* ZSTD_c_enableSeqProducerFallback + * Allowed values are 0 (disable) and 1 (enable). The default setting is 0. + * + * Controls whether zstd will fall back to an internal sequence producer if an + * external sequence producer is registered and returns an error code. This fallback + * is block-by-block: the internal sequence producer will only be called for blocks + * where the external sequence producer returns an error code. Fallback parsing will + * follow any other cParam settings, such as compression level, the same as in a + * normal (fully-internal) compression operation. + * + * The user is strongly encouraged to read the full Block-Level Sequence Producer API + * documentation (below) before setting this parameter. */ +#define ZSTD_c_enableSeqProducerFallback ZSTD_c_experimentalParam17 + +/* ZSTD_c_maxBlockSize + * Allowed values are between 1KB and ZSTD_BLOCKSIZE_MAX (128KB). + * The default is ZSTD_BLOCKSIZE_MAX, and setting to 0 will set to the default. + * + * This parameter can be used to set an upper bound on the blocksize + * that overrides the default ZSTD_BLOCKSIZE_MAX. It cannot be used to set upper + * bounds greater than ZSTD_BLOCKSIZE_MAX or bounds lower than 1KB (will make + * compressBound() inaccurate). Only currently meant to be used for testing. + * + */ +#define ZSTD_c_maxBlockSize ZSTD_c_experimentalParam18 + +/* ZSTD_c_searchForExternalRepcodes + * This parameter affects how zstd parses external sequences, such as sequences + * provided through the compressSequences() API or from an external block-level + * sequence producer. + * + * If set to ZSTD_ps_enable, the library will check for repeated offsets in + * external sequences, even if those repcodes are not explicitly indicated in + * the "rep" field. Note that this is the only way to exploit repcode matches + * while using compressSequences() or an external sequence producer, since zstd + * currently ignores the "rep" field of external sequences. + * + * If set to ZSTD_ps_disable, the library will not exploit repeated offsets in + * external sequences, regardless of whether the "rep" field has been set. This + * reduces sequence compression overhead by about 25% while sacrificing some + * compression ratio. + * + * The default value is ZSTD_ps_auto, for which the library will enable/disable + * based on compression level. + * + * Note: for now, this param only has an effect if ZSTD_c_blockDelimiters is + * set to ZSTD_sf_explicitBlockDelimiters. That may change in the future. + */ +#define ZSTD_c_searchForExternalRepcodes ZSTD_c_experimentalParam19 + +/*! ZSTD_CCtx_getParameter() : + * Get the requested compression parameter value, selected by enum ZSTD_cParameter, + * and store it into int* value. + * @return : 0, or an error code (which can be tested with ZSTD_isError()). + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_getParameter(const ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value); + + +/*! ZSTD_CCtx_params : + * Quick howto : + * - ZSTD_createCCtxParams() : Create a ZSTD_CCtx_params structure + * - ZSTD_CCtxParams_setParameter() : Push parameters one by one into + * an existing ZSTD_CCtx_params structure. + * This is similar to + * ZSTD_CCtx_setParameter(). + * - ZSTD_CCtx_setParametersUsingCCtxParams() : Apply parameters to + * an existing CCtx. + * These parameters will be applied to + * all subsequent frames. + * - ZSTD_compressStream2() : Do compression using the CCtx. + * - ZSTD_freeCCtxParams() : Free the memory, accept NULL pointer. + * + * This can be used with ZSTD_estimateCCtxSize_advanced_usingCCtxParams() + * for static allocation of CCtx for single-threaded compression. + */ +ZSTDLIB_STATIC_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void); +ZSTDLIB_STATIC_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params); /* accept NULL pointer */ + +/*! ZSTD_CCtxParams_reset() : + * Reset params to default values. + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params); + +/*! ZSTD_CCtxParams_init() : + * Initializes the compression parameters of cctxParams according to + * compression level. All other parameters are reset to their default values. + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel); + +/*! ZSTD_CCtxParams_init_advanced() : + * Initializes the compression and frame parameters of cctxParams according to + * params. All other parameters are reset to their default values. + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params); + +/*! ZSTD_CCtxParams_setParameter() : Requires v1.4.0+ + * Similar to ZSTD_CCtx_setParameter. + * Set one compression parameter, selected by enum ZSTD_cParameter. + * Parameters must be applied to a ZSTD_CCtx using + * ZSTD_CCtx_setParametersUsingCCtxParams(). + * @result : a code representing success or failure (which can be tested with + * ZSTD_isError()). + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, int value); + +/*! ZSTD_CCtxParams_getParameter() : + * Similar to ZSTD_CCtx_getParameter. + * Get the requested value of one compression parameter, selected by enum ZSTD_cParameter. + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_getParameter(const ZSTD_CCtx_params* params, ZSTD_cParameter param, int* value); + +/*! ZSTD_CCtx_setParametersUsingCCtxParams() : + * Apply a set of ZSTD_CCtx_params to the compression context. + * This can be done even after compression is started, + * if nbWorkers==0, this will have no impact until a new compression is started. + * if nbWorkers>=1, new parameters will be picked up at next job, + * with a few restrictions (windowLog, pledgedSrcSize, nbWorkers, jobSize, and overlapLog are not updated). + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_setParametersUsingCCtxParams( + ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params); + +/*! ZSTD_compressStream2_simpleArgs() : + * Same as ZSTD_compressStream2(), + * but using only integral types as arguments. + * This variant might be helpful for binders from dynamic languages + * which have troubles handling structures containing memory pointers. + */ +ZSTDLIB_STATIC_API size_t ZSTD_compressStream2_simpleArgs ( + ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, size_t* dstPos, + const void* src, size_t srcSize, size_t* srcPos, + ZSTD_EndDirective endOp); + + +/*************************************** +* Advanced decompression functions +***************************************/ + +/*! ZSTD_isFrame() : + * Tells if the content of `buffer` starts with a valid Frame Identifier. + * Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0. + * Note 2 : Legacy Frame Identifiers are considered valid only if Legacy Support is enabled. + * Note 3 : Skippable Frame Identifiers are considered valid. */ +ZSTDLIB_STATIC_API unsigned ZSTD_isFrame(const void* buffer, size_t size); + +/*! ZSTD_createDDict_byReference() : + * Create a digested dictionary, ready to start decompression operation without startup delay. + * Dictionary content is referenced, and therefore stays in dictBuffer. + * It is important that dictBuffer outlives DDict, + * it must remain read accessible throughout the lifetime of DDict */ +ZSTDLIB_STATIC_API ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize); + +/*! ZSTD_DCtx_loadDictionary_byReference() : + * Same as ZSTD_DCtx_loadDictionary(), + * but references `dict` content instead of copying it into `dctx`. + * This saves memory if `dict` remains around., + * However, it's imperative that `dict` remains accessible (and unmodified) while being used, so it must outlive decompression. */ +ZSTDLIB_STATIC_API size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); + +/*! ZSTD_DCtx_loadDictionary_advanced() : + * Same as ZSTD_DCtx_loadDictionary(), + * but gives direct control over + * how to load the dictionary (by copy ? by reference ?) + * and how to interpret it (automatic ? force raw mode ? full mode only ?). */ +ZSTDLIB_STATIC_API size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType); + +/*! ZSTD_DCtx_refPrefix_advanced() : + * Same as ZSTD_DCtx_refPrefix(), but gives finer control over + * how to interpret prefix content (automatic ? force raw mode (default) ? full mode only ?) */ +ZSTDLIB_STATIC_API size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType); + +/*! ZSTD_DCtx_setMaxWindowSize() : + * Refuses allocating internal buffers for frames requiring a window size larger than provided limit. + * This protects a decoder context from reserving too much memory for itself (potential attack scenario). + * This parameter is only useful in streaming mode, since no internal buffer is allocated in single-pass mode. + * By default, a decompression context accepts all window sizes <= (1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT) + * @return : 0, or an error code (which can be tested using ZSTD_isError()). + */ +ZSTDLIB_STATIC_API size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize); + +/*! ZSTD_DCtx_getParameter() : + * Get the requested decompression parameter value, selected by enum ZSTD_dParameter, + * and store it into int* value. + * @return : 0, or an error code (which can be tested with ZSTD_isError()). + */ +ZSTDLIB_STATIC_API size_t ZSTD_DCtx_getParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int* value); + +/* ZSTD_d_format + * experimental parameter, + * allowing selection between ZSTD_format_e input compression formats + */ +#define ZSTD_d_format ZSTD_d_experimentalParam1 +/* ZSTD_d_stableOutBuffer + * Experimental parameter. + * Default is 0 == disabled. Set to 1 to enable. + * + * Tells the decompressor that the ZSTD_outBuffer will ALWAYS be the same + * between calls, except for the modifications that zstd makes to pos (the + * caller must not modify pos). This is checked by the decompressor, and + * decompression will fail if it ever changes. Therefore the ZSTD_outBuffer + * MUST be large enough to fit the entire decompressed frame. This will be + * checked when the frame content size is known. The data in the ZSTD_outBuffer + * in the range [dst, dst + pos) MUST not be modified during decompression + * or you will get data corruption. + * + * When this flag is enabled zstd won't allocate an output buffer, because + * it can write directly to the ZSTD_outBuffer, but it will still allocate + * an input buffer large enough to fit any compressed block. This will also + * avoid the memcpy() from the internal output buffer to the ZSTD_outBuffer. + * If you need to avoid the input buffer allocation use the buffer-less + * streaming API. + * + * NOTE: So long as the ZSTD_outBuffer always points to valid memory, using + * this flag is ALWAYS memory safe, and will never access out-of-bounds + * memory. However, decompression WILL fail if you violate the preconditions. + * + * WARNING: The data in the ZSTD_outBuffer in the range [dst, dst + pos) MUST + * not be modified during decompression or you will get data corruption. This + * is because zstd needs to reference data in the ZSTD_outBuffer to regenerate + * matches. Normally zstd maintains its own buffer for this purpose, but passing + * this flag tells zstd to use the user provided buffer. + */ +#define ZSTD_d_stableOutBuffer ZSTD_d_experimentalParam2 + +/* ZSTD_d_forceIgnoreChecksum + * Experimental parameter. + * Default is 0 == disabled. Set to 1 to enable + * + * Tells the decompressor to skip checksum validation during decompression, regardless + * of whether checksumming was specified during compression. This offers some + * slight performance benefits, and may be useful for debugging. + * Param has values of type ZSTD_forceIgnoreChecksum_e + */ +#define ZSTD_d_forceIgnoreChecksum ZSTD_d_experimentalParam3 + +/* ZSTD_d_refMultipleDDicts + * Experimental parameter. + * Default is 0 == disabled. Set to 1 to enable + * + * If enabled and dctx is allocated on the heap, then additional memory will be allocated + * to store references to multiple ZSTD_DDict. That is, multiple calls of ZSTD_refDDict() + * using a given ZSTD_DCtx, rather than overwriting the previous DDict reference, will instead + * store all references. At decompression time, the appropriate dictID is selected + * from the set of DDicts based on the dictID in the frame. + * + * Usage is simply calling ZSTD_refDDict() on multiple dict buffers. + * + * Param has values of byte ZSTD_refMultipleDDicts_e + * + * WARNING: Enabling this parameter and calling ZSTD_DCtx_refDDict(), will trigger memory + * allocation for the hash table. ZSTD_freeDCtx() also frees this memory. + * Memory is allocated as per ZSTD_DCtx::customMem. + * + * Although this function allocates memory for the table, the user is still responsible for + * memory management of the underlying ZSTD_DDict* themselves. + */ +#define ZSTD_d_refMultipleDDicts ZSTD_d_experimentalParam4 + +/* ZSTD_d_disableHuffmanAssembly + * Set to 1 to disable the Huffman assembly implementation. + * The default value is 0, which allows zstd to use the Huffman assembly + * implementation if available. + * + * This parameter can be used to disable Huffman assembly at runtime. + * If you want to disable it at compile time you can define the macro + * ZSTD_DISABLE_ASM. + */ +#define ZSTD_d_disableHuffmanAssembly ZSTD_d_experimentalParam5 + + +/*! ZSTD_DCtx_setFormat() : + * This function is REDUNDANT. Prefer ZSTD_DCtx_setParameter(). + * Instruct the decoder context about what kind of data to decode next. + * This instruction is mandatory to decode data without a fully-formed header, + * such ZSTD_f_zstd1_magicless for example. + * @return : 0, or an error code (which can be tested using ZSTD_isError()). */ +ZSTD_DEPRECATED("use ZSTD_DCtx_setParameter() instead") +ZSTDLIB_STATIC_API +size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format); + +/*! ZSTD_decompressStream_simpleArgs() : + * Same as ZSTD_decompressStream(), + * but using only integral types as arguments. + * This can be helpful for binders from dynamic languages + * which have troubles handling structures containing memory pointers. + */ +ZSTDLIB_STATIC_API size_t ZSTD_decompressStream_simpleArgs ( + ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, size_t* dstPos, + const void* src, size_t srcSize, size_t* srcPos); + + +/******************************************************************** +* Advanced streaming functions +* Warning : most of these functions are now redundant with the Advanced API. +* Once Advanced API reaches "stable" status, +* redundant functions will be deprecated, and then at some point removed. +********************************************************************/ + +/*===== Advanced Streaming compression functions =====*/ + +/*! ZSTD_initCStream_srcSize() : + * This function is DEPRECATED, and equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * ZSTD_CCtx_refCDict(zcs, NULL); // clear the dictionary (if any) + * ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel); + * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); + * + * pledgedSrcSize must be correct. If it is not known at init time, use + * ZSTD_CONTENTSIZE_UNKNOWN. Note that, for compatibility with older programs, + * "0" also disables frame content size field. It may be enabled in the future. + * This prototype will generate compilation warnings. + */ +ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions") +ZSTDLIB_STATIC_API +size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, + int compressionLevel, + unsigned long long pledgedSrcSize); + +/*! ZSTD_initCStream_usingDict() : + * This function is DEPRECATED, and is equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel); + * ZSTD_CCtx_loadDictionary(zcs, dict, dictSize); + * + * Creates of an internal CDict (incompatible with static CCtx), except if + * dict == NULL or dictSize < 8, in which case no dict is used. + * Note: dict is loaded with ZSTD_dct_auto (treated as a full zstd dictionary if + * it begins with ZSTD_MAGIC_DICTIONARY, else as raw content) and ZSTD_dlm_byCopy. + * This prototype will generate compilation warnings. + */ +ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions") +ZSTDLIB_STATIC_API +size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, + const void* dict, size_t dictSize, + int compressionLevel); + +/*! ZSTD_initCStream_advanced() : + * This function is DEPRECATED, and is equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * ZSTD_CCtx_setParams(zcs, params); + * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); + * ZSTD_CCtx_loadDictionary(zcs, dict, dictSize); + * + * dict is loaded with ZSTD_dct_auto and ZSTD_dlm_byCopy. + * pledgedSrcSize must be correct. + * If srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN. + * This prototype will generate compilation warnings. + */ +ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions") +ZSTDLIB_STATIC_API +size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, + const void* dict, size_t dictSize, + ZSTD_parameters params, + unsigned long long pledgedSrcSize); + +/*! ZSTD_initCStream_usingCDict() : + * This function is DEPRECATED, and equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * ZSTD_CCtx_refCDict(zcs, cdict); + * + * note : cdict will just be referenced, and must outlive compression session + * This prototype will generate compilation warnings. + */ +ZSTD_DEPRECATED("use ZSTD_CCtx_reset and ZSTD_CCtx_refCDict, see zstd.h for detailed instructions") +ZSTDLIB_STATIC_API +size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict); + +/*! ZSTD_initCStream_usingCDict_advanced() : + * This function is DEPRECATED, and is equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * ZSTD_CCtx_setFParams(zcs, fParams); + * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); + * ZSTD_CCtx_refCDict(zcs, cdict); + * + * same as ZSTD_initCStream_usingCDict(), with control over frame parameters. + * pledgedSrcSize must be correct. If srcSize is not known at init time, use + * value ZSTD_CONTENTSIZE_UNKNOWN. + * This prototype will generate compilation warnings. + */ +ZSTD_DEPRECATED("use ZSTD_CCtx_reset and ZSTD_CCtx_refCDict, see zstd.h for detailed instructions") +ZSTDLIB_STATIC_API +size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, + const ZSTD_CDict* cdict, + ZSTD_frameParameters fParams, + unsigned long long pledgedSrcSize); + +/*! ZSTD_resetCStream() : + * This function is DEPRECATED, and is equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); + * Note: ZSTD_resetCStream() interprets pledgedSrcSize == 0 as ZSTD_CONTENTSIZE_UNKNOWN, but + * ZSTD_CCtx_setPledgedSrcSize() does not do the same, so ZSTD_CONTENTSIZE_UNKNOWN must be + * explicitly specified. + * + * start a new frame, using same parameters from previous frame. + * This is typically useful to skip dictionary loading stage, since it will re-use it in-place. + * Note that zcs must be init at least once before using ZSTD_resetCStream(). + * If pledgedSrcSize is not known at reset time, use macro ZSTD_CONTENTSIZE_UNKNOWN. + * If pledgedSrcSize > 0, its value must be correct, as it will be written in header, and controlled at the end. + * For the time being, pledgedSrcSize==0 is interpreted as "srcSize unknown" for compatibility with older programs, + * but it will change to mean "empty" in future version, so use macro ZSTD_CONTENTSIZE_UNKNOWN instead. + * @return : 0, or an error code (which can be tested using ZSTD_isError()) + * This prototype will generate compilation warnings. + */ +ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions") +ZSTDLIB_STATIC_API +size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize); + + +typedef struct { + unsigned long long ingested; /* nb input bytes read and buffered */ + unsigned long long consumed; /* nb input bytes actually compressed */ + unsigned long long produced; /* nb of compressed bytes generated and buffered */ + unsigned long long flushed; /* nb of compressed bytes flushed : not provided; can be tracked from caller side */ + unsigned currentJobID; /* MT only : latest started job nb */ + unsigned nbActiveWorkers; /* MT only : nb of workers actively compressing at probe time */ +} ZSTD_frameProgression; + +/* ZSTD_getFrameProgression() : + * tells how much data has been ingested (read from input) + * consumed (input actually compressed) and produced (output) for current frame. + * Note : (ingested - consumed) is amount of input data buffered internally, not yet compressed. + * Aggregates progression inside active worker threads. + */ +ZSTDLIB_STATIC_API ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx); + +/*! ZSTD_toFlushNow() : + * Tell how many bytes are ready to be flushed immediately. + * Useful for multithreading scenarios (nbWorkers >= 1). + * Probe the oldest active job, defined as oldest job not yet entirely flushed, + * and check its output buffer. + * @return : amount of data stored in oldest job and ready to be flushed immediately. + * if @return == 0, it means either : + * + there is no active job (could be checked with ZSTD_frameProgression()), or + * + oldest job is still actively compressing data, + * but everything it has produced has also been flushed so far, + * therefore flush speed is limited by production speed of oldest job + * irrespective of the speed of concurrent (and newer) jobs. + */ +ZSTDLIB_STATIC_API size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx); + + +/*===== Advanced Streaming decompression functions =====*/ + +/*! + * This function is deprecated, and is equivalent to: + * + * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); + * ZSTD_DCtx_loadDictionary(zds, dict, dictSize); + * + * note: no dictionary will be used if dict == NULL or dictSize < 8 + */ +ZSTD_DEPRECATED("use ZSTD_DCtx_reset + ZSTD_DCtx_loadDictionary, see zstd.h for detailed instructions") +ZSTDLIB_STATIC_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); + +/*! + * This function is deprecated, and is equivalent to: + * + * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); + * ZSTD_DCtx_refDDict(zds, ddict); + * + * note : ddict is referenced, it must outlive decompression session + */ +ZSTD_DEPRECATED("use ZSTD_DCtx_reset + ZSTD_DCtx_refDDict, see zstd.h for detailed instructions") +ZSTDLIB_STATIC_API size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict); + +/*! + * This function is deprecated, and is equivalent to: + * + * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); + * + * re-use decompression parameters from previous init; saves dictionary loading + */ +ZSTD_DEPRECATED("use ZSTD_DCtx_reset, see zstd.h for detailed instructions") +ZSTDLIB_STATIC_API size_t ZSTD_resetDStream(ZSTD_DStream* zds); + + +/* ********************* BLOCK-LEVEL SEQUENCE PRODUCER API ********************* + * + * *** OVERVIEW *** + * The Block-Level Sequence Producer API allows users to provide their own custom + * sequence producer which libzstd invokes to process each block. The produced list + * of sequences (literals and matches) is then post-processed by libzstd to produce + * valid compressed blocks. + * + * This block-level offload API is a more granular complement of the existing + * frame-level offload API compressSequences() (introduced in v1.5.1). It offers + * an easier migration story for applications already integrated with libzstd: the + * user application continues to invoke the same compression functions + * ZSTD_compress2() or ZSTD_compressStream2() as usual, and transparently benefits + * from the specific advantages of the external sequence producer. For example, + * the sequence producer could be tuned to take advantage of known characteristics + * of the input, to offer better speed / ratio, or could leverage hardware + * acceleration not available within libzstd itself. + * + * See contrib/externalSequenceProducer for an example program employing the + * Block-Level Sequence Producer API. + * + * *** USAGE *** + * The user is responsible for implementing a function of type + * ZSTD_sequenceProducer_F. For each block, zstd will pass the following + * arguments to the user-provided function: + * + * - sequenceProducerState: a pointer to a user-managed state for the sequence + * producer. + * + * - outSeqs, outSeqsCapacity: an output buffer for the sequence producer. + * outSeqsCapacity is guaranteed >= ZSTD_sequenceBound(srcSize). The memory + * backing outSeqs is managed by the CCtx. + * + * - src, srcSize: an input buffer for the sequence producer to parse. + * srcSize is guaranteed to be <= ZSTD_BLOCKSIZE_MAX. + * + * - dict, dictSize: a history buffer, which may be empty, which the sequence + * producer may reference as it parses the src buffer. Currently, zstd will + * always pass dictSize == 0 into external sequence producers, but this will + * change in the future. + * + * - compressionLevel: a signed integer representing the zstd compression level + * set by the user for the current operation. The sequence producer may choose + * to use this information to change its compression strategy and speed/ratio + * tradeoff. Note: the compression level does not reflect zstd parameters set + * through the advanced API. + * + * - windowSize: a size_t representing the maximum allowed offset for external + * sequences. Note that sequence offsets are sometimes allowed to exceed the + * windowSize if a dictionary is present, see doc/zstd_compression_format.md + * for details. + * + * The user-provided function shall return a size_t representing the number of + * sequences written to outSeqs. This return value will be treated as an error + * code if it is greater than outSeqsCapacity. The return value must be non-zero + * if srcSize is non-zero. The ZSTD_SEQUENCE_PRODUCER_ERROR macro is provided + * for convenience, but any value greater than outSeqsCapacity will be treated as + * an error code. + * + * If the user-provided function does not return an error code, the sequences + * written to outSeqs must be a valid parse of the src buffer. Data corruption may + * occur if the parse is not valid. A parse is defined to be valid if the + * following conditions hold: + * - The sum of matchLengths and literalLengths must equal srcSize. + * - All sequences in the parse, except for the final sequence, must have + * matchLength >= ZSTD_MINMATCH_MIN. The final sequence must have + * matchLength >= ZSTD_MINMATCH_MIN or matchLength == 0. + * - All offsets must respect the windowSize parameter as specified in + * doc/zstd_compression_format.md. + * - If the final sequence has matchLength == 0, it must also have offset == 0. + * + * zstd will only validate these conditions (and fail compression if they do not + * hold) if the ZSTD_c_validateSequences cParam is enabled. Note that sequence + * validation has a performance cost. + * + * If the user-provided function returns an error, zstd will either fall back + * to an internal sequence producer or fail the compression operation. The user can + * choose between the two behaviors by setting the ZSTD_c_enableSeqProducerFallback + * cParam. Fallback compression will follow any other cParam settings, such as + * compression level, the same as in a normal compression operation. + * + * The user shall instruct zstd to use a particular ZSTD_sequenceProducer_F + * function by calling + * ZSTD_registerSequenceProducer(cctx, + * sequenceProducerState, + * sequenceProducer) + * This setting will persist until the next parameter reset of the CCtx. + * + * The sequenceProducerState must be initialized by the user before calling + * ZSTD_registerSequenceProducer(). The user is responsible for destroying the + * sequenceProducerState. + * + * *** LIMITATIONS *** + * This API is compatible with all zstd compression APIs which respect advanced parameters. + * However, there are three limitations: + * + * First, the ZSTD_c_enableLongDistanceMatching cParam is not currently supported. + * COMPRESSION WILL FAIL if it is enabled and the user tries to compress with a block-level + * external sequence producer. + * - Note that ZSTD_c_enableLongDistanceMatching is auto-enabled by default in some + * cases (see its documentation for details). Users must explicitly set + * ZSTD_c_enableLongDistanceMatching to ZSTD_ps_disable in such cases if an external + * sequence producer is registered. + * - As of this writing, ZSTD_c_enableLongDistanceMatching is disabled by default + * whenever ZSTD_c_windowLog < 128MB, but that's subject to change. Users should + * check the docs on ZSTD_c_enableLongDistanceMatching whenever the Block-Level Sequence + * Producer API is used in conjunction with advanced settings (like ZSTD_c_windowLog). + * + * Second, history buffers are not currently supported. Concretely, zstd will always pass + * dictSize == 0 to the external sequence producer (for now). This has two implications: + * - Dictionaries are not currently supported. Compression will *not* fail if the user + * references a dictionary, but the dictionary won't have any effect. + * - Stream history is not currently supported. All advanced compression APIs, including + * streaming APIs, work with external sequence producers, but each block is treated as + * an independent chunk without history from previous blocks. + * + * Third, multi-threading within a single compression is not currently supported. In other words, + * COMPRESSION WILL FAIL if ZSTD_c_nbWorkers > 0 and an external sequence producer is registered. + * Multi-threading across compressions is fine: simply create one CCtx per thread. + * + * Long-term, we plan to overcome all three limitations. There is no technical blocker to + * overcoming them. It is purely a question of engineering effort. + */ + +#define ZSTD_SEQUENCE_PRODUCER_ERROR ((size_t)(-1)) + +typedef size_t ZSTD_sequenceProducer_F ( + void* sequenceProducerState, + ZSTD_Sequence* outSeqs, size_t outSeqsCapacity, + const void* src, size_t srcSize, + const void* dict, size_t dictSize, + int compressionLevel, + size_t windowSize +); + +/*! ZSTD_registerSequenceProducer() : + * Instruct zstd to use a block-level external sequence producer function. + * + * The sequenceProducerState must be initialized by the caller, and the caller is + * responsible for managing its lifetime. This parameter is sticky across + * compressions. It will remain set until the user explicitly resets compression + * parameters. + * + * Sequence producer registration is considered to be an "advanced parameter", + * part of the "advanced API". This means it will only have an effect on compression + * APIs which respect advanced parameters, such as compress2() and compressStream2(). + * Older compression APIs such as compressCCtx(), which predate the introduction of + * "advanced parameters", will ignore any external sequence producer setting. + * + * The sequence producer can be "cleared" by registering a NULL function pointer. This + * removes all limitations described above in the "LIMITATIONS" section of the API docs. + * + * The user is strongly encouraged to read the full API documentation (above) before + * calling this function. */ +ZSTDLIB_STATIC_API void +ZSTD_registerSequenceProducer( + ZSTD_CCtx* cctx, + void* sequenceProducerState, + ZSTD_sequenceProducer_F* sequenceProducer +); + + +/********************************************************************* +* Buffer-less and synchronous inner streaming functions (DEPRECATED) +* +* This API is deprecated, and will be removed in a future version. +* It allows streaming (de)compression with user allocated buffers. +* However, it is hard to use, and not as well tested as the rest of +* our API. +* +* Please use the normal streaming API instead: ZSTD_compressStream2, +* and ZSTD_decompressStream. +* If there is functionality that you need, but it doesn't provide, +* please open an issue on our GitHub. +********************************************************************* */ + +/** + Buffer-less streaming compression (synchronous mode) + + A ZSTD_CCtx object is required to track streaming operations. + Use ZSTD_createCCtx() / ZSTD_freeCCtx() to manage resource. + ZSTD_CCtx object can be re-used multiple times within successive compression operations. + + Start by initializing a context. + Use ZSTD_compressBegin(), or ZSTD_compressBegin_usingDict() for dictionary compression. + + Then, consume your input using ZSTD_compressContinue(). + There are some important considerations to keep in mind when using this advanced function : + - ZSTD_compressContinue() has no internal buffer. It uses externally provided buffers only. + - Interface is synchronous : input is consumed entirely and produces 1+ compressed blocks. + - Caller must ensure there is enough space in `dst` to store compressed data under worst case scenario. + Worst case evaluation is provided by ZSTD_compressBound(). + ZSTD_compressContinue() doesn't guarantee recover after a failed compression. + - ZSTD_compressContinue() presumes prior input ***is still accessible and unmodified*** (up to maximum distance size, see WindowLog). + It remembers all previous contiguous blocks, plus one separated memory segment (which can itself consists of multiple contiguous blocks) + - ZSTD_compressContinue() detects that prior input has been overwritten when `src` buffer overlaps. + In which case, it will "discard" the relevant memory section from its history. + + Finish a frame with ZSTD_compressEnd(), which will write the last block(s) and optional checksum. + It's possible to use srcSize==0, in which case, it will write a final empty block to end the frame. + Without last block mark, frames are considered unfinished (hence corrupted) by compliant decoders. + + `ZSTD_CCtx` object can be re-used (ZSTD_compressBegin()) to compress again. +*/ + +/*===== Buffer-less streaming compression functions =====*/ +ZSTD_DEPRECATED("The buffer-less API is deprecated in favor of the normal streaming API. See docs.") +ZSTDLIB_STATIC_API size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel); +ZSTD_DEPRECATED("The buffer-less API is deprecated in favor of the normal streaming API. See docs.") +ZSTDLIB_STATIC_API size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel); +ZSTD_DEPRECATED("The buffer-less API is deprecated in favor of the normal streaming API. See docs.") +ZSTDLIB_STATIC_API size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); /**< note: fails if cdict==NULL */ + +ZSTD_DEPRECATED("This function will likely be removed in a future release. It is misleading and has very limited utility.") +ZSTDLIB_STATIC_API +size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, unsigned long long pledgedSrcSize); /**< note: if pledgedSrcSize is not known, use ZSTD_CONTENTSIZE_UNKNOWN */ + +ZSTD_DEPRECATED("The buffer-less API is deprecated in favor of the normal streaming API. See docs.") +ZSTDLIB_STATIC_API size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); +ZSTD_DEPRECATED("The buffer-less API is deprecated in favor of the normal streaming API. See docs.") +ZSTDLIB_STATIC_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); + +/* The ZSTD_compressBegin_advanced() and ZSTD_compressBegin_usingCDict_advanced() are now DEPRECATED and will generate a compiler warning */ +ZSTD_DEPRECATED("use advanced API to access custom parameters") +ZSTDLIB_STATIC_API +size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize : If srcSize is not known at init time, use ZSTD_CONTENTSIZE_UNKNOWN */ +ZSTD_DEPRECATED("use advanced API to access custom parameters") +ZSTDLIB_STATIC_API +size_t ZSTD_compressBegin_usingCDict_advanced(ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize); /* compression parameters are already set within cdict. pledgedSrcSize must be correct. If srcSize is not known, use macro ZSTD_CONTENTSIZE_UNKNOWN */ +/** + Buffer-less streaming decompression (synchronous mode) + + A ZSTD_DCtx object is required to track streaming operations. + Use ZSTD_createDCtx() / ZSTD_freeDCtx() to manage it. + A ZSTD_DCtx object can be re-used multiple times. + + First typical operation is to retrieve frame parameters, using ZSTD_getFrameHeader(). + Frame header is extracted from the beginning of compressed frame, so providing only the frame's beginning is enough. + Data fragment must be large enough to ensure successful decoding. + `ZSTD_frameHeaderSize_max` bytes is guaranteed to always be large enough. + result : 0 : successful decoding, the `ZSTD_frameHeader` structure is correctly filled. + >0 : `srcSize` is too small, please provide at least result bytes on next attempt. + errorCode, which can be tested using ZSTD_isError(). + + It fills a ZSTD_frameHeader structure with important information to correctly decode the frame, + such as the dictionary ID, content size, or maximum back-reference distance (`windowSize`). + Note that these values could be wrong, either because of data corruption, or because a 3rd party deliberately spoofs false information. + As a consequence, check that values remain within valid application range. + For example, do not allocate memory blindly, check that `windowSize` is within expectation. + Each application can set its own limits, depending on local restrictions. + For extended interoperability, it is recommended to support `windowSize` of at least 8 MB. + + ZSTD_decompressContinue() needs previous data blocks during decompression, up to `windowSize` bytes. + ZSTD_decompressContinue() is very sensitive to contiguity, + if 2 blocks don't follow each other, make sure that either the compressor breaks contiguity at the same place, + or that previous contiguous segment is large enough to properly handle maximum back-reference distance. + There are multiple ways to guarantee this condition. + + The most memory efficient way is to use a round buffer of sufficient size. + Sufficient size is determined by invoking ZSTD_decodingBufferSize_min(), + which can return an error code if required value is too large for current system (in 32-bits mode). + In a round buffer methodology, ZSTD_decompressContinue() decompresses each block next to previous one, + up to the moment there is not enough room left in the buffer to guarantee decoding another full block, + which maximum size is provided in `ZSTD_frameHeader` structure, field `blockSizeMax`. + At which point, decoding can resume from the beginning of the buffer. + Note that already decoded data stored in the buffer should be flushed before being overwritten. + + There are alternatives possible, for example using two or more buffers of size `windowSize` each, though they consume more memory. + + Finally, if you control the compression process, you can also ignore all buffer size rules, + as long as the encoder and decoder progress in "lock-step", + aka use exactly the same buffer sizes, break contiguity at the same place, etc. + + Once buffers are setup, start decompression, with ZSTD_decompressBegin(). + If decompression requires a dictionary, use ZSTD_decompressBegin_usingDict() or ZSTD_decompressBegin_usingDDict(). + + Then use ZSTD_nextSrcSizeToDecompress() and ZSTD_decompressContinue() alternatively. + ZSTD_nextSrcSizeToDecompress() tells how many bytes to provide as 'srcSize' to ZSTD_decompressContinue(). + ZSTD_decompressContinue() requires this _exact_ amount of bytes, or it will fail. + + result of ZSTD_decompressContinue() is the number of bytes regenerated within 'dst' (necessarily <= dstCapacity). + It can be zero : it just means ZSTD_decompressContinue() has decoded some metadata item. + It can also be an error code, which can be tested with ZSTD_isError(). + + A frame is fully decoded when ZSTD_nextSrcSizeToDecompress() returns zero. + Context can then be reset to start a new decompression. + + Note : it's possible to know if next input to present is a header or a block, using ZSTD_nextInputType(). + This information is not required to properly decode a frame. + + == Special case : skippable frames == + + Skippable frames allow integration of user-defined data into a flow of concatenated frames. + Skippable frames will be ignored (skipped) by decompressor. + The format of skippable frames is as follows : + a) Skippable frame ID - 4 Bytes, Little endian format, any value from 0x184D2A50 to 0x184D2A5F + b) Frame Size - 4 Bytes, Little endian format, unsigned 32-bits + c) Frame Content - any content (User Data) of length equal to Frame Size + For skippable frames ZSTD_getFrameHeader() returns zfhPtr->frameType==ZSTD_skippableFrame. + For skippable frames ZSTD_decompressContinue() always returns 0 : it only skips the content. +*/ + +/*===== Buffer-less streaming decompression functions =====*/ + +ZSTDLIB_STATIC_API size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize); /**< when frame content size is not known, pass in frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN */ + +ZSTDLIB_STATIC_API size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx); +ZSTDLIB_STATIC_API size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); +ZSTDLIB_STATIC_API size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); + +ZSTDLIB_STATIC_API size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx); +ZSTDLIB_STATIC_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); + +/* misc */ +ZSTD_DEPRECATED("This function will likely be removed in the next minor release. It is misleading and has very limited utility.") +ZSTDLIB_STATIC_API void ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx); +typedef enum { ZSTDnit_frameHeader, ZSTDnit_blockHeader, ZSTDnit_block, ZSTDnit_lastBlock, ZSTDnit_checksum, ZSTDnit_skippableFrame } ZSTD_nextInputType_e; +ZSTDLIB_STATIC_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx); + + + + +/* ========================================= */ +/** Block level API (DEPRECATED) */ +/* ========================================= */ + +/*! + + This API is deprecated in favor of the regular compression API. + You can get the frame header down to 2 bytes by setting: + - ZSTD_c_format = ZSTD_f_zstd1_magicless + - ZSTD_c_contentSizeFlag = 0 + - ZSTD_c_checksumFlag = 0 + - ZSTD_c_dictIDFlag = 0 + + This API is not as well tested as our normal API, so we recommend not using it. + We will be removing it in a future version. If the normal API doesn't provide + the functionality you need, please open a GitHub issue. + + Block functions produce and decode raw zstd blocks, without frame metadata. + Frame metadata cost is typically ~12 bytes, which can be non-negligible for very small blocks (< 100 bytes). + But users will have to take in charge needed metadata to regenerate data, such as compressed and content sizes. + + A few rules to respect : + - Compressing and decompressing require a context structure + + Use ZSTD_createCCtx() and ZSTD_createDCtx() + - It is necessary to init context before starting + + compression : any ZSTD_compressBegin*() variant, including with dictionary + + decompression : any ZSTD_decompressBegin*() variant, including with dictionary + - Block size is limited, it must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX == 128 KB + + If input is larger than a block size, it's necessary to split input data into multiple blocks + + For inputs larger than a single block, consider using regular ZSTD_compress() instead. + Frame metadata is not that costly, and quickly becomes negligible as source size grows larger than a block. + - When a block is considered not compressible enough, ZSTD_compressBlock() result will be 0 (zero) ! + ===> In which case, nothing is produced into `dst` ! + + User __must__ test for such outcome and deal directly with uncompressed data + + A block cannot be declared incompressible if ZSTD_compressBlock() return value was != 0. + Doing so would mess up with statistics history, leading to potential data corruption. + + ZSTD_decompressBlock() _doesn't accept uncompressed data as input_ !! + + In case of multiple successive blocks, should some of them be uncompressed, + decoder must be informed of their existence in order to follow proper history. + Use ZSTD_insertBlock() for such a case. +*/ + +/*===== Raw zstd block functions =====*/ +ZSTD_DEPRECATED("The block API is deprecated in favor of the normal compression API. See docs.") +ZSTDLIB_STATIC_API size_t ZSTD_getBlockSize (const ZSTD_CCtx* cctx); +ZSTD_DEPRECATED("The block API is deprecated in favor of the normal compression API. See docs.") +ZSTDLIB_STATIC_API size_t ZSTD_compressBlock (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); +ZSTD_DEPRECATED("The block API is deprecated in favor of the normal compression API. See docs.") +ZSTDLIB_STATIC_API size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); +ZSTD_DEPRECATED("The block API is deprecated in favor of the normal compression API. See docs.") +ZSTDLIB_STATIC_API size_t ZSTD_insertBlock (ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize); /**< insert uncompressed block into `dctx` history. Useful for multi-blocks decompression. */ + +#endif /* ZSTD_H_ZSTD_STATIC_LINKING_ONLY */ + +#if defined (__cplusplus) +} +#endif diff --git a/lib/zstd/lib/zstd_errors.h b/lib/zstd/lib/zstd_errors.h new file mode 100644 index 0000000..dc75eee --- /dev/null +++ b/lib/zstd/lib/zstd_errors.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef ZSTD_ERRORS_H_398273423 +#define ZSTD_ERRORS_H_398273423 + +#if defined (__cplusplus) +extern "C" { +#endif + +/*===== dependency =====*/ +#include /* size_t */ + + +/* ===== ZSTDERRORLIB_API : control library symbols visibility ===== */ +#ifndef ZSTDERRORLIB_VISIBLE + /* Backwards compatibility with old macro name */ +# ifdef ZSTDERRORLIB_VISIBILITY +# define ZSTDERRORLIB_VISIBLE ZSTDERRORLIB_VISIBILITY +# elif defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) +# define ZSTDERRORLIB_VISIBLE __attribute__ ((visibility ("default"))) +# else +# define ZSTDERRORLIB_VISIBLE +# endif +#endif + +#ifndef ZSTDERRORLIB_HIDDEN +# if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) +# define ZSTDERRORLIB_HIDDEN __attribute__ ((visibility ("hidden"))) +# else +# define ZSTDERRORLIB_HIDDEN +# endif +#endif + +#if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) +# define ZSTDERRORLIB_API __declspec(dllexport) ZSTDERRORLIB_VISIBLE +#elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) +# define ZSTDERRORLIB_API __declspec(dllimport) ZSTDERRORLIB_VISIBLE /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ +#else +# define ZSTDERRORLIB_API ZSTDERRORLIB_VISIBLE +#endif + +/*-********************************************* + * Error codes list + *-********************************************* + * Error codes _values_ are pinned down since v1.3.1 only. + * Therefore, don't rely on values if you may link to any version < v1.3.1. + * + * Only values < 100 are considered stable. + * + * note 1 : this API shall be used with static linking only. + * dynamic linking is not yet officially supported. + * note 2 : Prefer relying on the enum than on its value whenever possible + * This is the only supported way to use the error list < v1.3.1 + * note 3 : ZSTD_isError() is always correct, whatever the library version. + **********************************************/ +typedef enum { + ZSTD_error_no_error = 0, + ZSTD_error_GENERIC = 1, + ZSTD_error_prefix_unknown = 10, + ZSTD_error_version_unsupported = 12, + ZSTD_error_frameParameter_unsupported = 14, + ZSTD_error_frameParameter_windowTooLarge = 16, + ZSTD_error_corruption_detected = 20, + ZSTD_error_checksum_wrong = 22, + ZSTD_error_literals_headerWrong = 24, + ZSTD_error_dictionary_corrupted = 30, + ZSTD_error_dictionary_wrong = 32, + ZSTD_error_dictionaryCreation_failed = 34, + ZSTD_error_parameter_unsupported = 40, + ZSTD_error_parameter_combination_unsupported = 41, + ZSTD_error_parameter_outOfBound = 42, + ZSTD_error_tableLog_tooLarge = 44, + ZSTD_error_maxSymbolValue_tooLarge = 46, + ZSTD_error_maxSymbolValue_tooSmall = 48, + ZSTD_error_stabilityCondition_notRespected = 50, + ZSTD_error_stage_wrong = 60, + ZSTD_error_init_missing = 62, + ZSTD_error_memory_allocation = 64, + ZSTD_error_workSpace_tooSmall= 66, + ZSTD_error_dstSize_tooSmall = 70, + ZSTD_error_srcSize_wrong = 72, + ZSTD_error_dstBuffer_null = 74, + ZSTD_error_noForwardProgress_destFull = 80, + ZSTD_error_noForwardProgress_inputEmpty = 82, + /* following error codes are __NOT STABLE__, they can be removed or changed in future versions */ + ZSTD_error_frameIndex_tooLarge = 100, + ZSTD_error_seekableIO = 102, + ZSTD_error_dstBuffer_wrong = 104, + ZSTD_error_srcBuffer_wrong = 105, + ZSTD_error_sequenceProducer_failed = 106, + ZSTD_error_externalSequences_invalid = 107, + ZSTD_error_maxCode = 120 /* never EVER use this value directly, it can change in future versions! Use ZSTD_isError() instead */ +} ZSTD_ErrorCode; + +/*! ZSTD_getErrorCode() : + convert a `size_t` function result into a `ZSTD_ErrorCode` enum type, + which can be used to compare with enum list published above */ +ZSTDERRORLIB_API ZSTD_ErrorCode ZSTD_getErrorCode(size_t functionResult); +ZSTDERRORLIB_API const char* ZSTD_getErrorString(ZSTD_ErrorCode code); /**< Same as ZSTD_getErrorName, but using a `ZSTD_ErrorCode` enum argument */ + + +#if defined (__cplusplus) +} +#endif + +#endif /* ZSTD_ERRORS_H_398273423 */ diff --git a/support/chd/mister_chd.cpp b/support/chd/mister_chd.cpp index 14949fe..c5606cf 100644 --- a/support/chd/mister_chd.cpp +++ b/support/chd/mister_chd.cpp @@ -50,7 +50,7 @@ chd_error mister_load_chd(const char *filename, toc_t *cd_toc) mister_chd_log("hunkbytes %d unitbytes %d logical length %llu\n", chd_header->hunkbytes, chd_header->unitbytes, chd_header->logicalbytes); //Set CLOEXEC on underlying FD - int chd_fd = fileno(chd_core_file(cd_toc->chd_f)); + int chd_fd = fileno((FILE *)chd_core_file(cd_toc->chd_f)->argp); if (chd_fd) fcntl(chd_fd, F_SETFD, FD_CLOEXEC); //Load track info