xref: /freebsd/sys/contrib/zstd/lib/legacy/zstd_v07.c (revision 5ff13fbc199bdf5f0572845351c68ee5ca828e71)
10c16b537SWarner Losh /*
2*5ff13fbcSAllan Jude  * Copyright (c) Yann Collet, Facebook, Inc.
30c16b537SWarner Losh  * All rights reserved.
40c16b537SWarner Losh  *
50c16b537SWarner Losh  * This source code is licensed under both the BSD-style license (found in the
60c16b537SWarner Losh  * LICENSE file in the root directory of this source tree) and the GPLv2 (found
70c16b537SWarner Losh  * in the COPYING file in the root directory of this source tree).
80c16b537SWarner Losh  * You may select, at your option, one of the above-listed licenses.
90c16b537SWarner Losh  */
100c16b537SWarner Losh 
110c16b537SWarner Losh 
120c16b537SWarner Losh /*- Dependencies -*/
130c16b537SWarner Losh #include <stddef.h>     /* size_t, ptrdiff_t */
140c16b537SWarner Losh #include <string.h>     /* memcpy */
150c16b537SWarner Losh #include <stdlib.h>     /* malloc, free, qsort */
160c16b537SWarner Losh 
170c16b537SWarner Losh #ifndef XXH_STATIC_LINKING_ONLY
180c16b537SWarner Losh #  define XXH_STATIC_LINKING_ONLY    /* XXH64_state_t */
190c16b537SWarner Losh #endif
2037f1f268SConrad Meyer #include "../common/xxhash.h"                  /* XXH64_* */
210c16b537SWarner Losh #include "zstd_v07.h"
220c16b537SWarner Losh 
230c16b537SWarner Losh #define FSEv07_STATIC_LINKING_ONLY   /* FSEv07_MIN_TABLELOG */
240c16b537SWarner Losh #define HUFv07_STATIC_LINKING_ONLY   /* HUFv07_TABLELOG_ABSOLUTEMAX */
250c16b537SWarner Losh #define ZSTDv07_STATIC_LINKING_ONLY
260c16b537SWarner Losh 
2737f1f268SConrad Meyer #include "../common/error_private.h"
280c16b537SWarner Losh 
290c16b537SWarner Losh 
300c16b537SWarner Losh #ifdef ZSTDv07_STATIC_LINKING_ONLY
310c16b537SWarner Losh 
320c16b537SWarner Losh /* ====================================================================================
330c16b537SWarner Losh  * The definitions in this section are considered experimental.
340c16b537SWarner Losh  * They should never be used with a dynamic library, as they may change in the future.
350c16b537SWarner Losh  * They are provided for advanced usages.
360c16b537SWarner Losh  * Use them only in association with static linking.
370c16b537SWarner Losh  * ==================================================================================== */
380c16b537SWarner Losh 
390c16b537SWarner Losh /*--- Constants ---*/
400c16b537SWarner Losh #define ZSTDv07_MAGIC_SKIPPABLE_START  0x184D2A50U
410c16b537SWarner Losh 
420c16b537SWarner Losh #define ZSTDv07_WINDOWLOG_MAX_32  25
430c16b537SWarner Losh #define ZSTDv07_WINDOWLOG_MAX_64  27
440c16b537SWarner Losh #define ZSTDv07_WINDOWLOG_MAX    ((U32)(MEM_32bits() ? ZSTDv07_WINDOWLOG_MAX_32 : ZSTDv07_WINDOWLOG_MAX_64))
450c16b537SWarner Losh #define ZSTDv07_WINDOWLOG_MIN     18
460c16b537SWarner Losh #define ZSTDv07_CHAINLOG_MAX     (ZSTDv07_WINDOWLOG_MAX+1)
470c16b537SWarner Losh #define ZSTDv07_CHAINLOG_MIN       4
480c16b537SWarner Losh #define ZSTDv07_HASHLOG_MAX       ZSTDv07_WINDOWLOG_MAX
490c16b537SWarner Losh #define ZSTDv07_HASHLOG_MIN       12
500c16b537SWarner Losh #define ZSTDv07_HASHLOG3_MAX      17
510c16b537SWarner Losh #define ZSTDv07_SEARCHLOG_MAX    (ZSTDv07_WINDOWLOG_MAX-1)
520c16b537SWarner Losh #define ZSTDv07_SEARCHLOG_MIN      1
530c16b537SWarner Losh #define ZSTDv07_SEARCHLENGTH_MAX   7
540c16b537SWarner Losh #define ZSTDv07_SEARCHLENGTH_MIN   3
550c16b537SWarner Losh #define ZSTDv07_TARGETLENGTH_MIN   4
560c16b537SWarner Losh #define ZSTDv07_TARGETLENGTH_MAX 999
570c16b537SWarner Losh 
580c16b537SWarner Losh #define ZSTDv07_FRAMEHEADERSIZE_MAX 18    /* for static allocation */
590c16b537SWarner Losh static const size_t ZSTDv07_frameHeaderSize_min = 5;
600c16b537SWarner Losh static const size_t ZSTDv07_frameHeaderSize_max = ZSTDv07_FRAMEHEADERSIZE_MAX;
610c16b537SWarner Losh static const size_t ZSTDv07_skippableHeaderSize = 8;  /* magic number + skippable frame length */
620c16b537SWarner Losh 
630c16b537SWarner Losh 
640c16b537SWarner Losh /* custom memory allocation functions */
650c16b537SWarner Losh typedef void* (*ZSTDv07_allocFunction) (void* opaque, size_t size);
660c16b537SWarner Losh typedef void  (*ZSTDv07_freeFunction) (void* opaque, void* address);
670c16b537SWarner Losh typedef struct { ZSTDv07_allocFunction customAlloc; ZSTDv07_freeFunction customFree; void* opaque; } ZSTDv07_customMem;
680c16b537SWarner Losh 
690c16b537SWarner Losh 
700c16b537SWarner Losh /*--- Advanced Decompression functions ---*/
710c16b537SWarner Losh 
720c16b537SWarner Losh /*! ZSTDv07_estimateDCtxSize() :
730c16b537SWarner Losh  *  Gives the potential amount of memory allocated to create a ZSTDv07_DCtx */
740c16b537SWarner Losh ZSTDLIBv07_API size_t ZSTDv07_estimateDCtxSize(void);
750c16b537SWarner Losh 
760c16b537SWarner Losh /*! ZSTDv07_createDCtx_advanced() :
770c16b537SWarner Losh  *  Create a ZSTD decompression context using external alloc and free functions */
780c16b537SWarner Losh ZSTDLIBv07_API ZSTDv07_DCtx* ZSTDv07_createDCtx_advanced(ZSTDv07_customMem customMem);
790c16b537SWarner Losh 
800c16b537SWarner Losh /*! ZSTDv07_sizeofDCtx() :
810c16b537SWarner Losh  *  Gives the amount of memory used by a given ZSTDv07_DCtx */
820c16b537SWarner Losh ZSTDLIBv07_API size_t ZSTDv07_sizeofDCtx(const ZSTDv07_DCtx* dctx);
830c16b537SWarner Losh 
840c16b537SWarner Losh 
850c16b537SWarner Losh /* ******************************************************************
860c16b537SWarner Losh *  Buffer-less streaming functions (synchronous mode)
870c16b537SWarner Losh ********************************************************************/
880c16b537SWarner Losh 
890c16b537SWarner Losh ZSTDLIBv07_API size_t ZSTDv07_decompressBegin(ZSTDv07_DCtx* dctx);
900c16b537SWarner Losh ZSTDLIBv07_API size_t ZSTDv07_decompressBegin_usingDict(ZSTDv07_DCtx* dctx, const void* dict, size_t dictSize);
910c16b537SWarner Losh ZSTDLIBv07_API void   ZSTDv07_copyDCtx(ZSTDv07_DCtx* dctx, const ZSTDv07_DCtx* preparedDCtx);
920c16b537SWarner Losh 
930c16b537SWarner Losh ZSTDLIBv07_API size_t ZSTDv07_nextSrcSizeToDecompress(ZSTDv07_DCtx* dctx);
940c16b537SWarner Losh ZSTDLIBv07_API size_t ZSTDv07_decompressContinue(ZSTDv07_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
950c16b537SWarner Losh 
960c16b537SWarner Losh /*
970c16b537SWarner Losh   Buffer-less streaming decompression (synchronous mode)
980c16b537SWarner Losh 
990c16b537SWarner Losh   A ZSTDv07_DCtx object is required to track streaming operations.
1000c16b537SWarner Losh   Use ZSTDv07_createDCtx() / ZSTDv07_freeDCtx() to manage it.
1010c16b537SWarner Losh   A ZSTDv07_DCtx object can be re-used multiple times.
1020c16b537SWarner Losh 
1030c16b537SWarner Losh   First optional operation is to retrieve frame parameters, using ZSTDv07_getFrameParams(), which doesn't consume the input.
1040c16b537SWarner Losh   It can provide the minimum size of rolling buffer required to properly decompress data (`windowSize`),
1050c16b537SWarner Losh   and optionally the final size of uncompressed content.
1060c16b537SWarner Losh   (Note : content size is an optional info that may not be present. 0 means : content size unknown)
1070c16b537SWarner Losh   Frame parameters are extracted from the beginning of compressed frame.
1080c16b537SWarner Losh   The amount of data to read is variable, from ZSTDv07_frameHeaderSize_min to ZSTDv07_frameHeaderSize_max (so if `srcSize` >= ZSTDv07_frameHeaderSize_max, it will always work)
1090c16b537SWarner Losh   If `srcSize` is too small for operation to succeed, function will return the minimum size it requires to produce a result.
1100c16b537SWarner Losh   Result : 0 when successful, it means the ZSTDv07_frameParams structure has been filled.
1110c16b537SWarner Losh           >0 : means there is not enough data into `src`. Provides the expected size to successfully decode header.
1120c16b537SWarner Losh            errorCode, which can be tested using ZSTDv07_isError()
1130c16b537SWarner Losh 
1140c16b537SWarner Losh   Start decompression, with ZSTDv07_decompressBegin() or ZSTDv07_decompressBegin_usingDict().
1150c16b537SWarner Losh   Alternatively, you can copy a prepared context, using ZSTDv07_copyDCtx().
1160c16b537SWarner Losh 
1170c16b537SWarner Losh   Then use ZSTDv07_nextSrcSizeToDecompress() and ZSTDv07_decompressContinue() alternatively.
1180c16b537SWarner Losh   ZSTDv07_nextSrcSizeToDecompress() tells how much bytes to provide as 'srcSize' to ZSTDv07_decompressContinue().
1190c16b537SWarner Losh   ZSTDv07_decompressContinue() requires this exact amount of bytes, or it will fail.
1200c16b537SWarner Losh 
1210c16b537SWarner Losh   @result of ZSTDv07_decompressContinue() is the number of bytes regenerated within 'dst' (necessarily <= dstCapacity).
1220c16b537SWarner Losh   It can be zero, which is not an error; it just means ZSTDv07_decompressContinue() has decoded some header.
1230c16b537SWarner Losh 
1240c16b537SWarner Losh   ZSTDv07_decompressContinue() needs previous data blocks during decompression, up to `windowSize`.
1250c16b537SWarner Losh   They should preferably be located contiguously, prior to current block.
1260c16b537SWarner Losh   Alternatively, a round buffer of sufficient size is also possible. Sufficient size is determined by frame parameters.
1270c16b537SWarner Losh   ZSTDv07_decompressContinue() is very sensitive to contiguity,
1280c16b537SWarner Losh   if 2 blocks don't follow each other, make sure that either the compressor breaks contiguity at the same place,
1290c16b537SWarner Losh     or that previous contiguous segment is large enough to properly handle maximum back-reference.
1300c16b537SWarner Losh 
1310c16b537SWarner Losh   A frame is fully decoded when ZSTDv07_nextSrcSizeToDecompress() returns zero.
1320c16b537SWarner Losh   Context can then be reset to start a new decompression.
1330c16b537SWarner Losh 
1340c16b537SWarner Losh 
1350c16b537SWarner Losh   == Special case : skippable frames ==
1360c16b537SWarner Losh 
1370c16b537SWarner Losh   Skippable frames allow the integration of user-defined data into a flow of concatenated frames.
1380c16b537SWarner Losh   Skippable frames will be ignored (skipped) by a decompressor. The format of skippable frame is following:
1390c16b537SWarner Losh   a) Skippable frame ID - 4 Bytes, Little endian format, any value from 0x184D2A50 to 0x184D2A5F
1400c16b537SWarner Losh   b) Frame Size - 4 Bytes, Little endian format, unsigned 32-bits
1410c16b537SWarner Losh   c) Frame Content - any content (User Data) of length equal to Frame Size
1420c16b537SWarner Losh   For skippable frames ZSTDv07_decompressContinue() always returns 0.
1430c16b537SWarner Losh   For skippable frames ZSTDv07_getFrameParams() returns fparamsPtr->windowLog==0 what means that a frame is skippable.
1440c16b537SWarner Losh   It also returns Frame Size as fparamsPtr->frameContentSize.
1450c16b537SWarner Losh */
1460c16b537SWarner Losh 
1470c16b537SWarner Losh 
1480c16b537SWarner Losh /* **************************************
1490c16b537SWarner Losh *  Block functions
1500c16b537SWarner Losh ****************************************/
1510c16b537SWarner Losh /*! Block functions produce and decode raw zstd blocks, without frame metadata.
1520c16b537SWarner Losh     Frame metadata cost is typically ~18 bytes, which can be non-negligible for very small blocks (< 100 bytes).
1530c16b537SWarner Losh     User will have to take in charge required information to regenerate data, such as compressed and content sizes.
1540c16b537SWarner Losh 
1550c16b537SWarner Losh     A few rules to respect :
1560c16b537SWarner Losh     - Compressing and decompressing require a context structure
1570c16b537SWarner Losh       + Use ZSTDv07_createCCtx() and ZSTDv07_createDCtx()
1580c16b537SWarner Losh     - It is necessary to init context before starting
1590c16b537SWarner Losh       + compression : ZSTDv07_compressBegin()
1600c16b537SWarner Losh       + decompression : ZSTDv07_decompressBegin()
1610c16b537SWarner Losh       + variants _usingDict() are also allowed
1620c16b537SWarner Losh       + copyCCtx() and copyDCtx() work too
1630c16b537SWarner Losh     - Block size is limited, it must be <= ZSTDv07_getBlockSizeMax()
1640c16b537SWarner Losh       + If you need to compress more, cut data into multiple blocks
1650c16b537SWarner Losh       + Consider using the regular ZSTDv07_compress() instead, as frame metadata costs become negligible when source size is large.
1660c16b537SWarner Losh     - When a block is considered not compressible enough, ZSTDv07_compressBlock() result will be zero.
1670c16b537SWarner Losh       In which case, nothing is produced into `dst`.
1680c16b537SWarner Losh       + User must test for such outcome and deal directly with uncompressed data
1690c16b537SWarner Losh       + ZSTDv07_decompressBlock() doesn't accept uncompressed data as input !!!
1700c16b537SWarner Losh       + In case of multiple successive blocks, decoder must be informed of uncompressed block existence to follow proper history.
1710c16b537SWarner Losh         Use ZSTDv07_insertBlock() in such a case.
1720c16b537SWarner Losh */
1730c16b537SWarner Losh 
1740c16b537SWarner Losh #define ZSTDv07_BLOCKSIZE_ABSOLUTEMAX (128 * 1024)   /* define, for static allocation */
1750c16b537SWarner Losh ZSTDLIBv07_API size_t ZSTDv07_decompressBlock(ZSTDv07_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
1760c16b537SWarner Losh ZSTDLIBv07_API size_t ZSTDv07_insertBlock(ZSTDv07_DCtx* dctx, const void* blockStart, size_t blockSize);  /**< insert block into `dctx` history. Useful for uncompressed blocks */
1770c16b537SWarner Losh 
1780c16b537SWarner Losh 
1790c16b537SWarner Losh #endif   /* ZSTDv07_STATIC_LINKING_ONLY */
1800c16b537SWarner Losh 
1810c16b537SWarner Losh 
1820c16b537SWarner Losh /* ******************************************************************
1830c16b537SWarner Losh    mem.h
1840c16b537SWarner Losh    low-level memory access routines
1850c16b537SWarner Losh    Copyright (C) 2013-2015, Yann Collet.
1860c16b537SWarner Losh 
1870c16b537SWarner Losh    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
1880c16b537SWarner Losh 
1890c16b537SWarner Losh    Redistribution and use in source and binary forms, with or without
1900c16b537SWarner Losh    modification, are permitted provided that the following conditions are
1910c16b537SWarner Losh    met:
1920c16b537SWarner Losh 
1930c16b537SWarner Losh        * Redistributions of source code must retain the above copyright
1940c16b537SWarner Losh    notice, this list of conditions and the following disclaimer.
1950c16b537SWarner Losh        * Redistributions in binary form must reproduce the above
1960c16b537SWarner Losh    copyright notice, this list of conditions and the following disclaimer
1970c16b537SWarner Losh    in the documentation and/or other materials provided with the
1980c16b537SWarner Losh    distribution.
1990c16b537SWarner Losh 
2000c16b537SWarner Losh    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2010c16b537SWarner Losh    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2020c16b537SWarner Losh    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2030c16b537SWarner Losh    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2040c16b537SWarner Losh    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2050c16b537SWarner Losh    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2060c16b537SWarner Losh    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2070c16b537SWarner Losh    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2080c16b537SWarner Losh    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2090c16b537SWarner Losh    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2100c16b537SWarner Losh    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2110c16b537SWarner Losh 
2120c16b537SWarner Losh     You can contact the author at :
2130c16b537SWarner Losh     - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
2140c16b537SWarner Losh     - Public forum : https://groups.google.com/forum/#!forum/lz4c
2150c16b537SWarner Losh ****************************************************************** */
2160c16b537SWarner Losh #ifndef MEM_H_MODULE
2170c16b537SWarner Losh #define MEM_H_MODULE
2180c16b537SWarner Losh 
2190c16b537SWarner Losh #if defined (__cplusplus)
2200c16b537SWarner Losh extern "C" {
2210c16b537SWarner Losh #endif
2220c16b537SWarner Losh 
2230c16b537SWarner Losh /*-****************************************
2240c16b537SWarner Losh *  Compiler specifics
2250c16b537SWarner Losh ******************************************/
2260c16b537SWarner Losh #if defined(_MSC_VER)   /* Visual Studio */
2270c16b537SWarner Losh #   include <stdlib.h>  /* _byteswap_ulong */
2280c16b537SWarner Losh #   include <intrin.h>  /* _byteswap_* */
2290c16b537SWarner Losh #endif
2300c16b537SWarner Losh #if defined(__GNUC__)
2310c16b537SWarner Losh #  define MEM_STATIC static __attribute__((unused))
2320c16b537SWarner Losh #elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
2330c16b537SWarner Losh #  define MEM_STATIC static inline
2340c16b537SWarner Losh #elif defined(_MSC_VER)
2350c16b537SWarner Losh #  define MEM_STATIC static __inline
2360c16b537SWarner Losh #else
2370c16b537SWarner Losh #  define MEM_STATIC static  /* this version may generate warnings for unused static functions; disable the relevant warning */
2380c16b537SWarner Losh #endif
2390c16b537SWarner Losh 
2400c16b537SWarner Losh 
2410c16b537SWarner Losh /*-**************************************************************
2420c16b537SWarner Losh *  Basic Types
2430c16b537SWarner Losh *****************************************************************/
2440c16b537SWarner Losh #if  !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
245f7cd7fe5SConrad Meyer # if defined(_AIX)
246f7cd7fe5SConrad Meyer #  include <inttypes.h>
247f7cd7fe5SConrad Meyer # else
248f7cd7fe5SConrad Meyer #  include <stdint.h> /* intptr_t */
249f7cd7fe5SConrad Meyer # endif
2500c16b537SWarner Losh   typedef  uint8_t BYTE;
2510c16b537SWarner Losh   typedef uint16_t U16;
2520c16b537SWarner Losh   typedef  int16_t S16;
2530c16b537SWarner Losh   typedef uint32_t U32;
2540c16b537SWarner Losh   typedef  int32_t S32;
2550c16b537SWarner Losh   typedef uint64_t U64;
2560c16b537SWarner Losh   typedef  int64_t S64;
2570c16b537SWarner Losh #else
2580c16b537SWarner Losh   typedef unsigned char       BYTE;
2590c16b537SWarner Losh   typedef unsigned short      U16;
2600c16b537SWarner Losh   typedef   signed short      S16;
2610c16b537SWarner Losh   typedef unsigned int        U32;
2620c16b537SWarner Losh   typedef   signed int        S32;
2630c16b537SWarner Losh   typedef unsigned long long  U64;
2640c16b537SWarner Losh   typedef   signed long long  S64;
2650c16b537SWarner Losh #endif
2660c16b537SWarner Losh 
2670c16b537SWarner Losh 
2680c16b537SWarner Losh /*-**************************************************************
2690c16b537SWarner Losh *  Memory I/O
2700c16b537SWarner Losh *****************************************************************/
2710c16b537SWarner Losh /* MEM_FORCE_MEMORY_ACCESS :
2720c16b537SWarner Losh  * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.
2730c16b537SWarner Losh  * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.
2740c16b537SWarner Losh  * The below switch allow to select different access method for improved performance.
2750c16b537SWarner Losh  * Method 0 (default) : use `memcpy()`. Safe and portable.
2760c16b537SWarner Losh  * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable).
2770c16b537SWarner Losh  *            This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.
2780c16b537SWarner Losh  * Method 2 : direct access. This method is portable but violate C standard.
2790c16b537SWarner Losh  *            It can generate buggy code on targets depending on alignment.
2800c16b537SWarner Losh  *            In some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)
2810c16b537SWarner Losh  * See http://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details.
2820c16b537SWarner Losh  * Prefer these methods in priority order (0 > 1 > 2)
2830c16b537SWarner Losh  */
2840c16b537SWarner Losh #ifndef MEM_FORCE_MEMORY_ACCESS   /* can be defined externally, on command line for example */
285*5ff13fbcSAllan Jude #  if defined(__INTEL_COMPILER) || defined(__GNUC__) || defined(__ICCARM__)
2860c16b537SWarner Losh #    define MEM_FORCE_MEMORY_ACCESS 1
2870c16b537SWarner Losh #  endif
2880c16b537SWarner Losh #endif
2890c16b537SWarner Losh 
MEM_32bits(void)2900c16b537SWarner Losh MEM_STATIC unsigned MEM_32bits(void) { return sizeof(size_t)==4; }
MEM_64bits(void)2910c16b537SWarner Losh MEM_STATIC unsigned MEM_64bits(void) { return sizeof(size_t)==8; }
2920c16b537SWarner Losh 
MEM_isLittleEndian(void)2930c16b537SWarner Losh MEM_STATIC unsigned MEM_isLittleEndian(void)
2940c16b537SWarner Losh {
2950c16b537SWarner Losh     const union { U32 u; BYTE c[4]; } one = { 1 };   /* don't use static : performance detrimental  */
2960c16b537SWarner Losh     return one.c[0];
2970c16b537SWarner Losh }
2980c16b537SWarner Losh 
2990c16b537SWarner Losh #if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2)
3000c16b537SWarner Losh 
3010c16b537SWarner Losh /* violates C standard, by lying on structure alignment.
3020c16b537SWarner Losh Only use if no other choice to achieve best performance on target platform */
MEM_read16(const void * memPtr)3030c16b537SWarner Losh MEM_STATIC U16 MEM_read16(const void* memPtr) { return *(const U16*) memPtr; }
MEM_read32(const void * memPtr)3040c16b537SWarner Losh MEM_STATIC U32 MEM_read32(const void* memPtr) { return *(const U32*) memPtr; }
MEM_read64(const void * memPtr)3050c16b537SWarner Losh MEM_STATIC U64 MEM_read64(const void* memPtr) { return *(const U64*) memPtr; }
3060c16b537SWarner Losh 
MEM_write16(void * memPtr,U16 value)3070c16b537SWarner Losh MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; }
3080c16b537SWarner Losh 
3090c16b537SWarner Losh #elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1)
3100c16b537SWarner Losh 
3110c16b537SWarner Losh /* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
3120c16b537SWarner Losh /* currently only defined for gcc and icc */
3130c16b537SWarner Losh typedef union { U16 u16; U32 u32; U64 u64; size_t st; } __attribute__((packed)) unalign;
3140c16b537SWarner Losh 
MEM_read16(const void * ptr)3150c16b537SWarner Losh MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign*)ptr)->u16; }
MEM_read32(const void * ptr)3160c16b537SWarner Losh MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign*)ptr)->u32; }
MEM_read64(const void * ptr)3170c16b537SWarner Losh MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign*)ptr)->u64; }
3180c16b537SWarner Losh 
MEM_write16(void * memPtr,U16 value)3190c16b537SWarner Losh MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; }
3200c16b537SWarner Losh 
3210c16b537SWarner Losh #else
3220c16b537SWarner Losh 
3230c16b537SWarner Losh /* default method, safe and standard.
3240c16b537SWarner Losh    can sometimes prove slower */
3250c16b537SWarner Losh 
MEM_read16(const void * memPtr)3260c16b537SWarner Losh MEM_STATIC U16 MEM_read16(const void* memPtr)
3270c16b537SWarner Losh {
3280c16b537SWarner Losh     U16 val; memcpy(&val, memPtr, sizeof(val)); return val;
3290c16b537SWarner Losh }
3300c16b537SWarner Losh 
MEM_read32(const void * memPtr)3310c16b537SWarner Losh MEM_STATIC U32 MEM_read32(const void* memPtr)
3320c16b537SWarner Losh {
3330c16b537SWarner Losh     U32 val; memcpy(&val, memPtr, sizeof(val)); return val;
3340c16b537SWarner Losh }
3350c16b537SWarner Losh 
MEM_read64(const void * memPtr)3360c16b537SWarner Losh MEM_STATIC U64 MEM_read64(const void* memPtr)
3370c16b537SWarner Losh {
3380c16b537SWarner Losh     U64 val; memcpy(&val, memPtr, sizeof(val)); return val;
3390c16b537SWarner Losh }
3400c16b537SWarner Losh 
MEM_write16(void * memPtr,U16 value)3410c16b537SWarner Losh MEM_STATIC void MEM_write16(void* memPtr, U16 value)
3420c16b537SWarner Losh {
3430c16b537SWarner Losh     memcpy(memPtr, &value, sizeof(value));
3440c16b537SWarner Losh }
3450c16b537SWarner Losh 
3460c16b537SWarner Losh #endif /* MEM_FORCE_MEMORY_ACCESS */
3470c16b537SWarner Losh 
MEM_swap32(U32 in)3480c16b537SWarner Losh MEM_STATIC U32 MEM_swap32(U32 in)
3490c16b537SWarner Losh {
3500c16b537SWarner Losh #if defined(_MSC_VER)     /* Visual Studio */
3510c16b537SWarner Losh     return _byteswap_ulong(in);
35219fcbaf1SConrad Meyer #elif defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)
3530c16b537SWarner Losh     return __builtin_bswap32(in);
3540c16b537SWarner Losh #else
3550c16b537SWarner Losh     return  ((in << 24) & 0xff000000 ) |
3560c16b537SWarner Losh             ((in <<  8) & 0x00ff0000 ) |
3570c16b537SWarner Losh             ((in >>  8) & 0x0000ff00 ) |
3580c16b537SWarner Losh             ((in >> 24) & 0x000000ff );
3590c16b537SWarner Losh #endif
3600c16b537SWarner Losh }
3610c16b537SWarner Losh 
MEM_swap64(U64 in)3620c16b537SWarner Losh MEM_STATIC U64 MEM_swap64(U64 in)
3630c16b537SWarner Losh {
3640c16b537SWarner Losh #if defined(_MSC_VER)     /* Visual Studio */
3650c16b537SWarner Losh     return _byteswap_uint64(in);
36619fcbaf1SConrad Meyer #elif defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)
3670c16b537SWarner Losh     return __builtin_bswap64(in);
3680c16b537SWarner Losh #else
3690c16b537SWarner Losh     return  ((in << 56) & 0xff00000000000000ULL) |
3700c16b537SWarner Losh             ((in << 40) & 0x00ff000000000000ULL) |
3710c16b537SWarner Losh             ((in << 24) & 0x0000ff0000000000ULL) |
3720c16b537SWarner Losh             ((in << 8)  & 0x000000ff00000000ULL) |
3730c16b537SWarner Losh             ((in >> 8)  & 0x00000000ff000000ULL) |
3740c16b537SWarner Losh             ((in >> 24) & 0x0000000000ff0000ULL) |
3750c16b537SWarner Losh             ((in >> 40) & 0x000000000000ff00ULL) |
3760c16b537SWarner Losh             ((in >> 56) & 0x00000000000000ffULL);
3770c16b537SWarner Losh #endif
3780c16b537SWarner Losh }
3790c16b537SWarner Losh 
3800c16b537SWarner Losh 
3810c16b537SWarner Losh /*=== Little endian r/w ===*/
3820c16b537SWarner Losh 
MEM_readLE16(const void * memPtr)3830c16b537SWarner Losh MEM_STATIC U16 MEM_readLE16(const void* memPtr)
3840c16b537SWarner Losh {
3850c16b537SWarner Losh     if (MEM_isLittleEndian())
3860c16b537SWarner Losh         return MEM_read16(memPtr);
3870c16b537SWarner Losh     else {
3880c16b537SWarner Losh         const BYTE* p = (const BYTE*)memPtr;
3890c16b537SWarner Losh         return (U16)(p[0] + (p[1]<<8));
3900c16b537SWarner Losh     }
3910c16b537SWarner Losh }
3920c16b537SWarner Losh 
MEM_writeLE16(void * memPtr,U16 val)3930c16b537SWarner Losh MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val)
3940c16b537SWarner Losh {
3950c16b537SWarner Losh     if (MEM_isLittleEndian()) {
3960c16b537SWarner Losh         MEM_write16(memPtr, val);
3970c16b537SWarner Losh     } else {
3980c16b537SWarner Losh         BYTE* p = (BYTE*)memPtr;
3990c16b537SWarner Losh         p[0] = (BYTE)val;
4000c16b537SWarner Losh         p[1] = (BYTE)(val>>8);
4010c16b537SWarner Losh     }
4020c16b537SWarner Losh }
4030c16b537SWarner Losh 
MEM_readLE32(const void * memPtr)4040c16b537SWarner Losh MEM_STATIC U32 MEM_readLE32(const void* memPtr)
4050c16b537SWarner Losh {
4060c16b537SWarner Losh     if (MEM_isLittleEndian())
4070c16b537SWarner Losh         return MEM_read32(memPtr);
4080c16b537SWarner Losh     else
4090c16b537SWarner Losh         return MEM_swap32(MEM_read32(memPtr));
4100c16b537SWarner Losh }
4110c16b537SWarner Losh 
4120c16b537SWarner Losh 
MEM_readLE64(const void * memPtr)4130c16b537SWarner Losh MEM_STATIC U64 MEM_readLE64(const void* memPtr)
4140c16b537SWarner Losh {
4150c16b537SWarner Losh     if (MEM_isLittleEndian())
4160c16b537SWarner Losh         return MEM_read64(memPtr);
4170c16b537SWarner Losh     else
4180c16b537SWarner Losh         return MEM_swap64(MEM_read64(memPtr));
4190c16b537SWarner Losh }
4200c16b537SWarner Losh 
MEM_readLEST(const void * memPtr)4210c16b537SWarner Losh MEM_STATIC size_t MEM_readLEST(const void* memPtr)
4220c16b537SWarner Losh {
4230c16b537SWarner Losh     if (MEM_32bits())
4240c16b537SWarner Losh         return (size_t)MEM_readLE32(memPtr);
4250c16b537SWarner Losh     else
4260c16b537SWarner Losh         return (size_t)MEM_readLE64(memPtr);
4270c16b537SWarner Losh }
4280c16b537SWarner Losh 
4290c16b537SWarner Losh 
4300c16b537SWarner Losh 
4310c16b537SWarner Losh #if defined (__cplusplus)
4320c16b537SWarner Losh }
4330c16b537SWarner Losh #endif
4340c16b537SWarner Losh 
4350c16b537SWarner Losh #endif /* MEM_H_MODULE */
4360c16b537SWarner Losh /* ******************************************************************
4370c16b537SWarner Losh    bitstream
4380c16b537SWarner Losh    Part of FSE library
4390c16b537SWarner Losh    header file (to include)
4400c16b537SWarner Losh    Copyright (C) 2013-2016, Yann Collet.
4410c16b537SWarner Losh 
4420c16b537SWarner Losh    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
4430c16b537SWarner Losh 
4440c16b537SWarner Losh    Redistribution and use in source and binary forms, with or without
4450c16b537SWarner Losh    modification, are permitted provided that the following conditions are
4460c16b537SWarner Losh    met:
4470c16b537SWarner Losh 
4480c16b537SWarner Losh        * Redistributions of source code must retain the above copyright
4490c16b537SWarner Losh    notice, this list of conditions and the following disclaimer.
4500c16b537SWarner Losh        * Redistributions in binary form must reproduce the above
4510c16b537SWarner Losh    copyright notice, this list of conditions and the following disclaimer
4520c16b537SWarner Losh    in the documentation and/or other materials provided with the
4530c16b537SWarner Losh    distribution.
4540c16b537SWarner Losh 
4550c16b537SWarner Losh    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4560c16b537SWarner Losh    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
4570c16b537SWarner Losh    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
4580c16b537SWarner Losh    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
4590c16b537SWarner Losh    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4600c16b537SWarner Losh    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4610c16b537SWarner Losh    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
4620c16b537SWarner Losh    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
4630c16b537SWarner Losh    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4640c16b537SWarner Losh    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
4650c16b537SWarner Losh    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4660c16b537SWarner Losh 
4670c16b537SWarner Losh    You can contact the author at :
4680c16b537SWarner Losh    - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
4690c16b537SWarner Losh ****************************************************************** */
4700c16b537SWarner Losh #ifndef BITSTREAM_H_MODULE
4710c16b537SWarner Losh #define BITSTREAM_H_MODULE
4720c16b537SWarner Losh 
4730c16b537SWarner Losh #if defined (__cplusplus)
4740c16b537SWarner Losh extern "C" {
4750c16b537SWarner Losh #endif
4760c16b537SWarner Losh 
4770c16b537SWarner Losh 
4780c16b537SWarner Losh /*
4790c16b537SWarner Losh *  This API consists of small unitary functions, which must be inlined for best performance.
4800c16b537SWarner Losh *  Since link-time-optimization is not available for all compilers,
4810c16b537SWarner Losh *  these functions are defined into a .h to be included.
4820c16b537SWarner Losh */
4830c16b537SWarner Losh 
4840c16b537SWarner Losh 
4850c16b537SWarner Losh /*=========================================
4860c16b537SWarner Losh *  Target specific
4870c16b537SWarner Losh =========================================*/
4880c16b537SWarner Losh #if defined(__BMI__) && defined(__GNUC__)
4890c16b537SWarner Losh #  include <immintrin.h>   /* support for bextr (experimental) */
4900c16b537SWarner Losh #endif
4910c16b537SWarner Losh 
4920c16b537SWarner Losh /*-********************************************
4930c16b537SWarner Losh *  bitStream decoding API (read backward)
4940c16b537SWarner Losh **********************************************/
4950c16b537SWarner Losh typedef struct
4960c16b537SWarner Losh {
4970c16b537SWarner Losh     size_t   bitContainer;
4980c16b537SWarner Losh     unsigned bitsConsumed;
4990c16b537SWarner Losh     const char* ptr;
5000c16b537SWarner Losh     const char* start;
5010c16b537SWarner Losh } BITv07_DStream_t;
5020c16b537SWarner Losh 
5030c16b537SWarner Losh typedef enum { BITv07_DStream_unfinished = 0,
5040c16b537SWarner Losh                BITv07_DStream_endOfBuffer = 1,
5050c16b537SWarner Losh                BITv07_DStream_completed = 2,
5060c16b537SWarner Losh                BITv07_DStream_overflow = 3 } BITv07_DStream_status;  /* result of BITv07_reloadDStream() */
5070c16b537SWarner Losh                /* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */
5080c16b537SWarner Losh 
5090c16b537SWarner Losh MEM_STATIC size_t   BITv07_initDStream(BITv07_DStream_t* bitD, const void* srcBuffer, size_t srcSize);
5100c16b537SWarner Losh MEM_STATIC size_t   BITv07_readBits(BITv07_DStream_t* bitD, unsigned nbBits);
5110c16b537SWarner Losh MEM_STATIC BITv07_DStream_status BITv07_reloadDStream(BITv07_DStream_t* bitD);
5120c16b537SWarner Losh MEM_STATIC unsigned BITv07_endOfDStream(const BITv07_DStream_t* bitD);
5130c16b537SWarner Losh 
5140c16b537SWarner Losh 
5150c16b537SWarner Losh 
5160c16b537SWarner Losh /*-****************************************
5170c16b537SWarner Losh *  unsafe API
5180c16b537SWarner Losh ******************************************/
5190c16b537SWarner Losh MEM_STATIC size_t BITv07_readBitsFast(BITv07_DStream_t* bitD, unsigned nbBits);
5200c16b537SWarner Losh /* faster, but works only if nbBits >= 1 */
5210c16b537SWarner Losh 
5220c16b537SWarner Losh 
5230c16b537SWarner Losh 
5240c16b537SWarner Losh /*-**************************************************************
5250c16b537SWarner Losh *  Internal functions
5260c16b537SWarner Losh ****************************************************************/
BITv07_highbit32(U32 val)527052d3c12SConrad Meyer MEM_STATIC unsigned BITv07_highbit32 (U32 val)
5280c16b537SWarner Losh {
5290c16b537SWarner Losh #   if defined(_MSC_VER)   /* Visual */
530*5ff13fbcSAllan Jude     unsigned long r;
531*5ff13fbcSAllan Jude     return _BitScanReverse(&r, val) ? (unsigned)r : 0;
5320c16b537SWarner Losh #   elif defined(__GNUC__) && (__GNUC__ >= 3)   /* Use GCC Intrinsic */
5339cbefe25SConrad Meyer     return __builtin_clz (val) ^ 31;
5340c16b537SWarner Losh #   else   /* Software version */
5350c16b537SWarner Losh     static const unsigned 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 };
5360c16b537SWarner Losh     U32 v = val;
5370c16b537SWarner Losh     v |= v >> 1;
5380c16b537SWarner Losh     v |= v >> 2;
5390c16b537SWarner Losh     v |= v >> 4;
5400c16b537SWarner Losh     v |= v >> 8;
5410c16b537SWarner Losh     v |= v >> 16;
5420c16b537SWarner Losh     return DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27];
5430c16b537SWarner Losh #   endif
5440c16b537SWarner Losh }
5450c16b537SWarner Losh 
5460c16b537SWarner Losh 
5470c16b537SWarner Losh 
5480c16b537SWarner Losh /*-********************************************************
5490c16b537SWarner Losh * bitStream decoding
5500c16b537SWarner Losh **********************************************************/
5510c16b537SWarner Losh /*! BITv07_initDStream() :
5520c16b537SWarner Losh *   Initialize a BITv07_DStream_t.
5530c16b537SWarner Losh *   `bitD` : a pointer to an already allocated BITv07_DStream_t structure.
5540c16b537SWarner Losh *   `srcSize` must be the *exact* size of the bitStream, in bytes.
5550c16b537SWarner Losh *   @return : size of stream (== srcSize) or an errorCode if a problem is detected
5560c16b537SWarner Losh */
BITv07_initDStream(BITv07_DStream_t * bitD,const void * srcBuffer,size_t srcSize)5570c16b537SWarner Losh MEM_STATIC size_t BITv07_initDStream(BITv07_DStream_t* bitD, const void* srcBuffer, size_t srcSize)
5580c16b537SWarner Losh {
5590c16b537SWarner Losh     if (srcSize < 1) { memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); }
5600c16b537SWarner Losh 
5610c16b537SWarner Losh     if (srcSize >=  sizeof(bitD->bitContainer)) {  /* normal case */
5620c16b537SWarner Losh         bitD->start = (const char*)srcBuffer;
5630c16b537SWarner Losh         bitD->ptr   = (const char*)srcBuffer + srcSize - sizeof(bitD->bitContainer);
5640c16b537SWarner Losh         bitD->bitContainer = MEM_readLEST(bitD->ptr);
5650c16b537SWarner Losh         { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
5660c16b537SWarner Losh           bitD->bitsConsumed = lastByte ? 8 - BITv07_highbit32(lastByte) : 0;
5670c16b537SWarner Losh           if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ }
5680c16b537SWarner Losh     } else {
5690c16b537SWarner Losh         bitD->start = (const char*)srcBuffer;
5700c16b537SWarner Losh         bitD->ptr   = bitD->start;
5710c16b537SWarner Losh         bitD->bitContainer = *(const BYTE*)(bitD->start);
5720c16b537SWarner Losh         switch(srcSize)
5730c16b537SWarner Losh         {
5740c16b537SWarner Losh             case 7: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16);/* fall-through */
5750c16b537SWarner Losh             case 6: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24);/* fall-through */
5760c16b537SWarner Losh             case 5: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32);/* fall-through */
5770c16b537SWarner Losh             case 4: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[3]) << 24; /* fall-through */
5780c16b537SWarner Losh             case 3: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[2]) << 16; /* fall-through */
5790c16b537SWarner Losh             case 2: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[1]) <<  8; /* fall-through */
5800c16b537SWarner Losh             default: break;
5810c16b537SWarner Losh         }
5820c16b537SWarner Losh         { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
5830c16b537SWarner Losh           bitD->bitsConsumed = lastByte ? 8 - BITv07_highbit32(lastByte) : 0;
5840c16b537SWarner Losh           if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ }
5850c16b537SWarner Losh         bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize)*8;
5860c16b537SWarner Losh     }
5870c16b537SWarner Losh 
5880c16b537SWarner Losh     return srcSize;
5890c16b537SWarner Losh }
5900c16b537SWarner Losh 
5910c16b537SWarner Losh 
BITv07_lookBits(const BITv07_DStream_t * bitD,U32 nbBits)5920c16b537SWarner Losh  MEM_STATIC size_t BITv07_lookBits(const BITv07_DStream_t* bitD, U32 nbBits)
5930c16b537SWarner Losh {
5940c16b537SWarner Losh     U32 const bitMask = sizeof(bitD->bitContainer)*8 - 1;
5950c16b537SWarner Losh     return ((bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> 1) >> ((bitMask-nbBits) & bitMask);
5960c16b537SWarner Losh }
5970c16b537SWarner Losh 
5980c16b537SWarner Losh /*! BITv07_lookBitsFast() :
5990c16b537SWarner Losh *   unsafe version; only works only if nbBits >= 1 */
BITv07_lookBitsFast(const BITv07_DStream_t * bitD,U32 nbBits)6000c16b537SWarner Losh MEM_STATIC size_t BITv07_lookBitsFast(const BITv07_DStream_t* bitD, U32 nbBits)
6010c16b537SWarner Losh {
6020c16b537SWarner Losh     U32 const bitMask = sizeof(bitD->bitContainer)*8 - 1;
6030c16b537SWarner Losh     return (bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> (((bitMask+1)-nbBits) & bitMask);
6040c16b537SWarner Losh }
6050c16b537SWarner Losh 
BITv07_skipBits(BITv07_DStream_t * bitD,U32 nbBits)6060c16b537SWarner Losh MEM_STATIC void BITv07_skipBits(BITv07_DStream_t* bitD, U32 nbBits)
6070c16b537SWarner Losh {
6080c16b537SWarner Losh     bitD->bitsConsumed += nbBits;
6090c16b537SWarner Losh }
6100c16b537SWarner Losh 
BITv07_readBits(BITv07_DStream_t * bitD,U32 nbBits)6110c16b537SWarner Losh MEM_STATIC size_t BITv07_readBits(BITv07_DStream_t* bitD, U32 nbBits)
6120c16b537SWarner Losh {
6130c16b537SWarner Losh     size_t const value = BITv07_lookBits(bitD, nbBits);
6140c16b537SWarner Losh     BITv07_skipBits(bitD, nbBits);
6150c16b537SWarner Losh     return value;
6160c16b537SWarner Losh }
6170c16b537SWarner Losh 
6180c16b537SWarner Losh /*! BITv07_readBitsFast() :
6190c16b537SWarner Losh *   unsafe version; only works only if nbBits >= 1 */
BITv07_readBitsFast(BITv07_DStream_t * bitD,U32 nbBits)6200c16b537SWarner Losh MEM_STATIC size_t BITv07_readBitsFast(BITv07_DStream_t* bitD, U32 nbBits)
6210c16b537SWarner Losh {
6220c16b537SWarner Losh     size_t const value = BITv07_lookBitsFast(bitD, nbBits);
6230c16b537SWarner Losh     BITv07_skipBits(bitD, nbBits);
6240c16b537SWarner Losh     return value;
6250c16b537SWarner Losh }
6260c16b537SWarner Losh 
BITv07_reloadDStream(BITv07_DStream_t * bitD)6270c16b537SWarner Losh MEM_STATIC BITv07_DStream_status BITv07_reloadDStream(BITv07_DStream_t* bitD)
6280c16b537SWarner Losh {
6290c16b537SWarner Losh     if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8))  /* should not happen => corruption detected */
6300c16b537SWarner Losh         return BITv07_DStream_overflow;
6310c16b537SWarner Losh 
6320c16b537SWarner Losh     if (bitD->ptr >= bitD->start + sizeof(bitD->bitContainer)) {
6330c16b537SWarner Losh         bitD->ptr -= bitD->bitsConsumed >> 3;
6340c16b537SWarner Losh         bitD->bitsConsumed &= 7;
6350c16b537SWarner Losh         bitD->bitContainer = MEM_readLEST(bitD->ptr);
6360c16b537SWarner Losh         return BITv07_DStream_unfinished;
6370c16b537SWarner Losh     }
6380c16b537SWarner Losh     if (bitD->ptr == bitD->start) {
6390c16b537SWarner Losh         if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BITv07_DStream_endOfBuffer;
6400c16b537SWarner Losh         return BITv07_DStream_completed;
6410c16b537SWarner Losh     }
6420c16b537SWarner Losh     {   U32 nbBytes = bitD->bitsConsumed >> 3;
6430c16b537SWarner Losh         BITv07_DStream_status result = BITv07_DStream_unfinished;
6440c16b537SWarner Losh         if (bitD->ptr - nbBytes < bitD->start) {
6450c16b537SWarner Losh             nbBytes = (U32)(bitD->ptr - bitD->start);  /* ptr > start */
6460c16b537SWarner Losh             result = BITv07_DStream_endOfBuffer;
6470c16b537SWarner Losh         }
6480c16b537SWarner Losh         bitD->ptr -= nbBytes;
6490c16b537SWarner Losh         bitD->bitsConsumed -= nbBytes*8;
6500c16b537SWarner Losh         bitD->bitContainer = MEM_readLEST(bitD->ptr);   /* reminder : srcSize > sizeof(bitD) */
6510c16b537SWarner Losh         return result;
6520c16b537SWarner Losh     }
6530c16b537SWarner Losh }
6540c16b537SWarner Losh 
6550c16b537SWarner Losh /*! BITv07_endOfDStream() :
6560c16b537SWarner Losh *   @return Tells if DStream has exactly reached its end (all bits consumed).
6570c16b537SWarner Losh */
BITv07_endOfDStream(const BITv07_DStream_t * DStream)6580c16b537SWarner Losh MEM_STATIC unsigned BITv07_endOfDStream(const BITv07_DStream_t* DStream)
6590c16b537SWarner Losh {
6600c16b537SWarner Losh     return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer)*8));
6610c16b537SWarner Losh }
6620c16b537SWarner Losh 
6630c16b537SWarner Losh #if defined (__cplusplus)
6640c16b537SWarner Losh }
6650c16b537SWarner Losh #endif
6660c16b537SWarner Losh 
6670c16b537SWarner Losh #endif /* BITSTREAM_H_MODULE */
6680c16b537SWarner Losh /* ******************************************************************
6690c16b537SWarner Losh    FSE : Finite State Entropy codec
6700c16b537SWarner Losh    Public Prototypes declaration
6710c16b537SWarner Losh    Copyright (C) 2013-2016, Yann Collet.
6720c16b537SWarner Losh 
6730c16b537SWarner Losh    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6740c16b537SWarner Losh 
6750c16b537SWarner Losh    Redistribution and use in source and binary forms, with or without
6760c16b537SWarner Losh    modification, are permitted provided that the following conditions are
6770c16b537SWarner Losh    met:
6780c16b537SWarner Losh 
6790c16b537SWarner Losh        * Redistributions of source code must retain the above copyright
6800c16b537SWarner Losh    notice, this list of conditions and the following disclaimer.
6810c16b537SWarner Losh        * Redistributions in binary form must reproduce the above
6820c16b537SWarner Losh    copyright notice, this list of conditions and the following disclaimer
6830c16b537SWarner Losh    in the documentation and/or other materials provided with the
6840c16b537SWarner Losh    distribution.
6850c16b537SWarner Losh 
6860c16b537SWarner Losh    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
6870c16b537SWarner Losh    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
6880c16b537SWarner Losh    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6890c16b537SWarner Losh    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
6900c16b537SWarner Losh    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
6910c16b537SWarner Losh    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
6920c16b537SWarner Losh    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
6930c16b537SWarner Losh    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
6940c16b537SWarner Losh    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
6950c16b537SWarner Losh    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
6960c16b537SWarner Losh    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
6970c16b537SWarner Losh 
6980c16b537SWarner Losh    You can contact the author at :
6990c16b537SWarner Losh    - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
7000c16b537SWarner Losh ****************************************************************** */
7010c16b537SWarner Losh #ifndef FSEv07_H
7020c16b537SWarner Losh #define FSEv07_H
7030c16b537SWarner Losh 
7040c16b537SWarner Losh #if defined (__cplusplus)
7050c16b537SWarner Losh extern "C" {
7060c16b537SWarner Losh #endif
7070c16b537SWarner Losh 
7080c16b537SWarner Losh 
7090c16b537SWarner Losh 
7100c16b537SWarner Losh /*-****************************************
7110c16b537SWarner Losh *  FSE simple functions
7120c16b537SWarner Losh ******************************************/
7130c16b537SWarner Losh 
7140c16b537SWarner Losh /*! FSEv07_decompress():
7150c16b537SWarner Losh     Decompress FSE data from buffer 'cSrc', of size 'cSrcSize',
7160c16b537SWarner Losh     into already allocated destination buffer 'dst', of size 'dstCapacity'.
7170c16b537SWarner Losh     @return : size of regenerated data (<= maxDstSize),
7180c16b537SWarner Losh               or an error code, which can be tested using FSEv07_isError() .
7190c16b537SWarner Losh 
7200c16b537SWarner Losh     ** Important ** : FSEv07_decompress() does not decompress non-compressible nor RLE data !!!
7210c16b537SWarner Losh     Why ? : making this distinction requires a header.
7220c16b537SWarner Losh     Header management is intentionally delegated to the user layer, which can better manage special cases.
7230c16b537SWarner Losh */
7240c16b537SWarner Losh size_t FSEv07_decompress(void* dst,  size_t dstCapacity,
7250c16b537SWarner Losh                 const void* cSrc, size_t cSrcSize);
7260c16b537SWarner Losh 
7270c16b537SWarner Losh 
7280c16b537SWarner Losh /* Error Management */
7290c16b537SWarner Losh unsigned    FSEv07_isError(size_t code);        /* tells if a return value is an error code */
7300c16b537SWarner Losh const char* FSEv07_getErrorName(size_t code);   /* provides error code string (useful for debugging) */
7310c16b537SWarner Losh 
7320c16b537SWarner Losh 
7330c16b537SWarner Losh /*-*****************************************
7340c16b537SWarner Losh *  FSE detailed API
7350c16b537SWarner Losh ******************************************/
7360c16b537SWarner Losh /*!
7370c16b537SWarner Losh FSEv07_decompress() does the following:
7380c16b537SWarner Losh 1. read normalized counters with readNCount()
7390c16b537SWarner Losh 2. build decoding table 'DTable' from normalized counters
7400c16b537SWarner Losh 3. decode the data stream using decoding table 'DTable'
7410c16b537SWarner Losh 
7420c16b537SWarner Losh The following API allows targeting specific sub-functions for advanced tasks.
7430c16b537SWarner Losh For example, it's possible to compress several blocks using the same 'CTable',
7440c16b537SWarner Losh or to save and provide normalized distribution using external method.
7450c16b537SWarner Losh */
7460c16b537SWarner Losh 
7470c16b537SWarner Losh 
7480c16b537SWarner Losh /* *** DECOMPRESSION *** */
7490c16b537SWarner Losh 
7500c16b537SWarner Losh /*! FSEv07_readNCount():
7510c16b537SWarner Losh     Read compactly saved 'normalizedCounter' from 'rBuffer'.
7520c16b537SWarner Losh     @return : size read from 'rBuffer',
7530c16b537SWarner Losh               or an errorCode, which can be tested using FSEv07_isError().
7540c16b537SWarner Losh               maxSymbolValuePtr[0] and tableLogPtr[0] will also be updated with their respective values */
7550c16b537SWarner Losh size_t FSEv07_readNCount (short* normalizedCounter, unsigned* maxSymbolValuePtr, unsigned* tableLogPtr, const void* rBuffer, size_t rBuffSize);
7560c16b537SWarner Losh 
7570c16b537SWarner Losh /*! Constructor and Destructor of FSEv07_DTable.
7580c16b537SWarner Losh     Note that its size depends on 'tableLog' */
7590c16b537SWarner Losh typedef unsigned FSEv07_DTable;   /* don't allocate that. It's just a way to be more restrictive than void* */
7600c16b537SWarner Losh FSEv07_DTable* FSEv07_createDTable(unsigned tableLog);
7610c16b537SWarner Losh void        FSEv07_freeDTable(FSEv07_DTable* dt);
7620c16b537SWarner Losh 
7630c16b537SWarner Losh /*! FSEv07_buildDTable():
7640c16b537SWarner Losh     Builds 'dt', which must be already allocated, using FSEv07_createDTable().
7650c16b537SWarner Losh     return : 0, or an errorCode, which can be tested using FSEv07_isError() */
7660c16b537SWarner Losh size_t FSEv07_buildDTable (FSEv07_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);
7670c16b537SWarner Losh 
7680c16b537SWarner Losh /*! FSEv07_decompress_usingDTable():
7690c16b537SWarner Losh     Decompress compressed source `cSrc` of size `cSrcSize` using `dt`
7700c16b537SWarner Losh     into `dst` which must be already allocated.
7710c16b537SWarner Losh     @return : size of regenerated data (necessarily <= `dstCapacity`),
7720c16b537SWarner Losh               or an errorCode, which can be tested using FSEv07_isError() */
7730c16b537SWarner Losh size_t FSEv07_decompress_usingDTable(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, const FSEv07_DTable* dt);
7740c16b537SWarner Losh 
7750c16b537SWarner Losh /*!
7760c16b537SWarner Losh Tutorial :
7770c16b537SWarner Losh ----------
7780c16b537SWarner Losh (Note : these functions only decompress FSE-compressed blocks.
7790c16b537SWarner Losh  If block is uncompressed, use memcpy() instead
7800c16b537SWarner Losh  If block is a single repeated byte, use memset() instead )
7810c16b537SWarner Losh 
7820c16b537SWarner Losh The first step is to obtain the normalized frequencies of symbols.
7830c16b537SWarner Losh This can be performed by FSEv07_readNCount() if it was saved using FSEv07_writeNCount().
7840c16b537SWarner Losh 'normalizedCounter' must be already allocated, and have at least 'maxSymbolValuePtr[0]+1' cells of signed short.
7850c16b537SWarner Losh In practice, that means it's necessary to know 'maxSymbolValue' beforehand,
7860c16b537SWarner Losh or size the table to handle worst case situations (typically 256).
7870c16b537SWarner Losh FSEv07_readNCount() will provide 'tableLog' and 'maxSymbolValue'.
7880c16b537SWarner Losh The result of FSEv07_readNCount() is the number of bytes read from 'rBuffer'.
7890c16b537SWarner Losh Note that 'rBufferSize' must be at least 4 bytes, even if useful information is less than that.
7900c16b537SWarner Losh If there is an error, the function will return an error code, which can be tested using FSEv07_isError().
7910c16b537SWarner Losh 
7920c16b537SWarner Losh The next step is to build the decompression tables 'FSEv07_DTable' from 'normalizedCounter'.
7930c16b537SWarner Losh This is performed by the function FSEv07_buildDTable().
7940c16b537SWarner Losh The space required by 'FSEv07_DTable' must be already allocated using FSEv07_createDTable().
7950c16b537SWarner Losh If there is an error, the function will return an error code, which can be tested using FSEv07_isError().
7960c16b537SWarner Losh 
7970c16b537SWarner Losh `FSEv07_DTable` can then be used to decompress `cSrc`, with FSEv07_decompress_usingDTable().
7980c16b537SWarner Losh `cSrcSize` must be strictly correct, otherwise decompression will fail.
7990c16b537SWarner Losh FSEv07_decompress_usingDTable() result will tell how many bytes were regenerated (<=`dstCapacity`).
8000c16b537SWarner Losh If there is an error, the function will return an error code, which can be tested using FSEv07_isError(). (ex: dst buffer too small)
8010c16b537SWarner Losh */
8020c16b537SWarner Losh 
8030c16b537SWarner Losh 
8040c16b537SWarner Losh #ifdef FSEv07_STATIC_LINKING_ONLY
8050c16b537SWarner Losh 
8060c16b537SWarner Losh 
8070c16b537SWarner Losh /* *****************************************
8080c16b537SWarner Losh *  Static allocation
8090c16b537SWarner Losh *******************************************/
8100c16b537SWarner Losh /* FSE buffer bounds */
8110c16b537SWarner Losh #define FSEv07_NCOUNTBOUND 512
8120c16b537SWarner Losh #define FSEv07_BLOCKBOUND(size) (size + (size>>7))
8130c16b537SWarner Losh 
8140c16b537SWarner Losh /* It is possible to statically allocate FSE CTable/DTable as a table of unsigned using below macros */
8150c16b537SWarner Losh #define FSEv07_DTABLE_SIZE_U32(maxTableLog)                   (1 + (1<<maxTableLog))
8160c16b537SWarner Losh 
8170c16b537SWarner Losh 
8180c16b537SWarner Losh /* *****************************************
8190c16b537SWarner Losh *  FSE advanced API
8200c16b537SWarner Losh *******************************************/
8210c16b537SWarner Losh size_t FSEv07_countFast(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize);
8220c16b537SWarner Losh /**< same as FSEv07_count(), but blindly trusts that all byte values within src are <= *maxSymbolValuePtr  */
8230c16b537SWarner Losh 
8240c16b537SWarner Losh unsigned FSEv07_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus);
8250c16b537SWarner Losh /**< same as FSEv07_optimalTableLog(), which used `minus==2` */
8260c16b537SWarner Losh 
8270c16b537SWarner Losh size_t FSEv07_buildDTable_raw (FSEv07_DTable* dt, unsigned nbBits);
8280c16b537SWarner Losh /**< build a fake FSEv07_DTable, designed to read an uncompressed bitstream where each symbol uses nbBits */
8290c16b537SWarner Losh 
8300c16b537SWarner Losh size_t FSEv07_buildDTable_rle (FSEv07_DTable* dt, unsigned char symbolValue);
8310c16b537SWarner Losh /**< build a fake FSEv07_DTable, designed to always generate the same symbolValue */
8320c16b537SWarner Losh 
8330c16b537SWarner Losh 
8340c16b537SWarner Losh 
8350c16b537SWarner Losh /* *****************************************
8360c16b537SWarner Losh *  FSE symbol decompression API
8370c16b537SWarner Losh *******************************************/
8380c16b537SWarner Losh typedef struct
8390c16b537SWarner Losh {
8400c16b537SWarner Losh     size_t      state;
8410c16b537SWarner Losh     const void* table;   /* precise table may vary, depending on U16 */
8420c16b537SWarner Losh } FSEv07_DState_t;
8430c16b537SWarner Losh 
8440c16b537SWarner Losh 
8450c16b537SWarner Losh static void     FSEv07_initDState(FSEv07_DState_t* DStatePtr, BITv07_DStream_t* bitD, const FSEv07_DTable* dt);
8460c16b537SWarner Losh 
8470c16b537SWarner Losh static unsigned char FSEv07_decodeSymbol(FSEv07_DState_t* DStatePtr, BITv07_DStream_t* bitD);
8480c16b537SWarner Losh 
8490c16b537SWarner Losh 
8500c16b537SWarner Losh 
8510c16b537SWarner Losh /* *****************************************
8520c16b537SWarner Losh *  FSE unsafe API
8530c16b537SWarner Losh *******************************************/
8540c16b537SWarner Losh static unsigned char FSEv07_decodeSymbolFast(FSEv07_DState_t* DStatePtr, BITv07_DStream_t* bitD);
8550c16b537SWarner Losh /* faster, but works only if nbBits is always >= 1 (otherwise, result will be corrupted) */
8560c16b537SWarner Losh 
8570c16b537SWarner Losh 
8580c16b537SWarner Losh /* ======    Decompression    ====== */
8590c16b537SWarner Losh 
8600c16b537SWarner Losh typedef struct {
8610c16b537SWarner Losh     U16 tableLog;
8620c16b537SWarner Losh     U16 fastMode;
8630c16b537SWarner Losh } FSEv07_DTableHeader;   /* sizeof U32 */
8640c16b537SWarner Losh 
8650c16b537SWarner Losh typedef struct
8660c16b537SWarner Losh {
8670c16b537SWarner Losh     unsigned short newState;
8680c16b537SWarner Losh     unsigned char  symbol;
8690c16b537SWarner Losh     unsigned char  nbBits;
8700c16b537SWarner Losh } FSEv07_decode_t;   /* size == U32 */
8710c16b537SWarner Losh 
FSEv07_initDState(FSEv07_DState_t * DStatePtr,BITv07_DStream_t * bitD,const FSEv07_DTable * dt)8720c16b537SWarner Losh MEM_STATIC void FSEv07_initDState(FSEv07_DState_t* DStatePtr, BITv07_DStream_t* bitD, const FSEv07_DTable* dt)
8730c16b537SWarner Losh {
8740c16b537SWarner Losh     const void* ptr = dt;
8750c16b537SWarner Losh     const FSEv07_DTableHeader* const DTableH = (const FSEv07_DTableHeader*)ptr;
8760c16b537SWarner Losh     DStatePtr->state = BITv07_readBits(bitD, DTableH->tableLog);
8770c16b537SWarner Losh     BITv07_reloadDStream(bitD);
8780c16b537SWarner Losh     DStatePtr->table = dt + 1;
8790c16b537SWarner Losh }
8800c16b537SWarner Losh 
FSEv07_peekSymbol(const FSEv07_DState_t * DStatePtr)8810c16b537SWarner Losh MEM_STATIC BYTE FSEv07_peekSymbol(const FSEv07_DState_t* DStatePtr)
8820c16b537SWarner Losh {
8830c16b537SWarner Losh     FSEv07_decode_t const DInfo = ((const FSEv07_decode_t*)(DStatePtr->table))[DStatePtr->state];
8840c16b537SWarner Losh     return DInfo.symbol;
8850c16b537SWarner Losh }
8860c16b537SWarner Losh 
FSEv07_updateState(FSEv07_DState_t * DStatePtr,BITv07_DStream_t * bitD)8870c16b537SWarner Losh MEM_STATIC void FSEv07_updateState(FSEv07_DState_t* DStatePtr, BITv07_DStream_t* bitD)
8880c16b537SWarner Losh {
8890c16b537SWarner Losh     FSEv07_decode_t const DInfo = ((const FSEv07_decode_t*)(DStatePtr->table))[DStatePtr->state];
8900c16b537SWarner Losh     U32 const nbBits = DInfo.nbBits;
8910c16b537SWarner Losh     size_t const lowBits = BITv07_readBits(bitD, nbBits);
8920c16b537SWarner Losh     DStatePtr->state = DInfo.newState + lowBits;
8930c16b537SWarner Losh }
8940c16b537SWarner Losh 
FSEv07_decodeSymbol(FSEv07_DState_t * DStatePtr,BITv07_DStream_t * bitD)8950c16b537SWarner Losh MEM_STATIC BYTE FSEv07_decodeSymbol(FSEv07_DState_t* DStatePtr, BITv07_DStream_t* bitD)
8960c16b537SWarner Losh {
8970c16b537SWarner Losh     FSEv07_decode_t const DInfo = ((const FSEv07_decode_t*)(DStatePtr->table))[DStatePtr->state];
8980c16b537SWarner Losh     U32 const nbBits = DInfo.nbBits;
8990c16b537SWarner Losh     BYTE const symbol = DInfo.symbol;
9000c16b537SWarner Losh     size_t const lowBits = BITv07_readBits(bitD, nbBits);
9010c16b537SWarner Losh 
9020c16b537SWarner Losh     DStatePtr->state = DInfo.newState + lowBits;
9030c16b537SWarner Losh     return symbol;
9040c16b537SWarner Losh }
9050c16b537SWarner Losh 
9060c16b537SWarner Losh /*! FSEv07_decodeSymbolFast() :
9070c16b537SWarner Losh     unsafe, only works if no symbol has a probability > 50% */
FSEv07_decodeSymbolFast(FSEv07_DState_t * DStatePtr,BITv07_DStream_t * bitD)9080c16b537SWarner Losh MEM_STATIC BYTE FSEv07_decodeSymbolFast(FSEv07_DState_t* DStatePtr, BITv07_DStream_t* bitD)
9090c16b537SWarner Losh {
9100c16b537SWarner Losh     FSEv07_decode_t const DInfo = ((const FSEv07_decode_t*)(DStatePtr->table))[DStatePtr->state];
9110c16b537SWarner Losh     U32 const nbBits = DInfo.nbBits;
9120c16b537SWarner Losh     BYTE const symbol = DInfo.symbol;
9130c16b537SWarner Losh     size_t const lowBits = BITv07_readBitsFast(bitD, nbBits);
9140c16b537SWarner Losh 
9150c16b537SWarner Losh     DStatePtr->state = DInfo.newState + lowBits;
9160c16b537SWarner Losh     return symbol;
9170c16b537SWarner Losh }
9180c16b537SWarner Losh 
9190c16b537SWarner Losh 
9200c16b537SWarner Losh 
9210c16b537SWarner Losh #ifndef FSEv07_COMMONDEFS_ONLY
9220c16b537SWarner Losh 
9230c16b537SWarner Losh /* **************************************************************
9240c16b537SWarner Losh *  Tuning parameters
9250c16b537SWarner Losh ****************************************************************/
9260c16b537SWarner Losh /*!MEMORY_USAGE :
9270c16b537SWarner Losh *  Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
9280c16b537SWarner Losh *  Increasing memory usage improves compression ratio
9290c16b537SWarner Losh *  Reduced memory usage can improve speed, due to cache effect
9300c16b537SWarner Losh *  Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */
9310c16b537SWarner Losh #define FSEv07_MAX_MEMORY_USAGE 14
9320c16b537SWarner Losh #define FSEv07_DEFAULT_MEMORY_USAGE 13
9330c16b537SWarner Losh 
9340c16b537SWarner Losh /*!FSEv07_MAX_SYMBOL_VALUE :
9350c16b537SWarner Losh *  Maximum symbol value authorized.
9360c16b537SWarner Losh *  Required for proper stack allocation */
9370c16b537SWarner Losh #define FSEv07_MAX_SYMBOL_VALUE 255
9380c16b537SWarner Losh 
9390c16b537SWarner Losh 
9400c16b537SWarner Losh /* **************************************************************
9410c16b537SWarner Losh *  template functions type & suffix
9420c16b537SWarner Losh ****************************************************************/
9430c16b537SWarner Losh #define FSEv07_FUNCTION_TYPE BYTE
9440c16b537SWarner Losh #define FSEv07_FUNCTION_EXTENSION
9450c16b537SWarner Losh #define FSEv07_DECODE_TYPE FSEv07_decode_t
9460c16b537SWarner Losh 
9470c16b537SWarner Losh 
9480c16b537SWarner Losh #endif   /* !FSEv07_COMMONDEFS_ONLY */
9490c16b537SWarner Losh 
9500c16b537SWarner Losh 
9510c16b537SWarner Losh /* ***************************************************************
9520c16b537SWarner Losh *  Constants
9530c16b537SWarner Losh *****************************************************************/
9540c16b537SWarner Losh #define FSEv07_MAX_TABLELOG  (FSEv07_MAX_MEMORY_USAGE-2)
9550c16b537SWarner Losh #define FSEv07_MAX_TABLESIZE (1U<<FSEv07_MAX_TABLELOG)
9560c16b537SWarner Losh #define FSEv07_MAXTABLESIZE_MASK (FSEv07_MAX_TABLESIZE-1)
9570c16b537SWarner Losh #define FSEv07_DEFAULT_TABLELOG (FSEv07_DEFAULT_MEMORY_USAGE-2)
9580c16b537SWarner Losh #define FSEv07_MIN_TABLELOG 5
9590c16b537SWarner Losh 
9600c16b537SWarner Losh #define FSEv07_TABLELOG_ABSOLUTE_MAX 15
9610c16b537SWarner Losh #if FSEv07_MAX_TABLELOG > FSEv07_TABLELOG_ABSOLUTE_MAX
9620c16b537SWarner Losh #  error "FSEv07_MAX_TABLELOG > FSEv07_TABLELOG_ABSOLUTE_MAX is not supported"
9630c16b537SWarner Losh #endif
9640c16b537SWarner Losh 
9650c16b537SWarner Losh #define FSEv07_TABLESTEP(tableSize) ((tableSize>>1) + (tableSize>>3) + 3)
9660c16b537SWarner Losh 
9670c16b537SWarner Losh 
9680c16b537SWarner Losh #endif /* FSEv07_STATIC_LINKING_ONLY */
9690c16b537SWarner Losh 
9700c16b537SWarner Losh 
9710c16b537SWarner Losh #if defined (__cplusplus)
9720c16b537SWarner Losh }
9730c16b537SWarner Losh #endif
9740c16b537SWarner Losh 
9750c16b537SWarner Losh #endif  /* FSEv07_H */
9760c16b537SWarner Losh /* ******************************************************************
9770c16b537SWarner Losh    Huffman coder, part of New Generation Entropy library
9780c16b537SWarner Losh    header file
9790c16b537SWarner Losh    Copyright (C) 2013-2016, Yann Collet.
9800c16b537SWarner Losh 
9810c16b537SWarner Losh    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
9820c16b537SWarner Losh 
9830c16b537SWarner Losh    Redistribution and use in source and binary forms, with or without
9840c16b537SWarner Losh    modification, are permitted provided that the following conditions are
9850c16b537SWarner Losh    met:
9860c16b537SWarner Losh 
9870c16b537SWarner Losh        * Redistributions of source code must retain the above copyright
9880c16b537SWarner Losh    notice, this list of conditions and the following disclaimer.
9890c16b537SWarner Losh        * Redistributions in binary form must reproduce the above
9900c16b537SWarner Losh    copyright notice, this list of conditions and the following disclaimer
9910c16b537SWarner Losh    in the documentation and/or other materials provided with the
9920c16b537SWarner Losh    distribution.
9930c16b537SWarner Losh 
9940c16b537SWarner Losh    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
9950c16b537SWarner Losh    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
9960c16b537SWarner Losh    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
9970c16b537SWarner Losh    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
9980c16b537SWarner Losh    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
9990c16b537SWarner Losh    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
10000c16b537SWarner Losh    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10010c16b537SWarner Losh    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
10020c16b537SWarner Losh    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
10030c16b537SWarner Losh    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
10040c16b537SWarner Losh    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
10050c16b537SWarner Losh 
10060c16b537SWarner Losh    You can contact the author at :
10070c16b537SWarner Losh    - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
10080c16b537SWarner Losh ****************************************************************** */
10090c16b537SWarner Losh #ifndef HUFv07_H_298734234
10100c16b537SWarner Losh #define HUFv07_H_298734234
10110c16b537SWarner Losh 
10120c16b537SWarner Losh #if defined (__cplusplus)
10130c16b537SWarner Losh extern "C" {
10140c16b537SWarner Losh #endif
10150c16b537SWarner Losh 
10160c16b537SWarner Losh 
10170c16b537SWarner Losh 
10180c16b537SWarner Losh /* *** simple functions *** */
10190c16b537SWarner Losh /**
10200c16b537SWarner Losh HUFv07_decompress() :
10210c16b537SWarner Losh     Decompress HUF data from buffer 'cSrc', of size 'cSrcSize',
10220c16b537SWarner Losh     into already allocated buffer 'dst', of minimum size 'dstSize'.
10230c16b537SWarner Losh     `dstSize` : **must** be the ***exact*** size of original (uncompressed) data.
10240c16b537SWarner Losh     Note : in contrast with FSE, HUFv07_decompress can regenerate
10250c16b537SWarner Losh            RLE (cSrcSize==1) and uncompressed (cSrcSize==dstSize) data,
10260c16b537SWarner Losh            because it knows size to regenerate.
10270c16b537SWarner Losh     @return : size of regenerated data (== dstSize),
10280c16b537SWarner Losh               or an error code, which can be tested using HUFv07_isError()
10290c16b537SWarner Losh */
10300c16b537SWarner Losh size_t HUFv07_decompress(void* dst,  size_t dstSize,
10310c16b537SWarner Losh                 const void* cSrc, size_t cSrcSize);
10320c16b537SWarner Losh 
10330c16b537SWarner Losh 
10340c16b537SWarner Losh /* ****************************************
10350c16b537SWarner Losh *  Tool functions
10360c16b537SWarner Losh ******************************************/
10370c16b537SWarner Losh #define HUFv07_BLOCKSIZE_MAX (128 * 1024)
10380c16b537SWarner Losh 
10390c16b537SWarner Losh /* Error Management */
10400c16b537SWarner Losh unsigned    HUFv07_isError(size_t code);        /**< tells if a return value is an error code */
10410c16b537SWarner Losh const char* HUFv07_getErrorName(size_t code);   /**< provides error code string (useful for debugging) */
10420c16b537SWarner Losh 
10430c16b537SWarner Losh 
10440c16b537SWarner Losh /* *** Advanced function *** */
10450c16b537SWarner Losh 
10460c16b537SWarner Losh 
10470c16b537SWarner Losh #ifdef HUFv07_STATIC_LINKING_ONLY
10480c16b537SWarner Losh 
10490c16b537SWarner Losh 
10500c16b537SWarner Losh /* *** Constants *** */
10510c16b537SWarner Losh #define HUFv07_TABLELOG_ABSOLUTEMAX  16   /* absolute limit of HUFv07_MAX_TABLELOG. Beyond that value, code does not work */
10520c16b537SWarner Losh #define HUFv07_TABLELOG_MAX  12           /* max configured tableLog (for static allocation); can be modified up to HUFv07_ABSOLUTEMAX_TABLELOG */
10530c16b537SWarner Losh #define HUFv07_TABLELOG_DEFAULT  11       /* tableLog by default, when not specified */
10540c16b537SWarner Losh #define HUFv07_SYMBOLVALUE_MAX 255
10550c16b537SWarner Losh #if (HUFv07_TABLELOG_MAX > HUFv07_TABLELOG_ABSOLUTEMAX)
10560c16b537SWarner Losh #  error "HUFv07_TABLELOG_MAX is too large !"
10570c16b537SWarner Losh #endif
10580c16b537SWarner Losh 
10590c16b537SWarner Losh 
10600c16b537SWarner Losh /* ****************************************
10610c16b537SWarner Losh *  Static allocation
10620c16b537SWarner Losh ******************************************/
10630c16b537SWarner Losh /* HUF buffer bounds */
10640c16b537SWarner Losh #define HUFv07_BLOCKBOUND(size) (size + (size>>8) + 8)   /* only true if incompressible pre-filtered with fast heuristic */
10650c16b537SWarner Losh 
10660c16b537SWarner Losh /* static allocation of HUF's DTable */
10670c16b537SWarner Losh typedef U32 HUFv07_DTable;
10680c16b537SWarner Losh #define HUFv07_DTABLE_SIZE(maxTableLog)   (1 + (1<<(maxTableLog)))
10690c16b537SWarner Losh #define HUFv07_CREATE_STATIC_DTABLEX2(DTable, maxTableLog) \
10700c16b537SWarner Losh         HUFv07_DTable DTable[HUFv07_DTABLE_SIZE((maxTableLog)-1)] = { ((U32)((maxTableLog)-1)*0x1000001) }
10710c16b537SWarner Losh #define HUFv07_CREATE_STATIC_DTABLEX4(DTable, maxTableLog) \
10720c16b537SWarner Losh         HUFv07_DTable DTable[HUFv07_DTABLE_SIZE(maxTableLog)] = { ((U32)(maxTableLog)*0x1000001) }
10730c16b537SWarner Losh 
10740c16b537SWarner Losh 
10750c16b537SWarner Losh /* ****************************************
10760c16b537SWarner Losh *  Advanced decompression functions
10770c16b537SWarner Losh ******************************************/
10780c16b537SWarner Losh size_t HUFv07_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /**< single-symbol decoder */
10790c16b537SWarner Losh size_t HUFv07_decompress4X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /**< double-symbols decoder */
10800c16b537SWarner Losh 
10810c16b537SWarner Losh size_t HUFv07_decompress4X_DCtx (HUFv07_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /**< decodes RLE and uncompressed */
10820c16b537SWarner Losh size_t HUFv07_decompress4X_hufOnly(HUFv07_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< considers RLE and uncompressed as errors */
10830c16b537SWarner Losh size_t HUFv07_decompress4X2_DCtx(HUFv07_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /**< single-symbol decoder */
10840c16b537SWarner Losh size_t HUFv07_decompress4X4_DCtx(HUFv07_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /**< double-symbols decoder */
10850c16b537SWarner Losh 
10860c16b537SWarner Losh size_t HUFv07_decompress1X_DCtx (HUFv07_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);
10870c16b537SWarner Losh size_t HUFv07_decompress1X2_DCtx(HUFv07_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /**< single-symbol decoder */
10880c16b537SWarner Losh size_t HUFv07_decompress1X4_DCtx(HUFv07_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /**< double-symbols decoder */
10890c16b537SWarner Losh 
10900c16b537SWarner Losh 
10910c16b537SWarner Losh /* ****************************************
10920c16b537SWarner Losh *  HUF detailed API
10930c16b537SWarner Losh ******************************************/
10940c16b537SWarner Losh /*!
10950c16b537SWarner Losh The following API allows targeting specific sub-functions for advanced tasks.
10960c16b537SWarner Losh For example, it's possible to compress several blocks using the same 'CTable',
10970c16b537SWarner Losh or to save and regenerate 'CTable' using external methods.
10980c16b537SWarner Losh */
10990c16b537SWarner Losh /* FSEv07_count() : find it within "fse.h" */
11000c16b537SWarner Losh 
11010c16b537SWarner Losh /*! HUFv07_readStats() :
11020c16b537SWarner Losh     Read compact Huffman tree, saved by HUFv07_writeCTable().
11030c16b537SWarner Losh     `huffWeight` is destination buffer.
11040c16b537SWarner Losh     @return : size read from `src` , or an error Code .
11050c16b537SWarner Losh     Note : Needed by HUFv07_readCTable() and HUFv07_readDTableXn() . */
11060c16b537SWarner Losh size_t HUFv07_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats,
11070c16b537SWarner Losh                      U32* nbSymbolsPtr, U32* tableLogPtr,
11080c16b537SWarner Losh                      const void* src, size_t srcSize);
11090c16b537SWarner Losh 
11100c16b537SWarner Losh 
11110c16b537SWarner Losh /*
11120c16b537SWarner Losh HUFv07_decompress() does the following:
11130c16b537SWarner Losh 1. select the decompression algorithm (X2, X4) based on pre-computed heuristics
11140c16b537SWarner Losh 2. build Huffman table from save, using HUFv07_readDTableXn()
11150c16b537SWarner Losh 3. decode 1 or 4 segments in parallel using HUFv07_decompressSXn_usingDTable
11160c16b537SWarner Losh */
11170c16b537SWarner Losh 
11180c16b537SWarner Losh /** HUFv07_selectDecoder() :
11190c16b537SWarner Losh *   Tells which decoder is likely to decode faster,
11200c16b537SWarner Losh *   based on a set of pre-determined metrics.
11210c16b537SWarner Losh *   @return : 0==HUFv07_decompress4X2, 1==HUFv07_decompress4X4 .
11220c16b537SWarner Losh *   Assumption : 0 < cSrcSize < dstSize <= 128 KB */
11230c16b537SWarner Losh U32 HUFv07_selectDecoder (size_t dstSize, size_t cSrcSize);
11240c16b537SWarner Losh 
11250c16b537SWarner Losh size_t HUFv07_readDTableX2 (HUFv07_DTable* DTable, const void* src, size_t srcSize);
11260c16b537SWarner Losh size_t HUFv07_readDTableX4 (HUFv07_DTable* DTable, const void* src, size_t srcSize);
11270c16b537SWarner Losh 
11280c16b537SWarner Losh size_t HUFv07_decompress4X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUFv07_DTable* DTable);
11290c16b537SWarner Losh size_t HUFv07_decompress4X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUFv07_DTable* DTable);
11300c16b537SWarner Losh size_t HUFv07_decompress4X4_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUFv07_DTable* DTable);
11310c16b537SWarner Losh 
11320c16b537SWarner Losh 
11330c16b537SWarner Losh /* single stream variants */
11340c16b537SWarner Losh size_t HUFv07_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /* single-symbol decoder */
11350c16b537SWarner Losh size_t HUFv07_decompress1X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /* double-symbol decoder */
11360c16b537SWarner Losh 
11370c16b537SWarner Losh size_t HUFv07_decompress1X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUFv07_DTable* DTable);
11380c16b537SWarner Losh size_t HUFv07_decompress1X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUFv07_DTable* DTable);
11390c16b537SWarner Losh size_t HUFv07_decompress1X4_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUFv07_DTable* DTable);
11400c16b537SWarner Losh 
11410c16b537SWarner Losh 
11420c16b537SWarner Losh #endif /* HUFv07_STATIC_LINKING_ONLY */
11430c16b537SWarner Losh 
11440c16b537SWarner Losh 
11450c16b537SWarner Losh #if defined (__cplusplus)
11460c16b537SWarner Losh }
11470c16b537SWarner Losh #endif
11480c16b537SWarner Losh 
11490c16b537SWarner Losh #endif   /* HUFv07_H_298734234 */
11500c16b537SWarner Losh /*
11510c16b537SWarner Losh    Common functions of New Generation Entropy library
11520c16b537SWarner Losh    Copyright (C) 2016, Yann Collet.
11530c16b537SWarner Losh 
11540c16b537SWarner Losh    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
11550c16b537SWarner Losh 
11560c16b537SWarner Losh    Redistribution and use in source and binary forms, with or without
11570c16b537SWarner Losh    modification, are permitted provided that the following conditions are
11580c16b537SWarner Losh    met:
11590c16b537SWarner Losh 
11600c16b537SWarner Losh        * Redistributions of source code must retain the above copyright
11610c16b537SWarner Losh    notice, this list of conditions and the following disclaimer.
11620c16b537SWarner Losh        * Redistributions in binary form must reproduce the above
11630c16b537SWarner Losh    copyright notice, this list of conditions and the following disclaimer
11640c16b537SWarner Losh    in the documentation and/or other materials provided with the
11650c16b537SWarner Losh    distribution.
11660c16b537SWarner Losh 
11670c16b537SWarner Losh    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
11680c16b537SWarner Losh    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
11690c16b537SWarner Losh    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
11700c16b537SWarner Losh    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
11710c16b537SWarner Losh    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
11720c16b537SWarner Losh    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
11730c16b537SWarner Losh    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
11740c16b537SWarner Losh    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11750c16b537SWarner Losh    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
11760c16b537SWarner Losh    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
11770c16b537SWarner Losh    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
11780c16b537SWarner Losh 
11790c16b537SWarner Losh     You can contact the author at :
11800c16b537SWarner Losh     - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
11810c16b537SWarner Losh     - Public forum : https://groups.google.com/forum/#!forum/lz4c
11820c16b537SWarner Losh *************************************************************************** */
11830c16b537SWarner Losh 
11840c16b537SWarner Losh 
11850c16b537SWarner Losh 
11860c16b537SWarner Losh /*-****************************************
11870c16b537SWarner Losh *  FSE Error Management
11880c16b537SWarner Losh ******************************************/
FSEv07_isError(size_t code)11890c16b537SWarner Losh unsigned FSEv07_isError(size_t code) { return ERR_isError(code); }
11900c16b537SWarner Losh 
FSEv07_getErrorName(size_t code)11910c16b537SWarner Losh const char* FSEv07_getErrorName(size_t code) { return ERR_getErrorName(code); }
11920c16b537SWarner Losh 
11930c16b537SWarner Losh 
11940c16b537SWarner Losh /* **************************************************************
11950c16b537SWarner Losh *  HUF Error Management
11960c16b537SWarner Losh ****************************************************************/
HUFv07_isError(size_t code)11970c16b537SWarner Losh unsigned HUFv07_isError(size_t code) { return ERR_isError(code); }
11980c16b537SWarner Losh 
HUFv07_getErrorName(size_t code)11990c16b537SWarner Losh const char* HUFv07_getErrorName(size_t code) { return ERR_getErrorName(code); }
12000c16b537SWarner Losh 
12010c16b537SWarner Losh 
12020c16b537SWarner Losh /*-**************************************************************
12030c16b537SWarner Losh *  FSE NCount encoding-decoding
12040c16b537SWarner Losh ****************************************************************/
FSEv07_abs(short a)12050c16b537SWarner Losh static short FSEv07_abs(short a) { return (short)(a<0 ? -a : a); }
12060c16b537SWarner Losh 
FSEv07_readNCount(short * normalizedCounter,unsigned * maxSVPtr,unsigned * tableLogPtr,const void * headerBuffer,size_t hbSize)12070c16b537SWarner Losh size_t FSEv07_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
12080c16b537SWarner Losh                  const void* headerBuffer, size_t hbSize)
12090c16b537SWarner Losh {
12100c16b537SWarner Losh     const BYTE* const istart = (const BYTE*) headerBuffer;
12110c16b537SWarner Losh     const BYTE* const iend = istart + hbSize;
12120c16b537SWarner Losh     const BYTE* ip = istart;
12130c16b537SWarner Losh     int nbBits;
12140c16b537SWarner Losh     int remaining;
12150c16b537SWarner Losh     int threshold;
12160c16b537SWarner Losh     U32 bitStream;
12170c16b537SWarner Losh     int bitCount;
12180c16b537SWarner Losh     unsigned charnum = 0;
12190c16b537SWarner Losh     int previous0 = 0;
12200c16b537SWarner Losh 
12210c16b537SWarner Losh     if (hbSize < 4) return ERROR(srcSize_wrong);
12220c16b537SWarner Losh     bitStream = MEM_readLE32(ip);
12230c16b537SWarner Losh     nbBits = (bitStream & 0xF) + FSEv07_MIN_TABLELOG;   /* extract tableLog */
12240c16b537SWarner Losh     if (nbBits > FSEv07_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge);
12250c16b537SWarner Losh     bitStream >>= 4;
12260c16b537SWarner Losh     bitCount = 4;
12270c16b537SWarner Losh     *tableLogPtr = nbBits;
12280c16b537SWarner Losh     remaining = (1<<nbBits)+1;
12290c16b537SWarner Losh     threshold = 1<<nbBits;
12300c16b537SWarner Losh     nbBits++;
12310c16b537SWarner Losh 
12320c16b537SWarner Losh     while ((remaining>1) && (charnum<=*maxSVPtr)) {
12330c16b537SWarner Losh         if (previous0) {
12340c16b537SWarner Losh             unsigned n0 = charnum;
12350c16b537SWarner Losh             while ((bitStream & 0xFFFF) == 0xFFFF) {
12360c16b537SWarner Losh                 n0+=24;
12370c16b537SWarner Losh                 if (ip < iend-5) {
12380c16b537SWarner Losh                     ip+=2;
12390c16b537SWarner Losh                     bitStream = MEM_readLE32(ip) >> bitCount;
12400c16b537SWarner Losh                 } else {
12410c16b537SWarner Losh                     bitStream >>= 16;
12420c16b537SWarner Losh                     bitCount+=16;
12430c16b537SWarner Losh             }   }
12440c16b537SWarner Losh             while ((bitStream & 3) == 3) {
12450c16b537SWarner Losh                 n0+=3;
12460c16b537SWarner Losh                 bitStream>>=2;
12470c16b537SWarner Losh                 bitCount+=2;
12480c16b537SWarner Losh             }
12490c16b537SWarner Losh             n0 += bitStream & 3;
12500c16b537SWarner Losh             bitCount += 2;
12510c16b537SWarner Losh             if (n0 > *maxSVPtr) return ERROR(maxSymbolValue_tooSmall);
12520c16b537SWarner Losh             while (charnum < n0) normalizedCounter[charnum++] = 0;
12530c16b537SWarner Losh             if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
12540c16b537SWarner Losh                 ip += bitCount>>3;
12550c16b537SWarner Losh                 bitCount &= 7;
12560c16b537SWarner Losh                 bitStream = MEM_readLE32(ip) >> bitCount;
12570c16b537SWarner Losh             }
12580c16b537SWarner Losh             else
12590c16b537SWarner Losh                 bitStream >>= 2;
12600c16b537SWarner Losh         }
12610c16b537SWarner Losh         {   short const max = (short)((2*threshold-1)-remaining);
12620c16b537SWarner Losh             short count;
12630c16b537SWarner Losh 
12640c16b537SWarner Losh             if ((bitStream & (threshold-1)) < (U32)max) {
12650c16b537SWarner Losh                 count = (short)(bitStream & (threshold-1));
12660c16b537SWarner Losh                 bitCount   += nbBits-1;
12670c16b537SWarner Losh             } else {
12680c16b537SWarner Losh                 count = (short)(bitStream & (2*threshold-1));
12690c16b537SWarner Losh                 if (count >= threshold) count -= max;
12700c16b537SWarner Losh                 bitCount   += nbBits;
12710c16b537SWarner Losh             }
12720c16b537SWarner Losh 
12730c16b537SWarner Losh             count--;   /* extra accuracy */
12740c16b537SWarner Losh             remaining -= FSEv07_abs(count);
12750c16b537SWarner Losh             normalizedCounter[charnum++] = count;
12760c16b537SWarner Losh             previous0 = !count;
12770c16b537SWarner Losh             while (remaining < threshold) {
12780c16b537SWarner Losh                 nbBits--;
12790c16b537SWarner Losh                 threshold >>= 1;
12800c16b537SWarner Losh             }
12810c16b537SWarner Losh 
12820c16b537SWarner Losh             if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
12830c16b537SWarner Losh                 ip += bitCount>>3;
12840c16b537SWarner Losh                 bitCount &= 7;
12850c16b537SWarner Losh             } else {
12860c16b537SWarner Losh                 bitCount -= (int)(8 * (iend - 4 - ip));
12870c16b537SWarner Losh                 ip = iend - 4;
12880c16b537SWarner Losh             }
12890c16b537SWarner Losh             bitStream = MEM_readLE32(ip) >> (bitCount & 31);
12900c16b537SWarner Losh     }   }   /* while ((remaining>1) && (charnum<=*maxSVPtr)) */
12910c16b537SWarner Losh     if (remaining != 1) return ERROR(GENERIC);
12920c16b537SWarner Losh     *maxSVPtr = charnum-1;
12930c16b537SWarner Losh 
12940c16b537SWarner Losh     ip += (bitCount+7)>>3;
12950c16b537SWarner Losh     if ((size_t)(ip-istart) > hbSize) return ERROR(srcSize_wrong);
12960c16b537SWarner Losh     return ip-istart;
12970c16b537SWarner Losh }
12980c16b537SWarner Losh 
12990c16b537SWarner Losh 
13000c16b537SWarner Losh /*! HUFv07_readStats() :
13010c16b537SWarner Losh     Read compact Huffman tree, saved by HUFv07_writeCTable().
13020c16b537SWarner Losh     `huffWeight` is destination buffer.
13030c16b537SWarner Losh     @return : size read from `src` , or an error Code .
13040c16b537SWarner Losh     Note : Needed by HUFv07_readCTable() and HUFv07_readDTableXn() .
13050c16b537SWarner Losh */
HUFv07_readStats(BYTE * huffWeight,size_t hwSize,U32 * rankStats,U32 * nbSymbolsPtr,U32 * tableLogPtr,const void * src,size_t srcSize)13060c16b537SWarner Losh size_t HUFv07_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats,
13070c16b537SWarner Losh                      U32* nbSymbolsPtr, U32* tableLogPtr,
13080c16b537SWarner Losh                      const void* src, size_t srcSize)
13090c16b537SWarner Losh {
13100c16b537SWarner Losh     U32 weightTotal;
13110c16b537SWarner Losh     const BYTE* ip = (const BYTE*) src;
13120c16b537SWarner Losh     size_t iSize;
13130c16b537SWarner Losh     size_t oSize;
13140c16b537SWarner Losh 
13150c16b537SWarner Losh     if (!srcSize) return ERROR(srcSize_wrong);
13160c16b537SWarner Losh     iSize = ip[0];
131737f1f268SConrad Meyer     /* memset(huffWeight, 0, hwSize); */   /* is not necessary, even though some analyzer complain ... */
13180c16b537SWarner Losh 
13190c16b537SWarner Losh     if (iSize >= 128)  { /* special header */
13200c16b537SWarner Losh         if (iSize >= (242)) {  /* RLE */
13210c16b537SWarner Losh             static U32 l[14] = { 1, 2, 3, 4, 7, 8, 15, 16, 31, 32, 63, 64, 127, 128 };
13220c16b537SWarner Losh             oSize = l[iSize-242];
13230c16b537SWarner Losh             memset(huffWeight, 1, hwSize);
13240c16b537SWarner Losh             iSize = 0;
13250c16b537SWarner Losh         }
13260c16b537SWarner Losh         else {   /* Incompressible */
13270c16b537SWarner Losh             oSize = iSize - 127;
13280c16b537SWarner Losh             iSize = ((oSize+1)/2);
13290c16b537SWarner Losh             if (iSize+1 > srcSize) return ERROR(srcSize_wrong);
13300c16b537SWarner Losh             if (oSize >= hwSize) return ERROR(corruption_detected);
13310c16b537SWarner Losh             ip += 1;
13320c16b537SWarner Losh             {   U32 n;
13330c16b537SWarner Losh                 for (n=0; n<oSize; n+=2) {
13340c16b537SWarner Losh                     huffWeight[n]   = ip[n/2] >> 4;
13350c16b537SWarner Losh                     huffWeight[n+1] = ip[n/2] & 15;
13360c16b537SWarner Losh     }   }   }   }
13370c16b537SWarner Losh     else  {   /* header compressed with FSE (normal case) */
13380c16b537SWarner Losh         if (iSize+1 > srcSize) return ERROR(srcSize_wrong);
13390c16b537SWarner Losh         oSize = FSEv07_decompress(huffWeight, hwSize-1, ip+1, iSize);   /* max (hwSize-1) values decoded, as last one is implied */
13400c16b537SWarner Losh         if (FSEv07_isError(oSize)) return oSize;
13410c16b537SWarner Losh     }
13420c16b537SWarner Losh 
13430c16b537SWarner Losh     /* collect weight stats */
13440c16b537SWarner Losh     memset(rankStats, 0, (HUFv07_TABLELOG_ABSOLUTEMAX + 1) * sizeof(U32));
13450c16b537SWarner Losh     weightTotal = 0;
13460c16b537SWarner Losh     {   U32 n; for (n=0; n<oSize; n++) {
13470c16b537SWarner Losh             if (huffWeight[n] >= HUFv07_TABLELOG_ABSOLUTEMAX) return ERROR(corruption_detected);
13480c16b537SWarner Losh             rankStats[huffWeight[n]]++;
13490c16b537SWarner Losh             weightTotal += (1 << huffWeight[n]) >> 1;
13500c16b537SWarner Losh     }   }
13510c16b537SWarner Losh     if (weightTotal == 0) return ERROR(corruption_detected);
13520c16b537SWarner Losh 
13530c16b537SWarner Losh     /* get last non-null symbol weight (implied, total must be 2^n) */
13540c16b537SWarner Losh     {   U32 const tableLog = BITv07_highbit32(weightTotal) + 1;
13550c16b537SWarner Losh         if (tableLog > HUFv07_TABLELOG_ABSOLUTEMAX) return ERROR(corruption_detected);
13560c16b537SWarner Losh         *tableLogPtr = tableLog;
13570c16b537SWarner Losh         /* determine last weight */
13580c16b537SWarner Losh         {   U32 const total = 1 << tableLog;
13590c16b537SWarner Losh             U32 const rest = total - weightTotal;
13600c16b537SWarner Losh             U32 const verif = 1 << BITv07_highbit32(rest);
13610c16b537SWarner Losh             U32 const lastWeight = BITv07_highbit32(rest) + 1;
13620c16b537SWarner Losh             if (verif != rest) return ERROR(corruption_detected);    /* last value must be a clean power of 2 */
13630c16b537SWarner Losh             huffWeight[oSize] = (BYTE)lastWeight;
13640c16b537SWarner Losh             rankStats[lastWeight]++;
13650c16b537SWarner Losh     }   }
13660c16b537SWarner Losh 
13670c16b537SWarner Losh     /* check tree construction validity */
13680c16b537SWarner Losh     if ((rankStats[1] < 2) || (rankStats[1] & 1)) return ERROR(corruption_detected);   /* by construction : at least 2 elts of rank 1, must be even */
13690c16b537SWarner Losh 
13700c16b537SWarner Losh     /* results */
13710c16b537SWarner Losh     *nbSymbolsPtr = (U32)(oSize+1);
13720c16b537SWarner Losh     return iSize+1;
13730c16b537SWarner Losh }
13740c16b537SWarner Losh /* ******************************************************************
13750c16b537SWarner Losh    FSE : Finite State Entropy decoder
13760c16b537SWarner Losh    Copyright (C) 2013-2015, Yann Collet.
13770c16b537SWarner Losh 
13780c16b537SWarner Losh    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
13790c16b537SWarner Losh 
13800c16b537SWarner Losh    Redistribution and use in source and binary forms, with or without
13810c16b537SWarner Losh    modification, are permitted provided that the following conditions are
13820c16b537SWarner Losh    met:
13830c16b537SWarner Losh 
13840c16b537SWarner Losh        * Redistributions of source code must retain the above copyright
13850c16b537SWarner Losh    notice, this list of conditions and the following disclaimer.
13860c16b537SWarner Losh        * Redistributions in binary form must reproduce the above
13870c16b537SWarner Losh    copyright notice, this list of conditions and the following disclaimer
13880c16b537SWarner Losh    in the documentation and/or other materials provided with the
13890c16b537SWarner Losh    distribution.
13900c16b537SWarner Losh 
13910c16b537SWarner Losh    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
13920c16b537SWarner Losh    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
13930c16b537SWarner Losh    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
13940c16b537SWarner Losh    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
13950c16b537SWarner Losh    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
13960c16b537SWarner Losh    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
13970c16b537SWarner Losh    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
13980c16b537SWarner Losh    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
13990c16b537SWarner Losh    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14000c16b537SWarner Losh    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
14010c16b537SWarner Losh    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14020c16b537SWarner Losh 
14030c16b537SWarner Losh     You can contact the author at :
14040c16b537SWarner Losh     - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
14050c16b537SWarner Losh     - Public forum : https://groups.google.com/forum/#!forum/lz4c
14060c16b537SWarner Losh ****************************************************************** */
14070c16b537SWarner Losh 
14080c16b537SWarner Losh 
14090c16b537SWarner Losh /* **************************************************************
14100c16b537SWarner Losh *  Compiler specifics
14110c16b537SWarner Losh ****************************************************************/
14120c16b537SWarner Losh #ifdef _MSC_VER    /* Visual Studio */
14130c16b537SWarner Losh #  define FORCE_INLINE static __forceinline
14140c16b537SWarner Losh #  include <intrin.h>                    /* For Visual 2005 */
14150c16b537SWarner Losh #  pragma warning(disable : 4127)        /* disable: C4127: conditional expression is constant */
14160c16b537SWarner Losh #  pragma warning(disable : 4214)        /* disable: C4214: non-int bitfields */
14170c16b537SWarner Losh #else
14180c16b537SWarner Losh #  if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L   /* C99 */
14190c16b537SWarner Losh #    ifdef __GNUC__
14200c16b537SWarner Losh #      define FORCE_INLINE static inline __attribute__((always_inline))
14210c16b537SWarner Losh #    else
14220c16b537SWarner Losh #      define FORCE_INLINE static inline
14230c16b537SWarner Losh #    endif
14240c16b537SWarner Losh #  else
14250c16b537SWarner Losh #    define FORCE_INLINE static
14260c16b537SWarner Losh #  endif /* __STDC_VERSION__ */
14270c16b537SWarner Losh #endif
14280c16b537SWarner Losh 
14290c16b537SWarner Losh 
14300c16b537SWarner Losh /* **************************************************************
14310c16b537SWarner Losh *  Error Management
14320c16b537SWarner Losh ****************************************************************/
14330c16b537SWarner Losh #define FSEv07_isError ERR_isError
14340c16b537SWarner Losh #define FSEv07_STATIC_ASSERT(c) { enum { FSEv07_static_assert = 1/(int)(!!(c)) }; }   /* use only *after* variable declarations */
14350c16b537SWarner Losh 
14360c16b537SWarner Losh 
14370c16b537SWarner Losh /* **************************************************************
14380c16b537SWarner Losh *  Complex types
14390c16b537SWarner Losh ****************************************************************/
14400c16b537SWarner Losh typedef U32 DTable_max_t[FSEv07_DTABLE_SIZE_U32(FSEv07_MAX_TABLELOG)];
14410c16b537SWarner Losh 
14420c16b537SWarner Losh 
14430c16b537SWarner Losh /* **************************************************************
14440c16b537SWarner Losh *  Templates
14450c16b537SWarner Losh ****************************************************************/
14460c16b537SWarner Losh /*
14470c16b537SWarner Losh   designed to be included
14480c16b537SWarner Losh   for type-specific functions (template emulation in C)
14490c16b537SWarner Losh   Objective is to write these functions only once, for improved maintenance
14500c16b537SWarner Losh */
14510c16b537SWarner Losh 
14520c16b537SWarner Losh /* safety checks */
14530c16b537SWarner Losh #ifndef FSEv07_FUNCTION_EXTENSION
14540c16b537SWarner Losh #  error "FSEv07_FUNCTION_EXTENSION must be defined"
14550c16b537SWarner Losh #endif
14560c16b537SWarner Losh #ifndef FSEv07_FUNCTION_TYPE
14570c16b537SWarner Losh #  error "FSEv07_FUNCTION_TYPE must be defined"
14580c16b537SWarner Losh #endif
14590c16b537SWarner Losh 
14600c16b537SWarner Losh /* Function names */
14610c16b537SWarner Losh #define FSEv07_CAT(X,Y) X##Y
14620c16b537SWarner Losh #define FSEv07_FUNCTION_NAME(X,Y) FSEv07_CAT(X,Y)
14630c16b537SWarner Losh #define FSEv07_TYPE_NAME(X,Y) FSEv07_CAT(X,Y)
14640c16b537SWarner Losh 
14650c16b537SWarner Losh 
14660c16b537SWarner Losh /* Function templates */
FSEv07_createDTable(unsigned tableLog)14670c16b537SWarner Losh FSEv07_DTable* FSEv07_createDTable (unsigned tableLog)
14680c16b537SWarner Losh {
14690c16b537SWarner Losh     if (tableLog > FSEv07_TABLELOG_ABSOLUTE_MAX) tableLog = FSEv07_TABLELOG_ABSOLUTE_MAX;
14700c16b537SWarner Losh     return (FSEv07_DTable*)malloc( FSEv07_DTABLE_SIZE_U32(tableLog) * sizeof (U32) );
14710c16b537SWarner Losh }
14720c16b537SWarner Losh 
FSEv07_freeDTable(FSEv07_DTable * dt)14730c16b537SWarner Losh void FSEv07_freeDTable (FSEv07_DTable* dt)
14740c16b537SWarner Losh {
14750c16b537SWarner Losh     free(dt);
14760c16b537SWarner Losh }
14770c16b537SWarner Losh 
FSEv07_buildDTable(FSEv07_DTable * dt,const short * normalizedCounter,unsigned maxSymbolValue,unsigned tableLog)14780c16b537SWarner Losh size_t FSEv07_buildDTable(FSEv07_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
14790c16b537SWarner Losh {
14800c16b537SWarner Losh     void* const tdPtr = dt+1;   /* because *dt is unsigned, 32-bits aligned on 32-bits */
14810c16b537SWarner Losh     FSEv07_DECODE_TYPE* const tableDecode = (FSEv07_DECODE_TYPE*) (tdPtr);
14820c16b537SWarner Losh     U16 symbolNext[FSEv07_MAX_SYMBOL_VALUE+1];
14830c16b537SWarner Losh 
14840c16b537SWarner Losh     U32 const maxSV1 = maxSymbolValue + 1;
14850c16b537SWarner Losh     U32 const tableSize = 1 << tableLog;
14860c16b537SWarner Losh     U32 highThreshold = tableSize-1;
14870c16b537SWarner Losh 
14880c16b537SWarner Losh     /* Sanity Checks */
14890c16b537SWarner Losh     if (maxSymbolValue > FSEv07_MAX_SYMBOL_VALUE) return ERROR(maxSymbolValue_tooLarge);
14900c16b537SWarner Losh     if (tableLog > FSEv07_MAX_TABLELOG) return ERROR(tableLog_tooLarge);
14910c16b537SWarner Losh 
14920c16b537SWarner Losh     /* Init, lay down lowprob symbols */
14930c16b537SWarner Losh     {   FSEv07_DTableHeader DTableH;
14940c16b537SWarner Losh         DTableH.tableLog = (U16)tableLog;
14950c16b537SWarner Losh         DTableH.fastMode = 1;
14960c16b537SWarner Losh         {   S16 const largeLimit= (S16)(1 << (tableLog-1));
14970c16b537SWarner Losh             U32 s;
14980c16b537SWarner Losh             for (s=0; s<maxSV1; s++) {
14990c16b537SWarner Losh                 if (normalizedCounter[s]==-1) {
15000c16b537SWarner Losh                     tableDecode[highThreshold--].symbol = (FSEv07_FUNCTION_TYPE)s;
15010c16b537SWarner Losh                     symbolNext[s] = 1;
15020c16b537SWarner Losh                 } else {
15030c16b537SWarner Losh                     if (normalizedCounter[s] >= largeLimit) DTableH.fastMode=0;
15040c16b537SWarner Losh                     symbolNext[s] = normalizedCounter[s];
15050c16b537SWarner Losh         }   }   }
15060c16b537SWarner Losh         memcpy(dt, &DTableH, sizeof(DTableH));
15070c16b537SWarner Losh     }
15080c16b537SWarner Losh 
15090c16b537SWarner Losh     /* Spread symbols */
15100c16b537SWarner Losh     {   U32 const tableMask = tableSize-1;
15110c16b537SWarner Losh         U32 const step = FSEv07_TABLESTEP(tableSize);
15120c16b537SWarner Losh         U32 s, position = 0;
15130c16b537SWarner Losh         for (s=0; s<maxSV1; s++) {
15140c16b537SWarner Losh             int i;
15150c16b537SWarner Losh             for (i=0; i<normalizedCounter[s]; i++) {
15160c16b537SWarner Losh                 tableDecode[position].symbol = (FSEv07_FUNCTION_TYPE)s;
15170c16b537SWarner Losh                 position = (position + step) & tableMask;
15180c16b537SWarner Losh                 while (position > highThreshold) position = (position + step) & tableMask;   /* lowprob area */
15190c16b537SWarner Losh         }   }
15200c16b537SWarner Losh 
15210c16b537SWarner Losh         if (position!=0) return ERROR(GENERIC);   /* position must reach all cells once, otherwise normalizedCounter is incorrect */
15220c16b537SWarner Losh     }
15230c16b537SWarner Losh 
15240c16b537SWarner Losh     /* Build Decoding table */
15250c16b537SWarner Losh     {   U32 u;
15260c16b537SWarner Losh         for (u=0; u<tableSize; u++) {
15270c16b537SWarner Losh             FSEv07_FUNCTION_TYPE const symbol = (FSEv07_FUNCTION_TYPE)(tableDecode[u].symbol);
15280c16b537SWarner Losh             U16 nextState = symbolNext[symbol]++;
15290c16b537SWarner Losh             tableDecode[u].nbBits = (BYTE) (tableLog - BITv07_highbit32 ((U32)nextState) );
15300c16b537SWarner Losh             tableDecode[u].newState = (U16) ( (nextState << tableDecode[u].nbBits) - tableSize);
15310c16b537SWarner Losh     }   }
15320c16b537SWarner Losh 
15330c16b537SWarner Losh     return 0;
15340c16b537SWarner Losh }
15350c16b537SWarner Losh 
15360c16b537SWarner Losh 
15370c16b537SWarner Losh 
15380c16b537SWarner Losh #ifndef FSEv07_COMMONDEFS_ONLY
15390c16b537SWarner Losh 
15400c16b537SWarner Losh /*-*******************************************************
15410c16b537SWarner Losh *  Decompression (Byte symbols)
15420c16b537SWarner Losh *********************************************************/
FSEv07_buildDTable_rle(FSEv07_DTable * dt,BYTE symbolValue)15430c16b537SWarner Losh size_t FSEv07_buildDTable_rle (FSEv07_DTable* dt, BYTE symbolValue)
15440c16b537SWarner Losh {
15450c16b537SWarner Losh     void* ptr = dt;
15460c16b537SWarner Losh     FSEv07_DTableHeader* const DTableH = (FSEv07_DTableHeader*)ptr;
15470c16b537SWarner Losh     void* dPtr = dt + 1;
15480c16b537SWarner Losh     FSEv07_decode_t* const cell = (FSEv07_decode_t*)dPtr;
15490c16b537SWarner Losh 
15500c16b537SWarner Losh     DTableH->tableLog = 0;
15510c16b537SWarner Losh     DTableH->fastMode = 0;
15520c16b537SWarner Losh 
15530c16b537SWarner Losh     cell->newState = 0;
15540c16b537SWarner Losh     cell->symbol = symbolValue;
15550c16b537SWarner Losh     cell->nbBits = 0;
15560c16b537SWarner Losh 
15570c16b537SWarner Losh     return 0;
15580c16b537SWarner Losh }
15590c16b537SWarner Losh 
15600c16b537SWarner Losh 
FSEv07_buildDTable_raw(FSEv07_DTable * dt,unsigned nbBits)15610c16b537SWarner Losh size_t FSEv07_buildDTable_raw (FSEv07_DTable* dt, unsigned nbBits)
15620c16b537SWarner Losh {
15630c16b537SWarner Losh     void* ptr = dt;
15640c16b537SWarner Losh     FSEv07_DTableHeader* const DTableH = (FSEv07_DTableHeader*)ptr;
15650c16b537SWarner Losh     void* dPtr = dt + 1;
15660c16b537SWarner Losh     FSEv07_decode_t* const dinfo = (FSEv07_decode_t*)dPtr;
15670c16b537SWarner Losh     const unsigned tableSize = 1 << nbBits;
15680c16b537SWarner Losh     const unsigned tableMask = tableSize - 1;
15690c16b537SWarner Losh     const unsigned maxSV1 = tableMask+1;
15700c16b537SWarner Losh     unsigned s;
15710c16b537SWarner Losh 
15720c16b537SWarner Losh     /* Sanity checks */
15730c16b537SWarner Losh     if (nbBits < 1) return ERROR(GENERIC);         /* min size */
15740c16b537SWarner Losh 
15750c16b537SWarner Losh     /* Build Decoding Table */
15760c16b537SWarner Losh     DTableH->tableLog = (U16)nbBits;
15770c16b537SWarner Losh     DTableH->fastMode = 1;
15780c16b537SWarner Losh     for (s=0; s<maxSV1; s++) {
15790c16b537SWarner Losh         dinfo[s].newState = 0;
15800c16b537SWarner Losh         dinfo[s].symbol = (BYTE)s;
15810c16b537SWarner Losh         dinfo[s].nbBits = (BYTE)nbBits;
15820c16b537SWarner Losh     }
15830c16b537SWarner Losh 
15840c16b537SWarner Losh     return 0;
15850c16b537SWarner Losh }
15860c16b537SWarner Losh 
FSEv07_decompress_usingDTable_generic(void * dst,size_t maxDstSize,const void * cSrc,size_t cSrcSize,const FSEv07_DTable * dt,const unsigned fast)15870c16b537SWarner Losh FORCE_INLINE size_t FSEv07_decompress_usingDTable_generic(
15880c16b537SWarner Losh           void* dst, size_t maxDstSize,
15890c16b537SWarner Losh     const void* cSrc, size_t cSrcSize,
15900c16b537SWarner Losh     const FSEv07_DTable* dt, const unsigned fast)
15910c16b537SWarner Losh {
15920c16b537SWarner Losh     BYTE* const ostart = (BYTE*) dst;
15930c16b537SWarner Losh     BYTE* op = ostart;
15940c16b537SWarner Losh     BYTE* const omax = op + maxDstSize;
15950c16b537SWarner Losh     BYTE* const olimit = omax-3;
15960c16b537SWarner Losh 
15970c16b537SWarner Losh     BITv07_DStream_t bitD;
15980c16b537SWarner Losh     FSEv07_DState_t state1;
15990c16b537SWarner Losh     FSEv07_DState_t state2;
16000c16b537SWarner Losh 
16010c16b537SWarner Losh     /* Init */
16020c16b537SWarner Losh     { size_t const errorCode = BITv07_initDStream(&bitD, cSrc, cSrcSize);   /* replaced last arg by maxCompressed Size */
16030c16b537SWarner Losh       if (FSEv07_isError(errorCode)) return errorCode; }
16040c16b537SWarner Losh 
16050c16b537SWarner Losh     FSEv07_initDState(&state1, &bitD, dt);
16060c16b537SWarner Losh     FSEv07_initDState(&state2, &bitD, dt);
16070c16b537SWarner Losh 
16080c16b537SWarner Losh #define FSEv07_GETSYMBOL(statePtr) fast ? FSEv07_decodeSymbolFast(statePtr, &bitD) : FSEv07_decodeSymbol(statePtr, &bitD)
16090c16b537SWarner Losh 
16100c16b537SWarner Losh     /* 4 symbols per loop */
16110c16b537SWarner Losh     for ( ; (BITv07_reloadDStream(&bitD)==BITv07_DStream_unfinished) && (op<olimit) ; op+=4) {
16120c16b537SWarner Losh         op[0] = FSEv07_GETSYMBOL(&state1);
16130c16b537SWarner Losh 
16140c16b537SWarner Losh         if (FSEv07_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8)    /* This test must be static */
16150c16b537SWarner Losh             BITv07_reloadDStream(&bitD);
16160c16b537SWarner Losh 
16170c16b537SWarner Losh         op[1] = FSEv07_GETSYMBOL(&state2);
16180c16b537SWarner Losh 
16190c16b537SWarner Losh         if (FSEv07_MAX_TABLELOG*4+7 > sizeof(bitD.bitContainer)*8)    /* This test must be static */
16200c16b537SWarner Losh             { if (BITv07_reloadDStream(&bitD) > BITv07_DStream_unfinished) { op+=2; break; } }
16210c16b537SWarner Losh 
16220c16b537SWarner Losh         op[2] = FSEv07_GETSYMBOL(&state1);
16230c16b537SWarner Losh 
16240c16b537SWarner Losh         if (FSEv07_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8)    /* This test must be static */
16250c16b537SWarner Losh             BITv07_reloadDStream(&bitD);
16260c16b537SWarner Losh 
16270c16b537SWarner Losh         op[3] = FSEv07_GETSYMBOL(&state2);
16280c16b537SWarner Losh     }
16290c16b537SWarner Losh 
16300c16b537SWarner Losh     /* tail */
16310c16b537SWarner Losh     /* note : BITv07_reloadDStream(&bitD) >= FSEv07_DStream_partiallyFilled; Ends at exactly BITv07_DStream_completed */
16320c16b537SWarner Losh     while (1) {
16330c16b537SWarner Losh         if (op>(omax-2)) return ERROR(dstSize_tooSmall);
16340c16b537SWarner Losh 
16350c16b537SWarner Losh         *op++ = FSEv07_GETSYMBOL(&state1);
16360c16b537SWarner Losh 
16370c16b537SWarner Losh         if (BITv07_reloadDStream(&bitD)==BITv07_DStream_overflow) {
16380c16b537SWarner Losh             *op++ = FSEv07_GETSYMBOL(&state2);
16390c16b537SWarner Losh             break;
16400c16b537SWarner Losh         }
16410c16b537SWarner Losh 
16420c16b537SWarner Losh         if (op>(omax-2)) return ERROR(dstSize_tooSmall);
16430c16b537SWarner Losh 
16440c16b537SWarner Losh         *op++ = FSEv07_GETSYMBOL(&state2);
16450c16b537SWarner Losh 
16460c16b537SWarner Losh         if (BITv07_reloadDStream(&bitD)==BITv07_DStream_overflow) {
16470c16b537SWarner Losh             *op++ = FSEv07_GETSYMBOL(&state1);
16480c16b537SWarner Losh             break;
16490c16b537SWarner Losh     }   }
16500c16b537SWarner Losh 
16510c16b537SWarner Losh     return op-ostart;
16520c16b537SWarner Losh }
16530c16b537SWarner Losh 
16540c16b537SWarner Losh 
FSEv07_decompress_usingDTable(void * dst,size_t originalSize,const void * cSrc,size_t cSrcSize,const FSEv07_DTable * dt)16550c16b537SWarner Losh size_t FSEv07_decompress_usingDTable(void* dst, size_t originalSize,
16560c16b537SWarner Losh                             const void* cSrc, size_t cSrcSize,
16570c16b537SWarner Losh                             const FSEv07_DTable* dt)
16580c16b537SWarner Losh {
16590c16b537SWarner Losh     const void* ptr = dt;
16600c16b537SWarner Losh     const FSEv07_DTableHeader* DTableH = (const FSEv07_DTableHeader*)ptr;
16610c16b537SWarner Losh     const U32 fastMode = DTableH->fastMode;
16620c16b537SWarner Losh 
16630c16b537SWarner Losh     /* select fast mode (static) */
16640c16b537SWarner Losh     if (fastMode) return FSEv07_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 1);
16650c16b537SWarner Losh     return FSEv07_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 0);
16660c16b537SWarner Losh }
16670c16b537SWarner Losh 
16680c16b537SWarner Losh 
FSEv07_decompress(void * dst,size_t maxDstSize,const void * cSrc,size_t cSrcSize)16690c16b537SWarner Losh size_t FSEv07_decompress(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize)
16700c16b537SWarner Losh {
16710c16b537SWarner Losh     const BYTE* const istart = (const BYTE*)cSrc;
16720c16b537SWarner Losh     const BYTE* ip = istart;
16730c16b537SWarner Losh     short counting[FSEv07_MAX_SYMBOL_VALUE+1];
16740c16b537SWarner Losh     DTable_max_t dt;   /* Static analyzer seems unable to understand this table will be properly initialized later */
16750c16b537SWarner Losh     unsigned tableLog;
16760c16b537SWarner Losh     unsigned maxSymbolValue = FSEv07_MAX_SYMBOL_VALUE;
16770c16b537SWarner Losh 
16780c16b537SWarner Losh     if (cSrcSize<2) return ERROR(srcSize_wrong);   /* too small input size */
16790c16b537SWarner Losh 
16800c16b537SWarner Losh     /* normal FSE decoding mode */
16810c16b537SWarner Losh     {   size_t const NCountLength = FSEv07_readNCount (counting, &maxSymbolValue, &tableLog, istart, cSrcSize);
16820c16b537SWarner Losh         if (FSEv07_isError(NCountLength)) return NCountLength;
16830c16b537SWarner Losh         if (NCountLength >= cSrcSize) return ERROR(srcSize_wrong);   /* too small input size */
16840c16b537SWarner Losh         ip += NCountLength;
16850c16b537SWarner Losh         cSrcSize -= NCountLength;
16860c16b537SWarner Losh     }
16870c16b537SWarner Losh 
16880c16b537SWarner Losh     { size_t const errorCode = FSEv07_buildDTable (dt, counting, maxSymbolValue, tableLog);
16890c16b537SWarner Losh       if (FSEv07_isError(errorCode)) return errorCode; }
16900c16b537SWarner Losh 
16910c16b537SWarner Losh     return FSEv07_decompress_usingDTable (dst, maxDstSize, ip, cSrcSize, dt);   /* always return, even if it is an error code */
16920c16b537SWarner Losh }
16930c16b537SWarner Losh 
16940c16b537SWarner Losh 
16950c16b537SWarner Losh 
16960c16b537SWarner Losh #endif   /* FSEv07_COMMONDEFS_ONLY */
16970c16b537SWarner Losh 
16980c16b537SWarner Losh /* ******************************************************************
16990c16b537SWarner Losh    Huffman decoder, part of New Generation Entropy library
17000c16b537SWarner Losh    Copyright (C) 2013-2016, Yann Collet.
17010c16b537SWarner Losh 
17020c16b537SWarner Losh    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
17030c16b537SWarner Losh 
17040c16b537SWarner Losh    Redistribution and use in source and binary forms, with or without
17050c16b537SWarner Losh    modification, are permitted provided that the following conditions are
17060c16b537SWarner Losh    met:
17070c16b537SWarner Losh 
17080c16b537SWarner Losh        * Redistributions of source code must retain the above copyright
17090c16b537SWarner Losh    notice, this list of conditions and the following disclaimer.
17100c16b537SWarner Losh        * Redistributions in binary form must reproduce the above
17110c16b537SWarner Losh    copyright notice, this list of conditions and the following disclaimer
17120c16b537SWarner Losh    in the documentation and/or other materials provided with the
17130c16b537SWarner Losh    distribution.
17140c16b537SWarner Losh 
17150c16b537SWarner Losh    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17160c16b537SWarner Losh    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17170c16b537SWarner Losh    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17180c16b537SWarner Losh    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
17190c16b537SWarner Losh    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
17200c16b537SWarner Losh    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
17210c16b537SWarner Losh    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
17220c16b537SWarner Losh    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
17230c16b537SWarner Losh    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
17240c16b537SWarner Losh    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
17250c16b537SWarner Losh    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17260c16b537SWarner Losh 
17270c16b537SWarner Losh     You can contact the author at :
17280c16b537SWarner Losh     - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
17290c16b537SWarner Losh     - Public forum : https://groups.google.com/forum/#!forum/lz4c
17300c16b537SWarner Losh ****************************************************************** */
17310c16b537SWarner Losh 
17320c16b537SWarner Losh /* **************************************************************
17330c16b537SWarner Losh *  Compiler specifics
17340c16b537SWarner Losh ****************************************************************/
17350c16b537SWarner Losh #if defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
17360c16b537SWarner Losh /* inline is defined */
17370c16b537SWarner Losh #elif defined(_MSC_VER)
17380c16b537SWarner Losh #  define inline __inline
17390c16b537SWarner Losh #else
17400c16b537SWarner Losh #  define inline /* disable inline */
17410c16b537SWarner Losh #endif
17420c16b537SWarner Losh 
17430c16b537SWarner Losh 
17440c16b537SWarner Losh #ifdef _MSC_VER    /* Visual Studio */
17450c16b537SWarner Losh #  pragma warning(disable : 4127)        /* disable: C4127: conditional expression is constant */
17460c16b537SWarner Losh #endif
17470c16b537SWarner Losh 
17480c16b537SWarner Losh 
17490c16b537SWarner Losh 
17500c16b537SWarner Losh /* **************************************************************
17510c16b537SWarner Losh *  Error Management
17520c16b537SWarner Losh ****************************************************************/
17530c16b537SWarner Losh #define HUFv07_STATIC_ASSERT(c) { enum { HUFv07_static_assert = 1/(int)(!!(c)) }; }   /* use only *after* variable declarations */
17540c16b537SWarner Losh 
17550c16b537SWarner Losh 
17560c16b537SWarner Losh /*-***************************/
17570c16b537SWarner Losh /*  generic DTableDesc       */
17580c16b537SWarner Losh /*-***************************/
17590c16b537SWarner Losh 
17600c16b537SWarner Losh typedef struct { BYTE maxTableLog; BYTE tableType; BYTE tableLog; BYTE reserved; } DTableDesc;
17610c16b537SWarner Losh 
HUFv07_getDTableDesc(const HUFv07_DTable * table)17620c16b537SWarner Losh static DTableDesc HUFv07_getDTableDesc(const HUFv07_DTable* table)
17630c16b537SWarner Losh {
17640c16b537SWarner Losh     DTableDesc dtd;
17650c16b537SWarner Losh     memcpy(&dtd, table, sizeof(dtd));
17660c16b537SWarner Losh     return dtd;
17670c16b537SWarner Losh }
17680c16b537SWarner Losh 
17690c16b537SWarner Losh 
17700c16b537SWarner Losh /*-***************************/
17710c16b537SWarner Losh /*  single-symbol decoding   */
17720c16b537SWarner Losh /*-***************************/
17730c16b537SWarner Losh 
17740c16b537SWarner Losh typedef struct { BYTE byte; BYTE nbBits; } HUFv07_DEltX2;   /* single-symbol decoding */
17750c16b537SWarner Losh 
HUFv07_readDTableX2(HUFv07_DTable * DTable,const void * src,size_t srcSize)17760c16b537SWarner Losh size_t HUFv07_readDTableX2 (HUFv07_DTable* DTable, const void* src, size_t srcSize)
17770c16b537SWarner Losh {
17780c16b537SWarner Losh     BYTE huffWeight[HUFv07_SYMBOLVALUE_MAX + 1];
17790c16b537SWarner Losh     U32 rankVal[HUFv07_TABLELOG_ABSOLUTEMAX + 1];   /* large enough for values from 0 to 16 */
17800c16b537SWarner Losh     U32 tableLog = 0;
17810c16b537SWarner Losh     U32 nbSymbols = 0;
17820c16b537SWarner Losh     size_t iSize;
17830c16b537SWarner Losh     void* const dtPtr = DTable + 1;
17840c16b537SWarner Losh     HUFv07_DEltX2* const dt = (HUFv07_DEltX2*)dtPtr;
17850c16b537SWarner Losh 
17860c16b537SWarner Losh     HUFv07_STATIC_ASSERT(sizeof(DTableDesc) == sizeof(HUFv07_DTable));
178737f1f268SConrad Meyer     /* memset(huffWeight, 0, sizeof(huffWeight)); */   /* is not necessary, even though some analyzer complain ... */
17880c16b537SWarner Losh 
17890c16b537SWarner Losh     iSize = HUFv07_readStats(huffWeight, HUFv07_SYMBOLVALUE_MAX + 1, rankVal, &nbSymbols, &tableLog, src, srcSize);
17900c16b537SWarner Losh     if (HUFv07_isError(iSize)) return iSize;
17910c16b537SWarner Losh 
17920c16b537SWarner Losh     /* Table header */
17930c16b537SWarner Losh     {   DTableDesc dtd = HUFv07_getDTableDesc(DTable);
17940c16b537SWarner Losh         if (tableLog > (U32)(dtd.maxTableLog+1)) return ERROR(tableLog_tooLarge);   /* DTable too small, huffman tree cannot fit in */
17950c16b537SWarner Losh         dtd.tableType = 0;
17960c16b537SWarner Losh         dtd.tableLog = (BYTE)tableLog;
17970c16b537SWarner Losh         memcpy(DTable, &dtd, sizeof(dtd));
17980c16b537SWarner Losh     }
17990c16b537SWarner Losh 
18000c16b537SWarner Losh     /* Prepare ranks */
18010c16b537SWarner Losh     {   U32 n, nextRankStart = 0;
18020c16b537SWarner Losh         for (n=1; n<tableLog+1; n++) {
18030c16b537SWarner Losh             U32 current = nextRankStart;
18040c16b537SWarner Losh             nextRankStart += (rankVal[n] << (n-1));
18050c16b537SWarner Losh             rankVal[n] = current;
18060c16b537SWarner Losh     }   }
18070c16b537SWarner Losh 
18080c16b537SWarner Losh     /* fill DTable */
18090c16b537SWarner Losh     {   U32 n;
18100c16b537SWarner Losh         for (n=0; n<nbSymbols; n++) {
18110c16b537SWarner Losh             U32 const w = huffWeight[n];
18120c16b537SWarner Losh             U32 const length = (1 << w) >> 1;
18130c16b537SWarner Losh             U32 i;
18140c16b537SWarner Losh             HUFv07_DEltX2 D;
18150c16b537SWarner Losh             D.byte = (BYTE)n; D.nbBits = (BYTE)(tableLog + 1 - w);
18160c16b537SWarner Losh             for (i = rankVal[w]; i < rankVal[w] + length; i++)
18170c16b537SWarner Losh                 dt[i] = D;
18180c16b537SWarner Losh             rankVal[w] += length;
18190c16b537SWarner Losh     }   }
18200c16b537SWarner Losh 
18210c16b537SWarner Losh     return iSize;
18220c16b537SWarner Losh }
18230c16b537SWarner Losh 
18240c16b537SWarner Losh 
HUFv07_decodeSymbolX2(BITv07_DStream_t * Dstream,const HUFv07_DEltX2 * dt,const U32 dtLog)18250c16b537SWarner Losh static BYTE HUFv07_decodeSymbolX2(BITv07_DStream_t* Dstream, const HUFv07_DEltX2* dt, const U32 dtLog)
18260c16b537SWarner Losh {
18270c16b537SWarner Losh     size_t const val = BITv07_lookBitsFast(Dstream, dtLog); /* note : dtLog >= 1 */
18280c16b537SWarner Losh     BYTE const c = dt[val].byte;
18290c16b537SWarner Losh     BITv07_skipBits(Dstream, dt[val].nbBits);
18300c16b537SWarner Losh     return c;
18310c16b537SWarner Losh }
18320c16b537SWarner Losh 
18330c16b537SWarner Losh #define HUFv07_DECODE_SYMBOLX2_0(ptr, DStreamPtr) \
18340c16b537SWarner Losh     *ptr++ = HUFv07_decodeSymbolX2(DStreamPtr, dt, dtLog)
18350c16b537SWarner Losh 
18360c16b537SWarner Losh #define HUFv07_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \
18370c16b537SWarner Losh     if (MEM_64bits() || (HUFv07_TABLELOG_MAX<=12)) \
18380c16b537SWarner Losh         HUFv07_DECODE_SYMBOLX2_0(ptr, DStreamPtr)
18390c16b537SWarner Losh 
18400c16b537SWarner Losh #define HUFv07_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \
18410c16b537SWarner Losh     if (MEM_64bits()) \
18420c16b537SWarner Losh         HUFv07_DECODE_SYMBOLX2_0(ptr, DStreamPtr)
18430c16b537SWarner Losh 
HUFv07_decodeStreamX2(BYTE * p,BITv07_DStream_t * const bitDPtr,BYTE * const pEnd,const HUFv07_DEltX2 * const dt,const U32 dtLog)18440c16b537SWarner Losh static inline size_t HUFv07_decodeStreamX2(BYTE* p, BITv07_DStream_t* const bitDPtr, BYTE* const pEnd, const HUFv07_DEltX2* const dt, const U32 dtLog)
18450c16b537SWarner Losh {
18460c16b537SWarner Losh     BYTE* const pStart = p;
18470c16b537SWarner Losh 
18480c16b537SWarner Losh     /* up to 4 symbols at a time */
18490c16b537SWarner Losh     while ((BITv07_reloadDStream(bitDPtr) == BITv07_DStream_unfinished) && (p <= pEnd-4)) {
18500c16b537SWarner Losh         HUFv07_DECODE_SYMBOLX2_2(p, bitDPtr);
18510c16b537SWarner Losh         HUFv07_DECODE_SYMBOLX2_1(p, bitDPtr);
18520c16b537SWarner Losh         HUFv07_DECODE_SYMBOLX2_2(p, bitDPtr);
18530c16b537SWarner Losh         HUFv07_DECODE_SYMBOLX2_0(p, bitDPtr);
18540c16b537SWarner Losh     }
18550c16b537SWarner Losh 
18560c16b537SWarner Losh     /* closer to the end */
18570c16b537SWarner Losh     while ((BITv07_reloadDStream(bitDPtr) == BITv07_DStream_unfinished) && (p < pEnd))
18580c16b537SWarner Losh         HUFv07_DECODE_SYMBOLX2_0(p, bitDPtr);
18590c16b537SWarner Losh 
18600c16b537SWarner Losh     /* no more data to retrieve from bitstream, hence no need to reload */
18610c16b537SWarner Losh     while (p < pEnd)
18620c16b537SWarner Losh         HUFv07_DECODE_SYMBOLX2_0(p, bitDPtr);
18630c16b537SWarner Losh 
18640c16b537SWarner Losh     return pEnd-pStart;
18650c16b537SWarner Losh }
18660c16b537SWarner Losh 
HUFv07_decompress1X2_usingDTable_internal(void * dst,size_t dstSize,const void * cSrc,size_t cSrcSize,const HUFv07_DTable * DTable)18670c16b537SWarner Losh static size_t HUFv07_decompress1X2_usingDTable_internal(
18680c16b537SWarner Losh           void* dst,  size_t dstSize,
18690c16b537SWarner Losh     const void* cSrc, size_t cSrcSize,
18700c16b537SWarner Losh     const HUFv07_DTable* DTable)
18710c16b537SWarner Losh {
18720c16b537SWarner Losh     BYTE* op = (BYTE*)dst;
18730c16b537SWarner Losh     BYTE* const oend = op + dstSize;
18740c16b537SWarner Losh     const void* dtPtr = DTable + 1;
18750c16b537SWarner Losh     const HUFv07_DEltX2* const dt = (const HUFv07_DEltX2*)dtPtr;
18760c16b537SWarner Losh     BITv07_DStream_t bitD;
18770c16b537SWarner Losh     DTableDesc const dtd = HUFv07_getDTableDesc(DTable);
18780c16b537SWarner Losh     U32 const dtLog = dtd.tableLog;
18790c16b537SWarner Losh 
18800c16b537SWarner Losh     { size_t const errorCode = BITv07_initDStream(&bitD, cSrc, cSrcSize);
18810c16b537SWarner Losh       if (HUFv07_isError(errorCode)) return errorCode; }
18820c16b537SWarner Losh 
18830c16b537SWarner Losh     HUFv07_decodeStreamX2(op, &bitD, oend, dt, dtLog);
18840c16b537SWarner Losh 
18850c16b537SWarner Losh     /* check */
18860c16b537SWarner Losh     if (!BITv07_endOfDStream(&bitD)) return ERROR(corruption_detected);
18870c16b537SWarner Losh 
18880c16b537SWarner Losh     return dstSize;
18890c16b537SWarner Losh }
18900c16b537SWarner Losh 
HUFv07_decompress1X2_usingDTable(void * dst,size_t dstSize,const void * cSrc,size_t cSrcSize,const HUFv07_DTable * DTable)18910c16b537SWarner Losh size_t HUFv07_decompress1X2_usingDTable(
18920c16b537SWarner Losh           void* dst,  size_t dstSize,
18930c16b537SWarner Losh     const void* cSrc, size_t cSrcSize,
18940c16b537SWarner Losh     const HUFv07_DTable* DTable)
18950c16b537SWarner Losh {
18960c16b537SWarner Losh     DTableDesc dtd = HUFv07_getDTableDesc(DTable);
18970c16b537SWarner Losh     if (dtd.tableType != 0) return ERROR(GENERIC);
18980c16b537SWarner Losh     return HUFv07_decompress1X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable);
18990c16b537SWarner Losh }
19000c16b537SWarner Losh 
HUFv07_decompress1X2_DCtx(HUFv07_DTable * DCtx,void * dst,size_t dstSize,const void * cSrc,size_t cSrcSize)19010c16b537SWarner Losh size_t HUFv07_decompress1X2_DCtx (HUFv07_DTable* DCtx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
19020c16b537SWarner Losh {
19030c16b537SWarner Losh     const BYTE* ip = (const BYTE*) cSrc;
19040c16b537SWarner Losh 
19050c16b537SWarner Losh     size_t const hSize = HUFv07_readDTableX2 (DCtx, cSrc, cSrcSize);
19060c16b537SWarner Losh     if (HUFv07_isError(hSize)) return hSize;
19070c16b537SWarner Losh     if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
19080c16b537SWarner Losh     ip += hSize; cSrcSize -= hSize;
19090c16b537SWarner Losh 
19100c16b537SWarner Losh     return HUFv07_decompress1X2_usingDTable_internal (dst, dstSize, ip, cSrcSize, DCtx);
19110c16b537SWarner Losh }
19120c16b537SWarner Losh 
HUFv07_decompress1X2(void * dst,size_t dstSize,const void * cSrc,size_t cSrcSize)19130c16b537SWarner Losh size_t HUFv07_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
19140c16b537SWarner Losh {
19150c16b537SWarner Losh     HUFv07_CREATE_STATIC_DTABLEX2(DTable, HUFv07_TABLELOG_MAX);
19160c16b537SWarner Losh     return HUFv07_decompress1X2_DCtx (DTable, dst, dstSize, cSrc, cSrcSize);
19170c16b537SWarner Losh }
19180c16b537SWarner Losh 
19190c16b537SWarner Losh 
HUFv07_decompress4X2_usingDTable_internal(void * dst,size_t dstSize,const void * cSrc,size_t cSrcSize,const HUFv07_DTable * DTable)19200c16b537SWarner Losh static size_t HUFv07_decompress4X2_usingDTable_internal(
19210c16b537SWarner Losh           void* dst,  size_t dstSize,
19220c16b537SWarner Losh     const void* cSrc, size_t cSrcSize,
19230c16b537SWarner Losh     const HUFv07_DTable* DTable)
19240c16b537SWarner Losh {
19250c16b537SWarner Losh     /* Check */
19260c16b537SWarner Losh     if (cSrcSize < 10) return ERROR(corruption_detected);  /* strict minimum : jump table + 1 byte per stream */
19270c16b537SWarner Losh 
19280c16b537SWarner Losh     {   const BYTE* const istart = (const BYTE*) cSrc;
19290c16b537SWarner Losh         BYTE* const ostart = (BYTE*) dst;
19300c16b537SWarner Losh         BYTE* const oend = ostart + dstSize;
19310c16b537SWarner Losh         const void* const dtPtr = DTable + 1;
19320c16b537SWarner Losh         const HUFv07_DEltX2* const dt = (const HUFv07_DEltX2*)dtPtr;
19330c16b537SWarner Losh 
19340c16b537SWarner Losh         /* Init */
19350c16b537SWarner Losh         BITv07_DStream_t bitD1;
19360c16b537SWarner Losh         BITv07_DStream_t bitD2;
19370c16b537SWarner Losh         BITv07_DStream_t bitD3;
19380c16b537SWarner Losh         BITv07_DStream_t bitD4;
19390c16b537SWarner Losh         size_t const length1 = MEM_readLE16(istart);
19400c16b537SWarner Losh         size_t const length2 = MEM_readLE16(istart+2);
19410c16b537SWarner Losh         size_t const length3 = MEM_readLE16(istart+4);
19420c16b537SWarner Losh         size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6);
19430c16b537SWarner Losh         const BYTE* const istart1 = istart + 6;  /* jumpTable */
19440c16b537SWarner Losh         const BYTE* const istart2 = istart1 + length1;
19450c16b537SWarner Losh         const BYTE* const istart3 = istart2 + length2;
19460c16b537SWarner Losh         const BYTE* const istart4 = istart3 + length3;
19470c16b537SWarner Losh         const size_t segmentSize = (dstSize+3) / 4;
19480c16b537SWarner Losh         BYTE* const opStart2 = ostart + segmentSize;
19490c16b537SWarner Losh         BYTE* const opStart3 = opStart2 + segmentSize;
19500c16b537SWarner Losh         BYTE* const opStart4 = opStart3 + segmentSize;
19510c16b537SWarner Losh         BYTE* op1 = ostart;
19520c16b537SWarner Losh         BYTE* op2 = opStart2;
19530c16b537SWarner Losh         BYTE* op3 = opStart3;
19540c16b537SWarner Losh         BYTE* op4 = opStart4;
19550c16b537SWarner Losh         U32 endSignal;
19560c16b537SWarner Losh         DTableDesc const dtd = HUFv07_getDTableDesc(DTable);
19570c16b537SWarner Losh         U32 const dtLog = dtd.tableLog;
19580c16b537SWarner Losh 
19590c16b537SWarner Losh         if (length4 > cSrcSize) return ERROR(corruption_detected);   /* overflow */
19600c16b537SWarner Losh         { size_t const errorCode = BITv07_initDStream(&bitD1, istart1, length1);
19610c16b537SWarner Losh           if (HUFv07_isError(errorCode)) return errorCode; }
19620c16b537SWarner Losh         { size_t const errorCode = BITv07_initDStream(&bitD2, istart2, length2);
19630c16b537SWarner Losh           if (HUFv07_isError(errorCode)) return errorCode; }
19640c16b537SWarner Losh         { size_t const errorCode = BITv07_initDStream(&bitD3, istart3, length3);
19650c16b537SWarner Losh           if (HUFv07_isError(errorCode)) return errorCode; }
19660c16b537SWarner Losh         { size_t const errorCode = BITv07_initDStream(&bitD4, istart4, length4);
19670c16b537SWarner Losh           if (HUFv07_isError(errorCode)) return errorCode; }
19680c16b537SWarner Losh 
19690c16b537SWarner Losh         /* 16-32 symbols per loop (4-8 symbols per stream) */
19700c16b537SWarner Losh         endSignal = BITv07_reloadDStream(&bitD1) | BITv07_reloadDStream(&bitD2) | BITv07_reloadDStream(&bitD3) | BITv07_reloadDStream(&bitD4);
19710c16b537SWarner Losh         for ( ; (endSignal==BITv07_DStream_unfinished) && (op4<(oend-7)) ; ) {
19720c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX2_2(op1, &bitD1);
19730c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX2_2(op2, &bitD2);
19740c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX2_2(op3, &bitD3);
19750c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX2_2(op4, &bitD4);
19760c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX2_1(op1, &bitD1);
19770c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX2_1(op2, &bitD2);
19780c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX2_1(op3, &bitD3);
19790c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX2_1(op4, &bitD4);
19800c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX2_2(op1, &bitD1);
19810c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX2_2(op2, &bitD2);
19820c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX2_2(op3, &bitD3);
19830c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX2_2(op4, &bitD4);
19840c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX2_0(op1, &bitD1);
19850c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX2_0(op2, &bitD2);
19860c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX2_0(op3, &bitD3);
19870c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX2_0(op4, &bitD4);
19880c16b537SWarner Losh             endSignal = BITv07_reloadDStream(&bitD1) | BITv07_reloadDStream(&bitD2) | BITv07_reloadDStream(&bitD3) | BITv07_reloadDStream(&bitD4);
19890c16b537SWarner Losh         }
19900c16b537SWarner Losh 
19910c16b537SWarner Losh         /* check corruption */
19920c16b537SWarner Losh         if (op1 > opStart2) return ERROR(corruption_detected);
19930c16b537SWarner Losh         if (op2 > opStart3) return ERROR(corruption_detected);
19940c16b537SWarner Losh         if (op3 > opStart4) return ERROR(corruption_detected);
19950c16b537SWarner Losh         /* note : op4 supposed already verified within main loop */
19960c16b537SWarner Losh 
19970c16b537SWarner Losh         /* finish bitStreams one by one */
19980c16b537SWarner Losh         HUFv07_decodeStreamX2(op1, &bitD1, opStart2, dt, dtLog);
19990c16b537SWarner Losh         HUFv07_decodeStreamX2(op2, &bitD2, opStart3, dt, dtLog);
20000c16b537SWarner Losh         HUFv07_decodeStreamX2(op3, &bitD3, opStart4, dt, dtLog);
20010c16b537SWarner Losh         HUFv07_decodeStreamX2(op4, &bitD4, oend,     dt, dtLog);
20020c16b537SWarner Losh 
20030c16b537SWarner Losh         /* check */
20040c16b537SWarner Losh         endSignal = BITv07_endOfDStream(&bitD1) & BITv07_endOfDStream(&bitD2) & BITv07_endOfDStream(&bitD3) & BITv07_endOfDStream(&bitD4);
20050c16b537SWarner Losh         if (!endSignal) return ERROR(corruption_detected);
20060c16b537SWarner Losh 
20070c16b537SWarner Losh         /* decoded size */
20080c16b537SWarner Losh         return dstSize;
20090c16b537SWarner Losh     }
20100c16b537SWarner Losh }
20110c16b537SWarner Losh 
20120c16b537SWarner Losh 
HUFv07_decompress4X2_usingDTable(void * dst,size_t dstSize,const void * cSrc,size_t cSrcSize,const HUFv07_DTable * DTable)20130c16b537SWarner Losh size_t HUFv07_decompress4X2_usingDTable(
20140c16b537SWarner Losh           void* dst,  size_t dstSize,
20150c16b537SWarner Losh     const void* cSrc, size_t cSrcSize,
20160c16b537SWarner Losh     const HUFv07_DTable* DTable)
20170c16b537SWarner Losh {
20180c16b537SWarner Losh     DTableDesc dtd = HUFv07_getDTableDesc(DTable);
20190c16b537SWarner Losh     if (dtd.tableType != 0) return ERROR(GENERIC);
20200c16b537SWarner Losh     return HUFv07_decompress4X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable);
20210c16b537SWarner Losh }
20220c16b537SWarner Losh 
20230c16b537SWarner Losh 
HUFv07_decompress4X2_DCtx(HUFv07_DTable * dctx,void * dst,size_t dstSize,const void * cSrc,size_t cSrcSize)20240c16b537SWarner Losh size_t HUFv07_decompress4X2_DCtx (HUFv07_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
20250c16b537SWarner Losh {
20260c16b537SWarner Losh     const BYTE* ip = (const BYTE*) cSrc;
20270c16b537SWarner Losh 
20280c16b537SWarner Losh     size_t const hSize = HUFv07_readDTableX2 (dctx, cSrc, cSrcSize);
20290c16b537SWarner Losh     if (HUFv07_isError(hSize)) return hSize;
20300c16b537SWarner Losh     if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
20310c16b537SWarner Losh     ip += hSize; cSrcSize -= hSize;
20320c16b537SWarner Losh 
20330c16b537SWarner Losh     return HUFv07_decompress4X2_usingDTable_internal (dst, dstSize, ip, cSrcSize, dctx);
20340c16b537SWarner Losh }
20350c16b537SWarner Losh 
HUFv07_decompress4X2(void * dst,size_t dstSize,const void * cSrc,size_t cSrcSize)20360c16b537SWarner Losh size_t HUFv07_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
20370c16b537SWarner Losh {
20380c16b537SWarner Losh     HUFv07_CREATE_STATIC_DTABLEX2(DTable, HUFv07_TABLELOG_MAX);
20390c16b537SWarner Losh     return HUFv07_decompress4X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);
20400c16b537SWarner Losh }
20410c16b537SWarner Losh 
20420c16b537SWarner Losh 
20430c16b537SWarner Losh /* *************************/
20440c16b537SWarner Losh /* double-symbols decoding */
20450c16b537SWarner Losh /* *************************/
20460c16b537SWarner Losh typedef struct { U16 sequence; BYTE nbBits; BYTE length; } HUFv07_DEltX4;  /* double-symbols decoding */
20470c16b537SWarner Losh 
20480c16b537SWarner Losh typedef struct { BYTE symbol; BYTE weight; } sortedSymbol_t;
20490c16b537SWarner Losh 
HUFv07_fillDTableX4Level2(HUFv07_DEltX4 * DTable,U32 sizeLog,const U32 consumed,const U32 * rankValOrigin,const int minWeight,const sortedSymbol_t * sortedSymbols,const U32 sortedListSize,U32 nbBitsBaseline,U16 baseSeq)20500c16b537SWarner Losh static void HUFv07_fillDTableX4Level2(HUFv07_DEltX4* DTable, U32 sizeLog, const U32 consumed,
20510c16b537SWarner Losh                            const U32* rankValOrigin, const int minWeight,
20520c16b537SWarner Losh                            const sortedSymbol_t* sortedSymbols, const U32 sortedListSize,
20530c16b537SWarner Losh                            U32 nbBitsBaseline, U16 baseSeq)
20540c16b537SWarner Losh {
20550c16b537SWarner Losh     HUFv07_DEltX4 DElt;
20560c16b537SWarner Losh     U32 rankVal[HUFv07_TABLELOG_ABSOLUTEMAX + 1];
20570c16b537SWarner Losh 
20580c16b537SWarner Losh     /* get pre-calculated rankVal */
20590c16b537SWarner Losh     memcpy(rankVal, rankValOrigin, sizeof(rankVal));
20600c16b537SWarner Losh 
20610c16b537SWarner Losh     /* fill skipped values */
20620c16b537SWarner Losh     if (minWeight>1) {
20630c16b537SWarner Losh         U32 i, skipSize = rankVal[minWeight];
20640c16b537SWarner Losh         MEM_writeLE16(&(DElt.sequence), baseSeq);
20650c16b537SWarner Losh         DElt.nbBits   = (BYTE)(consumed);
20660c16b537SWarner Losh         DElt.length   = 1;
20670c16b537SWarner Losh         for (i = 0; i < skipSize; i++)
20680c16b537SWarner Losh             DTable[i] = DElt;
20690c16b537SWarner Losh     }
20700c16b537SWarner Losh 
20710c16b537SWarner Losh     /* fill DTable */
20720c16b537SWarner Losh     { U32 s; for (s=0; s<sortedListSize; s++) {   /* note : sortedSymbols already skipped */
20730c16b537SWarner Losh         const U32 symbol = sortedSymbols[s].symbol;
20740c16b537SWarner Losh         const U32 weight = sortedSymbols[s].weight;
20750c16b537SWarner Losh         const U32 nbBits = nbBitsBaseline - weight;
20760c16b537SWarner Losh         const U32 length = 1 << (sizeLog-nbBits);
20770c16b537SWarner Losh         const U32 start = rankVal[weight];
20780c16b537SWarner Losh         U32 i = start;
20790c16b537SWarner Losh         const U32 end = start + length;
20800c16b537SWarner Losh 
20810c16b537SWarner Losh         MEM_writeLE16(&(DElt.sequence), (U16)(baseSeq + (symbol << 8)));
20820c16b537SWarner Losh         DElt.nbBits = (BYTE)(nbBits + consumed);
20830c16b537SWarner Losh         DElt.length = 2;
20840c16b537SWarner Losh         do { DTable[i++] = DElt; } while (i<end);   /* since length >= 1 */
20850c16b537SWarner Losh 
20860c16b537SWarner Losh         rankVal[weight] += length;
20870c16b537SWarner Losh     }}
20880c16b537SWarner Losh }
20890c16b537SWarner Losh 
20900c16b537SWarner Losh typedef U32 rankVal_t[HUFv07_TABLELOG_ABSOLUTEMAX][HUFv07_TABLELOG_ABSOLUTEMAX + 1];
20910c16b537SWarner Losh 
HUFv07_fillDTableX4(HUFv07_DEltX4 * DTable,const U32 targetLog,const sortedSymbol_t * sortedList,const U32 sortedListSize,const U32 * rankStart,rankVal_t rankValOrigin,const U32 maxWeight,const U32 nbBitsBaseline)20920c16b537SWarner Losh static void HUFv07_fillDTableX4(HUFv07_DEltX4* DTable, const U32 targetLog,
20930c16b537SWarner Losh                            const sortedSymbol_t* sortedList, const U32 sortedListSize,
20940c16b537SWarner Losh                            const U32* rankStart, rankVal_t rankValOrigin, const U32 maxWeight,
20950c16b537SWarner Losh                            const U32 nbBitsBaseline)
20960c16b537SWarner Losh {
20970c16b537SWarner Losh     U32 rankVal[HUFv07_TABLELOG_ABSOLUTEMAX + 1];
20980c16b537SWarner Losh     const int scaleLog = nbBitsBaseline - targetLog;   /* note : targetLog >= srcLog, hence scaleLog <= 1 */
20990c16b537SWarner Losh     const U32 minBits  = nbBitsBaseline - maxWeight;
21000c16b537SWarner Losh     U32 s;
21010c16b537SWarner Losh 
21020c16b537SWarner Losh     memcpy(rankVal, rankValOrigin, sizeof(rankVal));
21030c16b537SWarner Losh 
21040c16b537SWarner Losh     /* fill DTable */
21050c16b537SWarner Losh     for (s=0; s<sortedListSize; s++) {
21060c16b537SWarner Losh         const U16 symbol = sortedList[s].symbol;
21070c16b537SWarner Losh         const U32 weight = sortedList[s].weight;
21080c16b537SWarner Losh         const U32 nbBits = nbBitsBaseline - weight;
21090c16b537SWarner Losh         const U32 start = rankVal[weight];
21100c16b537SWarner Losh         const U32 length = 1 << (targetLog-nbBits);
21110c16b537SWarner Losh 
21120c16b537SWarner Losh         if (targetLog-nbBits >= minBits) {   /* enough room for a second symbol */
21130c16b537SWarner Losh             U32 sortedRank;
21140c16b537SWarner Losh             int minWeight = nbBits + scaleLog;
21150c16b537SWarner Losh             if (minWeight < 1) minWeight = 1;
21160c16b537SWarner Losh             sortedRank = rankStart[minWeight];
21170c16b537SWarner Losh             HUFv07_fillDTableX4Level2(DTable+start, targetLog-nbBits, nbBits,
21180c16b537SWarner Losh                            rankValOrigin[nbBits], minWeight,
21190c16b537SWarner Losh                            sortedList+sortedRank, sortedListSize-sortedRank,
21200c16b537SWarner Losh                            nbBitsBaseline, symbol);
21210c16b537SWarner Losh         } else {
21220c16b537SWarner Losh             HUFv07_DEltX4 DElt;
21230c16b537SWarner Losh             MEM_writeLE16(&(DElt.sequence), symbol);
21240c16b537SWarner Losh             DElt.nbBits = (BYTE)(nbBits);
21250c16b537SWarner Losh             DElt.length = 1;
21260c16b537SWarner Losh             {   U32 u;
21270c16b537SWarner Losh                 const U32 end = start + length;
21280c16b537SWarner Losh                 for (u = start; u < end; u++) DTable[u] = DElt;
21290c16b537SWarner Losh         }   }
21300c16b537SWarner Losh         rankVal[weight] += length;
21310c16b537SWarner Losh     }
21320c16b537SWarner Losh }
21330c16b537SWarner Losh 
HUFv07_readDTableX4(HUFv07_DTable * DTable,const void * src,size_t srcSize)21340c16b537SWarner Losh size_t HUFv07_readDTableX4 (HUFv07_DTable* DTable, const void* src, size_t srcSize)
21350c16b537SWarner Losh {
21360c16b537SWarner Losh     BYTE weightList[HUFv07_SYMBOLVALUE_MAX + 1];
21370c16b537SWarner Losh     sortedSymbol_t sortedSymbol[HUFv07_SYMBOLVALUE_MAX + 1];
21380c16b537SWarner Losh     U32 rankStats[HUFv07_TABLELOG_ABSOLUTEMAX + 1] = { 0 };
21390c16b537SWarner Losh     U32 rankStart0[HUFv07_TABLELOG_ABSOLUTEMAX + 2] = { 0 };
21400c16b537SWarner Losh     U32* const rankStart = rankStart0+1;
21410c16b537SWarner Losh     rankVal_t rankVal;
21420c16b537SWarner Losh     U32 tableLog, maxW, sizeOfSort, nbSymbols;
21430c16b537SWarner Losh     DTableDesc dtd = HUFv07_getDTableDesc(DTable);
21440c16b537SWarner Losh     U32 const maxTableLog = dtd.maxTableLog;
21450c16b537SWarner Losh     size_t iSize;
21460c16b537SWarner Losh     void* dtPtr = DTable+1;   /* force compiler to avoid strict-aliasing */
21470c16b537SWarner Losh     HUFv07_DEltX4* const dt = (HUFv07_DEltX4*)dtPtr;
21480c16b537SWarner Losh 
21490c16b537SWarner Losh     HUFv07_STATIC_ASSERT(sizeof(HUFv07_DEltX4) == sizeof(HUFv07_DTable));   /* if compilation fails here, assertion is false */
21500c16b537SWarner Losh     if (maxTableLog > HUFv07_TABLELOG_ABSOLUTEMAX) return ERROR(tableLog_tooLarge);
215137f1f268SConrad Meyer     /* memset(weightList, 0, sizeof(weightList)); */   /* is not necessary, even though some analyzer complain ... */
21520c16b537SWarner Losh 
21530c16b537SWarner Losh     iSize = HUFv07_readStats(weightList, HUFv07_SYMBOLVALUE_MAX + 1, rankStats, &nbSymbols, &tableLog, src, srcSize);
21540c16b537SWarner Losh     if (HUFv07_isError(iSize)) return iSize;
21550c16b537SWarner Losh 
21560c16b537SWarner Losh     /* check result */
21570c16b537SWarner Losh     if (tableLog > maxTableLog) return ERROR(tableLog_tooLarge);   /* DTable can't fit code depth */
21580c16b537SWarner Losh 
21590c16b537SWarner Losh     /* find maxWeight */
21600c16b537SWarner Losh     for (maxW = tableLog; rankStats[maxW]==0; maxW--) {}  /* necessarily finds a solution before 0 */
21610c16b537SWarner Losh 
21620c16b537SWarner Losh     /* Get start index of each weight */
21630c16b537SWarner Losh     {   U32 w, nextRankStart = 0;
21640c16b537SWarner Losh         for (w=1; w<maxW+1; w++) {
21650c16b537SWarner Losh             U32 current = nextRankStart;
21660c16b537SWarner Losh             nextRankStart += rankStats[w];
21670c16b537SWarner Losh             rankStart[w] = current;
21680c16b537SWarner Losh         }
21690c16b537SWarner Losh         rankStart[0] = nextRankStart;   /* put all 0w symbols at the end of sorted list*/
21700c16b537SWarner Losh         sizeOfSort = nextRankStart;
21710c16b537SWarner Losh     }
21720c16b537SWarner Losh 
21730c16b537SWarner Losh     /* sort symbols by weight */
21740c16b537SWarner Losh     {   U32 s;
21750c16b537SWarner Losh         for (s=0; s<nbSymbols; s++) {
21760c16b537SWarner Losh             U32 const w = weightList[s];
21770c16b537SWarner Losh             U32 const r = rankStart[w]++;
21780c16b537SWarner Losh             sortedSymbol[r].symbol = (BYTE)s;
21790c16b537SWarner Losh             sortedSymbol[r].weight = (BYTE)w;
21800c16b537SWarner Losh         }
21810c16b537SWarner Losh         rankStart[0] = 0;   /* forget 0w symbols; this is beginning of weight(1) */
21820c16b537SWarner Losh     }
21830c16b537SWarner Losh 
21840c16b537SWarner Losh     /* Build rankVal */
21850c16b537SWarner Losh     {   U32* const rankVal0 = rankVal[0];
21860c16b537SWarner Losh         {   int const rescale = (maxTableLog-tableLog) - 1;   /* tableLog <= maxTableLog */
21870c16b537SWarner Losh             U32 nextRankVal = 0;
21880c16b537SWarner Losh             U32 w;
21890c16b537SWarner Losh             for (w=1; w<maxW+1; w++) {
21900c16b537SWarner Losh                 U32 current = nextRankVal;
21910c16b537SWarner Losh                 nextRankVal += rankStats[w] << (w+rescale);
21920c16b537SWarner Losh                 rankVal0[w] = current;
21930c16b537SWarner Losh         }   }
21940c16b537SWarner Losh         {   U32 const minBits = tableLog+1 - maxW;
21950c16b537SWarner Losh             U32 consumed;
21960c16b537SWarner Losh             for (consumed = minBits; consumed < maxTableLog - minBits + 1; consumed++) {
21970c16b537SWarner Losh                 U32* const rankValPtr = rankVal[consumed];
21980c16b537SWarner Losh                 U32 w;
21990c16b537SWarner Losh                 for (w = 1; w < maxW+1; w++) {
22000c16b537SWarner Losh                     rankValPtr[w] = rankVal0[w] >> consumed;
22010c16b537SWarner Losh     }   }   }   }
22020c16b537SWarner Losh 
22030c16b537SWarner Losh     HUFv07_fillDTableX4(dt, maxTableLog,
22040c16b537SWarner Losh                    sortedSymbol, sizeOfSort,
22050c16b537SWarner Losh                    rankStart0, rankVal, maxW,
22060c16b537SWarner Losh                    tableLog+1);
22070c16b537SWarner Losh 
22080c16b537SWarner Losh     dtd.tableLog = (BYTE)maxTableLog;
22090c16b537SWarner Losh     dtd.tableType = 1;
22100c16b537SWarner Losh     memcpy(DTable, &dtd, sizeof(dtd));
22110c16b537SWarner Losh     return iSize;
22120c16b537SWarner Losh }
22130c16b537SWarner Losh 
22140c16b537SWarner Losh 
HUFv07_decodeSymbolX4(void * op,BITv07_DStream_t * DStream,const HUFv07_DEltX4 * dt,const U32 dtLog)22150c16b537SWarner Losh static U32 HUFv07_decodeSymbolX4(void* op, BITv07_DStream_t* DStream, const HUFv07_DEltX4* dt, const U32 dtLog)
22160c16b537SWarner Losh {
22170c16b537SWarner Losh     const size_t val = BITv07_lookBitsFast(DStream, dtLog);   /* note : dtLog >= 1 */
22180c16b537SWarner Losh     memcpy(op, dt+val, 2);
22190c16b537SWarner Losh     BITv07_skipBits(DStream, dt[val].nbBits);
22200c16b537SWarner Losh     return dt[val].length;
22210c16b537SWarner Losh }
22220c16b537SWarner Losh 
HUFv07_decodeLastSymbolX4(void * op,BITv07_DStream_t * DStream,const HUFv07_DEltX4 * dt,const U32 dtLog)22230c16b537SWarner Losh static U32 HUFv07_decodeLastSymbolX4(void* op, BITv07_DStream_t* DStream, const HUFv07_DEltX4* dt, const U32 dtLog)
22240c16b537SWarner Losh {
22250c16b537SWarner Losh     const size_t val = BITv07_lookBitsFast(DStream, dtLog);   /* note : dtLog >= 1 */
22260c16b537SWarner Losh     memcpy(op, dt+val, 1);
22270c16b537SWarner Losh     if (dt[val].length==1) BITv07_skipBits(DStream, dt[val].nbBits);
22280c16b537SWarner Losh     else {
22290c16b537SWarner Losh         if (DStream->bitsConsumed < (sizeof(DStream->bitContainer)*8)) {
22300c16b537SWarner Losh             BITv07_skipBits(DStream, dt[val].nbBits);
22310c16b537SWarner Losh             if (DStream->bitsConsumed > (sizeof(DStream->bitContainer)*8))
22320c16b537SWarner Losh                 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 */
22330c16b537SWarner Losh     }   }
22340c16b537SWarner Losh     return 1;
22350c16b537SWarner Losh }
22360c16b537SWarner Losh 
22370c16b537SWarner Losh 
22380c16b537SWarner Losh #define HUFv07_DECODE_SYMBOLX4_0(ptr, DStreamPtr) \
22390c16b537SWarner Losh     ptr += HUFv07_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
22400c16b537SWarner Losh 
22410c16b537SWarner Losh #define HUFv07_DECODE_SYMBOLX4_1(ptr, DStreamPtr) \
22420c16b537SWarner Losh     if (MEM_64bits() || (HUFv07_TABLELOG_MAX<=12)) \
22430c16b537SWarner Losh         ptr += HUFv07_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
22440c16b537SWarner Losh 
22450c16b537SWarner Losh #define HUFv07_DECODE_SYMBOLX4_2(ptr, DStreamPtr) \
22460c16b537SWarner Losh     if (MEM_64bits()) \
22470c16b537SWarner Losh         ptr += HUFv07_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
22480c16b537SWarner Losh 
HUFv07_decodeStreamX4(BYTE * p,BITv07_DStream_t * bitDPtr,BYTE * const pEnd,const HUFv07_DEltX4 * const dt,const U32 dtLog)22490c16b537SWarner Losh static inline size_t HUFv07_decodeStreamX4(BYTE* p, BITv07_DStream_t* bitDPtr, BYTE* const pEnd, const HUFv07_DEltX4* const dt, const U32 dtLog)
22500c16b537SWarner Losh {
22510c16b537SWarner Losh     BYTE* const pStart = p;
22520c16b537SWarner Losh 
22530c16b537SWarner Losh     /* up to 8 symbols at a time */
22540c16b537SWarner Losh     while ((BITv07_reloadDStream(bitDPtr) == BITv07_DStream_unfinished) && (p < pEnd-7)) {
22550c16b537SWarner Losh         HUFv07_DECODE_SYMBOLX4_2(p, bitDPtr);
22560c16b537SWarner Losh         HUFv07_DECODE_SYMBOLX4_1(p, bitDPtr);
22570c16b537SWarner Losh         HUFv07_DECODE_SYMBOLX4_2(p, bitDPtr);
22580c16b537SWarner Losh         HUFv07_DECODE_SYMBOLX4_0(p, bitDPtr);
22590c16b537SWarner Losh     }
22600c16b537SWarner Losh 
22610c16b537SWarner Losh     /* closer to end : up to 2 symbols at a time */
22620c16b537SWarner Losh     while ((BITv07_reloadDStream(bitDPtr) == BITv07_DStream_unfinished) && (p <= pEnd-2))
22630c16b537SWarner Losh         HUFv07_DECODE_SYMBOLX4_0(p, bitDPtr);
22640c16b537SWarner Losh 
22650c16b537SWarner Losh     while (p <= pEnd-2)
22660c16b537SWarner Losh         HUFv07_DECODE_SYMBOLX4_0(p, bitDPtr);   /* no need to reload : reached the end of DStream */
22670c16b537SWarner Losh 
22680c16b537SWarner Losh     if (p < pEnd)
22690c16b537SWarner Losh         p += HUFv07_decodeLastSymbolX4(p, bitDPtr, dt, dtLog);
22700c16b537SWarner Losh 
22710c16b537SWarner Losh     return p-pStart;
22720c16b537SWarner Losh }
22730c16b537SWarner Losh 
22740c16b537SWarner Losh 
HUFv07_decompress1X4_usingDTable_internal(void * dst,size_t dstSize,const void * cSrc,size_t cSrcSize,const HUFv07_DTable * DTable)22750c16b537SWarner Losh static size_t HUFv07_decompress1X4_usingDTable_internal(
22760c16b537SWarner Losh           void* dst,  size_t dstSize,
22770c16b537SWarner Losh     const void* cSrc, size_t cSrcSize,
22780c16b537SWarner Losh     const HUFv07_DTable* DTable)
22790c16b537SWarner Losh {
22800c16b537SWarner Losh     BITv07_DStream_t bitD;
22810c16b537SWarner Losh 
22820c16b537SWarner Losh     /* Init */
22830c16b537SWarner Losh     {   size_t const errorCode = BITv07_initDStream(&bitD, cSrc, cSrcSize);
22840c16b537SWarner Losh         if (HUFv07_isError(errorCode)) return errorCode;
22850c16b537SWarner Losh     }
22860c16b537SWarner Losh 
22870c16b537SWarner Losh     /* decode */
22880c16b537SWarner Losh     {   BYTE* const ostart = (BYTE*) dst;
22890c16b537SWarner Losh         BYTE* const oend = ostart + dstSize;
22900c16b537SWarner Losh         const void* const dtPtr = DTable+1;   /* force compiler to not use strict-aliasing */
22910c16b537SWarner Losh         const HUFv07_DEltX4* const dt = (const HUFv07_DEltX4*)dtPtr;
22920c16b537SWarner Losh         DTableDesc const dtd = HUFv07_getDTableDesc(DTable);
22930c16b537SWarner Losh         HUFv07_decodeStreamX4(ostart, &bitD, oend, dt, dtd.tableLog);
22940c16b537SWarner Losh     }
22950c16b537SWarner Losh 
22960c16b537SWarner Losh     /* check */
22970c16b537SWarner Losh     if (!BITv07_endOfDStream(&bitD)) return ERROR(corruption_detected);
22980c16b537SWarner Losh 
22990c16b537SWarner Losh     /* decoded size */
23000c16b537SWarner Losh     return dstSize;
23010c16b537SWarner Losh }
23020c16b537SWarner Losh 
HUFv07_decompress1X4_usingDTable(void * dst,size_t dstSize,const void * cSrc,size_t cSrcSize,const HUFv07_DTable * DTable)23030c16b537SWarner Losh size_t HUFv07_decompress1X4_usingDTable(
23040c16b537SWarner Losh           void* dst,  size_t dstSize,
23050c16b537SWarner Losh     const void* cSrc, size_t cSrcSize,
23060c16b537SWarner Losh     const HUFv07_DTable* DTable)
23070c16b537SWarner Losh {
23080c16b537SWarner Losh     DTableDesc dtd = HUFv07_getDTableDesc(DTable);
23090c16b537SWarner Losh     if (dtd.tableType != 1) return ERROR(GENERIC);
23100c16b537SWarner Losh     return HUFv07_decompress1X4_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable);
23110c16b537SWarner Losh }
23120c16b537SWarner Losh 
HUFv07_decompress1X4_DCtx(HUFv07_DTable * DCtx,void * dst,size_t dstSize,const void * cSrc,size_t cSrcSize)23130c16b537SWarner Losh size_t HUFv07_decompress1X4_DCtx (HUFv07_DTable* DCtx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
23140c16b537SWarner Losh {
23150c16b537SWarner Losh     const BYTE* ip = (const BYTE*) cSrc;
23160c16b537SWarner Losh 
23170c16b537SWarner Losh     size_t const hSize = HUFv07_readDTableX4 (DCtx, cSrc, cSrcSize);
23180c16b537SWarner Losh     if (HUFv07_isError(hSize)) return hSize;
23190c16b537SWarner Losh     if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
23200c16b537SWarner Losh     ip += hSize; cSrcSize -= hSize;
23210c16b537SWarner Losh 
23220c16b537SWarner Losh     return HUFv07_decompress1X4_usingDTable_internal (dst, dstSize, ip, cSrcSize, DCtx);
23230c16b537SWarner Losh }
23240c16b537SWarner Losh 
HUFv07_decompress1X4(void * dst,size_t dstSize,const void * cSrc,size_t cSrcSize)23250c16b537SWarner Losh size_t HUFv07_decompress1X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
23260c16b537SWarner Losh {
23270c16b537SWarner Losh     HUFv07_CREATE_STATIC_DTABLEX4(DTable, HUFv07_TABLELOG_MAX);
23280c16b537SWarner Losh     return HUFv07_decompress1X4_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);
23290c16b537SWarner Losh }
23300c16b537SWarner Losh 
HUFv07_decompress4X4_usingDTable_internal(void * dst,size_t dstSize,const void * cSrc,size_t cSrcSize,const HUFv07_DTable * DTable)23310c16b537SWarner Losh static size_t HUFv07_decompress4X4_usingDTable_internal(
23320c16b537SWarner Losh           void* dst,  size_t dstSize,
23330c16b537SWarner Losh     const void* cSrc, size_t cSrcSize,
23340c16b537SWarner Losh     const HUFv07_DTable* DTable)
23350c16b537SWarner Losh {
23360c16b537SWarner Losh     if (cSrcSize < 10) return ERROR(corruption_detected);   /* strict minimum : jump table + 1 byte per stream */
23370c16b537SWarner Losh 
23380c16b537SWarner Losh     {   const BYTE* const istart = (const BYTE*) cSrc;
23390c16b537SWarner Losh         BYTE* const ostart = (BYTE*) dst;
23400c16b537SWarner Losh         BYTE* const oend = ostart + dstSize;
23410c16b537SWarner Losh         const void* const dtPtr = DTable+1;
23420c16b537SWarner Losh         const HUFv07_DEltX4* const dt = (const HUFv07_DEltX4*)dtPtr;
23430c16b537SWarner Losh 
23440c16b537SWarner Losh         /* Init */
23450c16b537SWarner Losh         BITv07_DStream_t bitD1;
23460c16b537SWarner Losh         BITv07_DStream_t bitD2;
23470c16b537SWarner Losh         BITv07_DStream_t bitD3;
23480c16b537SWarner Losh         BITv07_DStream_t bitD4;
23490c16b537SWarner Losh         size_t const length1 = MEM_readLE16(istart);
23500c16b537SWarner Losh         size_t const length2 = MEM_readLE16(istart+2);
23510c16b537SWarner Losh         size_t const length3 = MEM_readLE16(istart+4);
23520c16b537SWarner Losh         size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6);
23530c16b537SWarner Losh         const BYTE* const istart1 = istart + 6;  /* jumpTable */
23540c16b537SWarner Losh         const BYTE* const istart2 = istart1 + length1;
23550c16b537SWarner Losh         const BYTE* const istart3 = istart2 + length2;
23560c16b537SWarner Losh         const BYTE* const istart4 = istart3 + length3;
23570c16b537SWarner Losh         size_t const segmentSize = (dstSize+3) / 4;
23580c16b537SWarner Losh         BYTE* const opStart2 = ostart + segmentSize;
23590c16b537SWarner Losh         BYTE* const opStart3 = opStart2 + segmentSize;
23600c16b537SWarner Losh         BYTE* const opStart4 = opStart3 + segmentSize;
23610c16b537SWarner Losh         BYTE* op1 = ostart;
23620c16b537SWarner Losh         BYTE* op2 = opStart2;
23630c16b537SWarner Losh         BYTE* op3 = opStart3;
23640c16b537SWarner Losh         BYTE* op4 = opStart4;
23650c16b537SWarner Losh         U32 endSignal;
23660c16b537SWarner Losh         DTableDesc const dtd = HUFv07_getDTableDesc(DTable);
23670c16b537SWarner Losh         U32 const dtLog = dtd.tableLog;
23680c16b537SWarner Losh 
23690c16b537SWarner Losh         if (length4 > cSrcSize) return ERROR(corruption_detected);   /* overflow */
23700c16b537SWarner Losh         { size_t const errorCode = BITv07_initDStream(&bitD1, istart1, length1);
23710c16b537SWarner Losh           if (HUFv07_isError(errorCode)) return errorCode; }
23720c16b537SWarner Losh         { size_t const errorCode = BITv07_initDStream(&bitD2, istart2, length2);
23730c16b537SWarner Losh           if (HUFv07_isError(errorCode)) return errorCode; }
23740c16b537SWarner Losh         { size_t const errorCode = BITv07_initDStream(&bitD3, istart3, length3);
23750c16b537SWarner Losh           if (HUFv07_isError(errorCode)) return errorCode; }
23760c16b537SWarner Losh         { size_t const errorCode = BITv07_initDStream(&bitD4, istart4, length4);
23770c16b537SWarner Losh           if (HUFv07_isError(errorCode)) return errorCode; }
23780c16b537SWarner Losh 
23790c16b537SWarner Losh         /* 16-32 symbols per loop (4-8 symbols per stream) */
23800c16b537SWarner Losh         endSignal = BITv07_reloadDStream(&bitD1) | BITv07_reloadDStream(&bitD2) | BITv07_reloadDStream(&bitD3) | BITv07_reloadDStream(&bitD4);
23810c16b537SWarner Losh         for ( ; (endSignal==BITv07_DStream_unfinished) && (op4<(oend-7)) ; ) {
23820c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX4_2(op1, &bitD1);
23830c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX4_2(op2, &bitD2);
23840c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX4_2(op3, &bitD3);
23850c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX4_2(op4, &bitD4);
23860c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX4_1(op1, &bitD1);
23870c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX4_1(op2, &bitD2);
23880c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX4_1(op3, &bitD3);
23890c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX4_1(op4, &bitD4);
23900c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX4_2(op1, &bitD1);
23910c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX4_2(op2, &bitD2);
23920c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX4_2(op3, &bitD3);
23930c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX4_2(op4, &bitD4);
23940c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX4_0(op1, &bitD1);
23950c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX4_0(op2, &bitD2);
23960c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX4_0(op3, &bitD3);
23970c16b537SWarner Losh             HUFv07_DECODE_SYMBOLX4_0(op4, &bitD4);
23980c16b537SWarner Losh 
23990c16b537SWarner Losh             endSignal = BITv07_reloadDStream(&bitD1) | BITv07_reloadDStream(&bitD2) | BITv07_reloadDStream(&bitD3) | BITv07_reloadDStream(&bitD4);
24000c16b537SWarner Losh         }
24010c16b537SWarner Losh 
24020c16b537SWarner Losh         /* check corruption */
24030c16b537SWarner Losh         if (op1 > opStart2) return ERROR(corruption_detected);
24040c16b537SWarner Losh         if (op2 > opStart3) return ERROR(corruption_detected);
24050c16b537SWarner Losh         if (op3 > opStart4) return ERROR(corruption_detected);
24060c16b537SWarner Losh         /* note : op4 supposed already verified within main loop */
24070c16b537SWarner Losh 
24080c16b537SWarner Losh         /* finish bitStreams one by one */
24090c16b537SWarner Losh         HUFv07_decodeStreamX4(op1, &bitD1, opStart2, dt, dtLog);
24100c16b537SWarner Losh         HUFv07_decodeStreamX4(op2, &bitD2, opStart3, dt, dtLog);
24110c16b537SWarner Losh         HUFv07_decodeStreamX4(op3, &bitD3, opStart4, dt, dtLog);
24120c16b537SWarner Losh         HUFv07_decodeStreamX4(op4, &bitD4, oend,     dt, dtLog);
24130c16b537SWarner Losh 
24140c16b537SWarner Losh         /* check */
24150c16b537SWarner Losh         { U32 const endCheck = BITv07_endOfDStream(&bitD1) & BITv07_endOfDStream(&bitD2) & BITv07_endOfDStream(&bitD3) & BITv07_endOfDStream(&bitD4);
24160c16b537SWarner Losh           if (!endCheck) return ERROR(corruption_detected); }
24170c16b537SWarner Losh 
24180c16b537SWarner Losh         /* decoded size */
24190c16b537SWarner Losh         return dstSize;
24200c16b537SWarner Losh     }
24210c16b537SWarner Losh }
24220c16b537SWarner Losh 
24230c16b537SWarner Losh 
HUFv07_decompress4X4_usingDTable(void * dst,size_t dstSize,const void * cSrc,size_t cSrcSize,const HUFv07_DTable * DTable)24240c16b537SWarner Losh size_t HUFv07_decompress4X4_usingDTable(
24250c16b537SWarner Losh           void* dst,  size_t dstSize,
24260c16b537SWarner Losh     const void* cSrc, size_t cSrcSize,
24270c16b537SWarner Losh     const HUFv07_DTable* DTable)
24280c16b537SWarner Losh {
24290c16b537SWarner Losh     DTableDesc dtd = HUFv07_getDTableDesc(DTable);
24300c16b537SWarner Losh     if (dtd.tableType != 1) return ERROR(GENERIC);
24310c16b537SWarner Losh     return HUFv07_decompress4X4_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable);
24320c16b537SWarner Losh }
24330c16b537SWarner Losh 
24340c16b537SWarner Losh 
HUFv07_decompress4X4_DCtx(HUFv07_DTable * dctx,void * dst,size_t dstSize,const void * cSrc,size_t cSrcSize)24350c16b537SWarner Losh size_t HUFv07_decompress4X4_DCtx (HUFv07_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
24360c16b537SWarner Losh {
24370c16b537SWarner Losh     const BYTE* ip = (const BYTE*) cSrc;
24380c16b537SWarner Losh 
24390c16b537SWarner Losh     size_t hSize = HUFv07_readDTableX4 (dctx, cSrc, cSrcSize);
24400c16b537SWarner Losh     if (HUFv07_isError(hSize)) return hSize;
24410c16b537SWarner Losh     if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
24420c16b537SWarner Losh     ip += hSize; cSrcSize -= hSize;
24430c16b537SWarner Losh 
24440c16b537SWarner Losh     return HUFv07_decompress4X4_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx);
24450c16b537SWarner Losh }
24460c16b537SWarner Losh 
HUFv07_decompress4X4(void * dst,size_t dstSize,const void * cSrc,size_t cSrcSize)24470c16b537SWarner Losh size_t HUFv07_decompress4X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
24480c16b537SWarner Losh {
24490c16b537SWarner Losh     HUFv07_CREATE_STATIC_DTABLEX4(DTable, HUFv07_TABLELOG_MAX);
24500c16b537SWarner Losh     return HUFv07_decompress4X4_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);
24510c16b537SWarner Losh }
24520c16b537SWarner Losh 
24530c16b537SWarner Losh 
24540c16b537SWarner Losh /* ********************************/
24550c16b537SWarner Losh /* Generic decompression selector */
24560c16b537SWarner Losh /* ********************************/
24570c16b537SWarner Losh 
HUFv07_decompress1X_usingDTable(void * dst,size_t maxDstSize,const void * cSrc,size_t cSrcSize,const HUFv07_DTable * DTable)24580c16b537SWarner Losh size_t HUFv07_decompress1X_usingDTable(void* dst, size_t maxDstSize,
24590c16b537SWarner Losh                                     const void* cSrc, size_t cSrcSize,
24600c16b537SWarner Losh                                     const HUFv07_DTable* DTable)
24610c16b537SWarner Losh {
24620c16b537SWarner Losh     DTableDesc const dtd = HUFv07_getDTableDesc(DTable);
24630c16b537SWarner Losh     return dtd.tableType ? HUFv07_decompress1X4_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable) :
24640c16b537SWarner Losh                            HUFv07_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable);
24650c16b537SWarner Losh }
24660c16b537SWarner Losh 
HUFv07_decompress4X_usingDTable(void * dst,size_t maxDstSize,const void * cSrc,size_t cSrcSize,const HUFv07_DTable * DTable)24670c16b537SWarner Losh size_t HUFv07_decompress4X_usingDTable(void* dst, size_t maxDstSize,
24680c16b537SWarner Losh                                     const void* cSrc, size_t cSrcSize,
24690c16b537SWarner Losh                                     const HUFv07_DTable* DTable)
24700c16b537SWarner Losh {
24710c16b537SWarner Losh     DTableDesc const dtd = HUFv07_getDTableDesc(DTable);
24720c16b537SWarner Losh     return dtd.tableType ? HUFv07_decompress4X4_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable) :
24730c16b537SWarner Losh                            HUFv07_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable);
24740c16b537SWarner Losh }
24750c16b537SWarner Losh 
24760c16b537SWarner Losh 
24770c16b537SWarner Losh typedef struct { U32 tableTime; U32 decode256Time; } algo_time_t;
24780c16b537SWarner Losh static const algo_time_t algoTime[16 /* Quantization */][3 /* single, double, quad */] =
24790c16b537SWarner Losh {
24800c16b537SWarner Losh     /* single, double, quad */
24810c16b537SWarner Losh     {{0,0}, {1,1}, {2,2}},  /* Q==0 : impossible */
24820c16b537SWarner Losh     {{0,0}, {1,1}, {2,2}},  /* Q==1 : impossible */
24830c16b537SWarner Losh     {{  38,130}, {1313, 74}, {2151, 38}},   /* Q == 2 : 12-18% */
24840c16b537SWarner Losh     {{ 448,128}, {1353, 74}, {2238, 41}},   /* Q == 3 : 18-25% */
24850c16b537SWarner Losh     {{ 556,128}, {1353, 74}, {2238, 47}},   /* Q == 4 : 25-32% */
24860c16b537SWarner Losh     {{ 714,128}, {1418, 74}, {2436, 53}},   /* Q == 5 : 32-38% */
24870c16b537SWarner Losh     {{ 883,128}, {1437, 74}, {2464, 61}},   /* Q == 6 : 38-44% */
24880c16b537SWarner Losh     {{ 897,128}, {1515, 75}, {2622, 68}},   /* Q == 7 : 44-50% */
24890c16b537SWarner Losh     {{ 926,128}, {1613, 75}, {2730, 75}},   /* Q == 8 : 50-56% */
24900c16b537SWarner Losh     {{ 947,128}, {1729, 77}, {3359, 77}},   /* Q == 9 : 56-62% */
24910c16b537SWarner Losh     {{1107,128}, {2083, 81}, {4006, 84}},   /* Q ==10 : 62-69% */
24920c16b537SWarner Losh     {{1177,128}, {2379, 87}, {4785, 88}},   /* Q ==11 : 69-75% */
24930c16b537SWarner Losh     {{1242,128}, {2415, 93}, {5155, 84}},   /* Q ==12 : 75-81% */
24940c16b537SWarner Losh     {{1349,128}, {2644,106}, {5260,106}},   /* Q ==13 : 81-87% */
24950c16b537SWarner Losh     {{1455,128}, {2422,124}, {4174,124}},   /* Q ==14 : 87-93% */
24960c16b537SWarner Losh     {{ 722,128}, {1891,145}, {1936,146}},   /* Q ==15 : 93-99% */
24970c16b537SWarner Losh };
24980c16b537SWarner Losh 
24990c16b537SWarner Losh /** HUFv07_selectDecoder() :
25000c16b537SWarner Losh *   Tells which decoder is likely to decode faster,
25010c16b537SWarner Losh *   based on a set of pre-determined metrics.
25020c16b537SWarner Losh *   @return : 0==HUFv07_decompress4X2, 1==HUFv07_decompress4X4 .
25030c16b537SWarner Losh *   Assumption : 0 < cSrcSize < dstSize <= 128 KB */
HUFv07_selectDecoder(size_t dstSize,size_t cSrcSize)25040c16b537SWarner Losh U32 HUFv07_selectDecoder (size_t dstSize, size_t cSrcSize)
25050c16b537SWarner Losh {
25060c16b537SWarner Losh     /* decoder timing evaluation */
25070c16b537SWarner Losh     U32 const Q = (U32)(cSrcSize * 16 / dstSize);   /* Q < 16 since dstSize > cSrcSize */
25080c16b537SWarner Losh     U32 const D256 = (U32)(dstSize >> 8);
25090c16b537SWarner Losh     U32 const DTime0 = algoTime[Q][0].tableTime + (algoTime[Q][0].decode256Time * D256);
25100c16b537SWarner Losh     U32 DTime1 = algoTime[Q][1].tableTime + (algoTime[Q][1].decode256Time * D256);
25110c16b537SWarner Losh     DTime1 += DTime1 >> 3;  /* advantage to algorithm using less memory, for cache eviction */
25120c16b537SWarner Losh 
25130c16b537SWarner Losh     return DTime1 < DTime0;
25140c16b537SWarner Losh }
25150c16b537SWarner Losh 
25160c16b537SWarner Losh 
25170c16b537SWarner Losh typedef size_t (*decompressionAlgo)(void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);
25180c16b537SWarner Losh 
HUFv07_decompress(void * dst,size_t dstSize,const void * cSrc,size_t cSrcSize)25190c16b537SWarner Losh size_t HUFv07_decompress (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
25200c16b537SWarner Losh {
25210c16b537SWarner Losh     static const decompressionAlgo decompress[2] = { HUFv07_decompress4X2, HUFv07_decompress4X4 };
25220c16b537SWarner Losh 
25230c16b537SWarner Losh     /* validation checks */
25240c16b537SWarner Losh     if (dstSize == 0) return ERROR(dstSize_tooSmall);
25250c16b537SWarner Losh     if (cSrcSize > dstSize) return ERROR(corruption_detected);   /* invalid */
25260c16b537SWarner Losh     if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; }   /* not compressed */
25270c16b537SWarner Losh     if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; }   /* RLE */
25280c16b537SWarner Losh 
25290c16b537SWarner Losh     {   U32 const algoNb = HUFv07_selectDecoder(dstSize, cSrcSize);
25300c16b537SWarner Losh         return decompress[algoNb](dst, dstSize, cSrc, cSrcSize);
25310c16b537SWarner Losh     }
25320c16b537SWarner Losh 
253337f1f268SConrad Meyer     /* return HUFv07_decompress4X2(dst, dstSize, cSrc, cSrcSize); */   /* multi-streams single-symbol decoding */
253437f1f268SConrad Meyer     /* return HUFv07_decompress4X4(dst, dstSize, cSrc, cSrcSize); */   /* multi-streams double-symbols decoding */
25350c16b537SWarner Losh }
25360c16b537SWarner Losh 
HUFv07_decompress4X_DCtx(HUFv07_DTable * dctx,void * dst,size_t dstSize,const void * cSrc,size_t cSrcSize)25370c16b537SWarner Losh size_t HUFv07_decompress4X_DCtx (HUFv07_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
25380c16b537SWarner Losh {
25390c16b537SWarner Losh     /* validation checks */
25400c16b537SWarner Losh     if (dstSize == 0) return ERROR(dstSize_tooSmall);
25410c16b537SWarner Losh     if (cSrcSize > dstSize) return ERROR(corruption_detected);   /* invalid */
25420c16b537SWarner Losh     if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; }   /* not compressed */
25430c16b537SWarner Losh     if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; }   /* RLE */
25440c16b537SWarner Losh 
25450c16b537SWarner Losh     {   U32 const algoNb = HUFv07_selectDecoder(dstSize, cSrcSize);
25460c16b537SWarner Losh         return algoNb ? HUFv07_decompress4X4_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) :
25470c16b537SWarner Losh                         HUFv07_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) ;
25480c16b537SWarner Losh     }
25490c16b537SWarner Losh }
25500c16b537SWarner Losh 
HUFv07_decompress4X_hufOnly(HUFv07_DTable * dctx,void * dst,size_t dstSize,const void * cSrc,size_t cSrcSize)25510c16b537SWarner Losh size_t HUFv07_decompress4X_hufOnly (HUFv07_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
25520c16b537SWarner Losh {
25530c16b537SWarner Losh     /* validation checks */
25540c16b537SWarner Losh     if (dstSize == 0) return ERROR(dstSize_tooSmall);
25550c16b537SWarner Losh     if ((cSrcSize >= dstSize) || (cSrcSize <= 1)) return ERROR(corruption_detected);   /* invalid */
25560c16b537SWarner Losh 
25570c16b537SWarner Losh     {   U32 const algoNb = HUFv07_selectDecoder(dstSize, cSrcSize);
25580c16b537SWarner Losh         return algoNb ? HUFv07_decompress4X4_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) :
25590c16b537SWarner Losh                         HUFv07_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) ;
25600c16b537SWarner Losh     }
25610c16b537SWarner Losh }
25620c16b537SWarner Losh 
HUFv07_decompress1X_DCtx(HUFv07_DTable * dctx,void * dst,size_t dstSize,const void * cSrc,size_t cSrcSize)25630c16b537SWarner Losh size_t HUFv07_decompress1X_DCtx (HUFv07_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
25640c16b537SWarner Losh {
25650c16b537SWarner Losh     /* validation checks */
25660c16b537SWarner Losh     if (dstSize == 0) return ERROR(dstSize_tooSmall);
25670c16b537SWarner Losh     if (cSrcSize > dstSize) return ERROR(corruption_detected);   /* invalid */
25680c16b537SWarner Losh     if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; }   /* not compressed */
25690c16b537SWarner Losh     if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; }   /* RLE */
25700c16b537SWarner Losh 
25710c16b537SWarner Losh     {   U32 const algoNb = HUFv07_selectDecoder(dstSize, cSrcSize);
25720c16b537SWarner Losh         return algoNb ? HUFv07_decompress1X4_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) :
25730c16b537SWarner Losh                         HUFv07_decompress1X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) ;
25740c16b537SWarner Losh     }
25750c16b537SWarner Losh }
25760c16b537SWarner Losh /*
25770c16b537SWarner Losh     Common functions of Zstd compression library
25780c16b537SWarner Losh     Copyright (C) 2015-2016, Yann Collet.
25790c16b537SWarner Losh 
25800c16b537SWarner Losh     BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
25810c16b537SWarner Losh 
25820c16b537SWarner Losh     Redistribution and use in source and binary forms, with or without
25830c16b537SWarner Losh     modification, are permitted provided that the following conditions are
25840c16b537SWarner Losh     met:
25850c16b537SWarner Losh     * Redistributions of source code must retain the above copyright
25860c16b537SWarner Losh     notice, this list of conditions and the following disclaimer.
25870c16b537SWarner Losh     * Redistributions in binary form must reproduce the above
25880c16b537SWarner Losh     copyright notice, this list of conditions and the following disclaimer
25890c16b537SWarner Losh     in the documentation and/or other materials provided with the
25900c16b537SWarner Losh     distribution.
25910c16b537SWarner Losh     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25920c16b537SWarner Losh     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25930c16b537SWarner Losh     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25940c16b537SWarner Losh     A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25950c16b537SWarner Losh     OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25960c16b537SWarner Losh     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25970c16b537SWarner Losh     LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25980c16b537SWarner Losh     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25990c16b537SWarner Losh     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26000c16b537SWarner Losh     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26010c16b537SWarner Losh     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26020c16b537SWarner Losh 
26030c16b537SWarner Losh     You can contact the author at :
26040c16b537SWarner Losh     - zstd homepage : http://www.zstd.net/
26050c16b537SWarner Losh */
26060c16b537SWarner Losh 
26070c16b537SWarner Losh 
26080c16b537SWarner Losh 
26090c16b537SWarner Losh /*-****************************************
26100c16b537SWarner Losh *  ZSTD Error Management
26110c16b537SWarner Losh ******************************************/
26120c16b537SWarner Losh /*! ZSTDv07_isError() :
26130c16b537SWarner Losh *   tells if a return value is an error code */
ZSTDv07_isError(size_t code)26140c16b537SWarner Losh unsigned ZSTDv07_isError(size_t code) { return ERR_isError(code); }
26150c16b537SWarner Losh 
26160c16b537SWarner Losh /*! ZSTDv07_getErrorName() :
26170c16b537SWarner Losh *   provides error code string from function result (useful for debugging) */
ZSTDv07_getErrorName(size_t code)26180c16b537SWarner Losh const char* ZSTDv07_getErrorName(size_t code) { return ERR_getErrorName(code); }
26190c16b537SWarner Losh 
26200c16b537SWarner Losh 
26210c16b537SWarner Losh 
26220c16b537SWarner Losh /* **************************************************************
26230c16b537SWarner Losh *  ZBUFF Error Management
26240c16b537SWarner Losh ****************************************************************/
ZBUFFv07_isError(size_t errorCode)26250c16b537SWarner Losh unsigned ZBUFFv07_isError(size_t errorCode) { return ERR_isError(errorCode); }
26260c16b537SWarner Losh 
ZBUFFv07_getErrorName(size_t errorCode)26270c16b537SWarner Losh const char* ZBUFFv07_getErrorName(size_t errorCode) { return ERR_getErrorName(errorCode); }
26280c16b537SWarner Losh 
26290c16b537SWarner Losh 
26300c16b537SWarner Losh 
ZSTDv07_defaultAllocFunction(void * opaque,size_t size)26310f743729SConrad Meyer static void* ZSTDv07_defaultAllocFunction(void* opaque, size_t size)
26320c16b537SWarner Losh {
26330c16b537SWarner Losh     void* address = malloc(size);
26340c16b537SWarner Losh     (void)opaque;
26350c16b537SWarner Losh     /* printf("alloc %p, %d opaque=%p \n", address, (int)size, opaque); */
26360c16b537SWarner Losh     return address;
26370c16b537SWarner Losh }
26380c16b537SWarner Losh 
ZSTDv07_defaultFreeFunction(void * opaque,void * address)26390f743729SConrad Meyer static void ZSTDv07_defaultFreeFunction(void* opaque, void* address)
26400c16b537SWarner Losh {
26410c16b537SWarner Losh     (void)opaque;
26420c16b537SWarner Losh     /* if (address) printf("free %p opaque=%p \n", address, opaque); */
26430c16b537SWarner Losh     free(address);
26440c16b537SWarner Losh }
26450c16b537SWarner Losh /*
26460c16b537SWarner Losh     zstd_internal - common functions to include
26470c16b537SWarner Losh     Header File for include
26480c16b537SWarner Losh     Copyright (C) 2014-2016, Yann Collet.
26490c16b537SWarner Losh 
26500c16b537SWarner Losh     BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
26510c16b537SWarner Losh 
26520c16b537SWarner Losh     Redistribution and use in source and binary forms, with or without
26530c16b537SWarner Losh     modification, are permitted provided that the following conditions are
26540c16b537SWarner Losh     met:
26550c16b537SWarner Losh     * Redistributions of source code must retain the above copyright
26560c16b537SWarner Losh     notice, this list of conditions and the following disclaimer.
26570c16b537SWarner Losh     * Redistributions in binary form must reproduce the above
26580c16b537SWarner Losh     copyright notice, this list of conditions and the following disclaimer
26590c16b537SWarner Losh     in the documentation and/or other materials provided with the
26600c16b537SWarner Losh     distribution.
26610c16b537SWarner Losh     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26620c16b537SWarner Losh     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26630c16b537SWarner Losh     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26640c16b537SWarner Losh     A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26650c16b537SWarner Losh     OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26660c16b537SWarner Losh     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26670c16b537SWarner Losh     LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26680c16b537SWarner Losh     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26690c16b537SWarner Losh     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26700c16b537SWarner Losh     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26710c16b537SWarner Losh     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26720c16b537SWarner Losh 
26730c16b537SWarner Losh     You can contact the author at :
26740c16b537SWarner Losh     - zstd homepage : https://www.zstd.net
26750c16b537SWarner Losh */
26760c16b537SWarner Losh #ifndef ZSTDv07_CCOMMON_H_MODULE
26770c16b537SWarner Losh #define ZSTDv07_CCOMMON_H_MODULE
26780c16b537SWarner Losh 
26790c16b537SWarner Losh 
26800c16b537SWarner Losh /*-*************************************
26810c16b537SWarner Losh *  Common macros
26820c16b537SWarner Losh ***************************************/
26830c16b537SWarner Losh #define MIN(a,b) ((a)<(b) ? (a) : (b))
26840c16b537SWarner Losh #define MAX(a,b) ((a)>(b) ? (a) : (b))
26850c16b537SWarner Losh 
26860c16b537SWarner Losh 
26870c16b537SWarner Losh /*-*************************************
26880c16b537SWarner Losh *  Common constants
26890c16b537SWarner Losh ***************************************/
26900c16b537SWarner Losh #define ZSTDv07_OPT_NUM    (1<<12)
26910c16b537SWarner Losh #define ZSTDv07_DICT_MAGIC  0xEC30A437   /* v0.7 */
26920c16b537SWarner Losh 
26930c16b537SWarner Losh #define ZSTDv07_REP_NUM    3
26940c16b537SWarner Losh #define ZSTDv07_REP_INIT   ZSTDv07_REP_NUM
26950c16b537SWarner Losh #define ZSTDv07_REP_MOVE   (ZSTDv07_REP_NUM-1)
26960c16b537SWarner Losh static const U32 repStartValue[ZSTDv07_REP_NUM] = { 1, 4, 8 };
26970c16b537SWarner Losh 
26980c16b537SWarner Losh #define KB *(1 <<10)
26990c16b537SWarner Losh #define MB *(1 <<20)
27000c16b537SWarner Losh #define GB *(1U<<30)
27010c16b537SWarner Losh 
27020c16b537SWarner Losh #define BIT7 128
27030c16b537SWarner Losh #define BIT6  64
27040c16b537SWarner Losh #define BIT5  32
27050c16b537SWarner Losh #define BIT4  16
27060c16b537SWarner Losh #define BIT1   2
27070c16b537SWarner Losh #define BIT0   1
27080c16b537SWarner Losh 
27090c16b537SWarner Losh #define ZSTDv07_WINDOWLOG_ABSOLUTEMIN 10
27100c16b537SWarner Losh static const size_t ZSTDv07_fcs_fieldSize[4] = { 0, 2, 4, 8 };
27110c16b537SWarner Losh static const size_t ZSTDv07_did_fieldSize[4] = { 0, 1, 2, 4 };
27120c16b537SWarner Losh 
27130c16b537SWarner Losh #define ZSTDv07_BLOCKHEADERSIZE 3   /* C standard doesn't allow `static const` variable to be init using another `static const` variable */
27140c16b537SWarner Losh static const size_t ZSTDv07_blockHeaderSize = ZSTDv07_BLOCKHEADERSIZE;
27150c16b537SWarner Losh typedef enum { bt_compressed, bt_raw, bt_rle, bt_end } blockType_t;
27160c16b537SWarner Losh 
27170c16b537SWarner Losh #define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */
27180c16b537SWarner Losh #define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */)   /* for a non-null block */
27190c16b537SWarner Losh 
27200c16b537SWarner Losh #define HufLog 12
27210c16b537SWarner Losh typedef enum { lbt_huffman, lbt_repeat, lbt_raw, lbt_rle } litBlockType_t;
27220c16b537SWarner Losh 
27230c16b537SWarner Losh #define LONGNBSEQ 0x7F00
27240c16b537SWarner Losh 
27250c16b537SWarner Losh #define MINMATCH 3
27260c16b537SWarner Losh #define EQUAL_READ32 4
27270c16b537SWarner Losh 
27280c16b537SWarner Losh #define Litbits  8
27290c16b537SWarner Losh #define MaxLit ((1<<Litbits) - 1)
27300c16b537SWarner Losh #define MaxML  52
27310c16b537SWarner Losh #define MaxLL  35
27320c16b537SWarner Losh #define MaxOff 28
27330c16b537SWarner Losh #define MaxSeq MAX(MaxLL, MaxML)   /* Assumption : MaxOff < MaxLL,MaxML */
27340c16b537SWarner Losh #define MLFSELog    9
27350c16b537SWarner Losh #define LLFSELog    9
27360c16b537SWarner Losh #define OffFSELog   8
27370c16b537SWarner Losh 
27380c16b537SWarner Losh #define FSEv07_ENCODING_RAW     0
27390c16b537SWarner Losh #define FSEv07_ENCODING_RLE     1
27400c16b537SWarner Losh #define FSEv07_ENCODING_STATIC  2
27410c16b537SWarner Losh #define FSEv07_ENCODING_DYNAMIC 3
27420c16b537SWarner Losh 
27432b9c00cbSConrad Meyer #define ZSTD_CONTENTSIZE_ERROR   (0ULL - 2)
27442b9c00cbSConrad Meyer 
27450c16b537SWarner Losh static const U32 LL_bits[MaxLL+1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
27460c16b537SWarner Losh                                       1, 1, 1, 1, 2, 2, 3, 3, 4, 6, 7, 8, 9,10,11,12,
27470c16b537SWarner Losh                                      13,14,15,16 };
27480c16b537SWarner Losh static const S16 LL_defaultNorm[MaxLL+1] = { 4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
27490c16b537SWarner Losh                                              2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1,
27500c16b537SWarner Losh                                             -1,-1,-1,-1 };
27510c16b537SWarner Losh static const U32 LL_defaultNormLog = 6;
27520c16b537SWarner Losh 
27530c16b537SWarner Losh static const U32 ML_bits[MaxML+1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
27540c16b537SWarner Losh                                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
27550c16b537SWarner Losh                                       1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 7, 8, 9,10,11,
27560c16b537SWarner Losh                                      12,13,14,15,16 };
27570c16b537SWarner Losh static const S16 ML_defaultNorm[MaxML+1] = { 1, 4, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
27580c16b537SWarner Losh                                              1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
27590c16b537SWarner Losh                                              1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,-1,-1,
27600c16b537SWarner Losh                                             -1,-1,-1,-1,-1 };
27610c16b537SWarner Losh static const U32 ML_defaultNormLog = 6;
27620c16b537SWarner Losh 
27630c16b537SWarner Losh static const S16 OF_defaultNorm[MaxOff+1] = { 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
27640c16b537SWarner Losh                                               1, 1, 1, 1, 1, 1, 1, 1,-1,-1,-1,-1,-1 };
27650c16b537SWarner Losh static const U32 OF_defaultNormLog = 5;
27660c16b537SWarner Losh 
27670c16b537SWarner Losh 
27680c16b537SWarner Losh /*-*******************************************
27690c16b537SWarner Losh *  Shared functions to include for inlining
27700c16b537SWarner Losh *********************************************/
ZSTDv07_copy8(void * dst,const void * src)27710c16b537SWarner Losh static void ZSTDv07_copy8(void* dst, const void* src) { memcpy(dst, src, 8); }
27720c16b537SWarner Losh #define COPY8(d,s) { ZSTDv07_copy8(d,s); d+=8; s+=8; }
27730c16b537SWarner Losh 
27740c16b537SWarner Losh /*! ZSTDv07_wildcopy() :
27750c16b537SWarner Losh *   custom version of memcpy(), can copy up to 7 bytes too many (8 bytes if length==0) */
27760c16b537SWarner Losh #define WILDCOPY_OVERLENGTH 8
ZSTDv07_wildcopy(void * dst,const void * src,ptrdiff_t length)27770c16b537SWarner Losh MEM_STATIC void ZSTDv07_wildcopy(void* dst, const void* src, ptrdiff_t length)
27780c16b537SWarner Losh {
27790c16b537SWarner Losh     const BYTE* ip = (const BYTE*)src;
27800c16b537SWarner Losh     BYTE* op = (BYTE*)dst;
27810c16b537SWarner Losh     BYTE* const oend = op + length;
27820c16b537SWarner Losh     do
27830c16b537SWarner Losh         COPY8(op, ip)
27840c16b537SWarner Losh     while (op < oend);
27850c16b537SWarner Losh }
27860c16b537SWarner Losh 
27870c16b537SWarner Losh 
27880c16b537SWarner Losh /*-*******************************************
27890c16b537SWarner Losh *  Private interfaces
27900c16b537SWarner Losh *********************************************/
27910c16b537SWarner Losh typedef struct ZSTDv07_stats_s ZSTDv07_stats_t;
27920c16b537SWarner Losh 
27930c16b537SWarner Losh typedef struct {
27940c16b537SWarner Losh     U32 off;
27950c16b537SWarner Losh     U32 len;
27960c16b537SWarner Losh } ZSTDv07_match_t;
27970c16b537SWarner Losh 
27980c16b537SWarner Losh typedef struct {
27990c16b537SWarner Losh     U32 price;
28000c16b537SWarner Losh     U32 off;
28010c16b537SWarner Losh     U32 mlen;
28020c16b537SWarner Losh     U32 litlen;
28030c16b537SWarner Losh     U32 rep[ZSTDv07_REP_INIT];
28040c16b537SWarner Losh } ZSTDv07_optimal_t;
28050c16b537SWarner Losh 
28060c16b537SWarner Losh struct ZSTDv07_stats_s { U32 unused; };
28070c16b537SWarner Losh 
28080c16b537SWarner Losh typedef struct {
28090c16b537SWarner Losh     void* buffer;
28100c16b537SWarner Losh     U32*  offsetStart;
28110c16b537SWarner Losh     U32*  offset;
28120c16b537SWarner Losh     BYTE* offCodeStart;
28130c16b537SWarner Losh     BYTE* litStart;
28140c16b537SWarner Losh     BYTE* lit;
28150c16b537SWarner Losh     U16*  litLengthStart;
28160c16b537SWarner Losh     U16*  litLength;
28170c16b537SWarner Losh     BYTE* llCodeStart;
28180c16b537SWarner Losh     U16*  matchLengthStart;
28190c16b537SWarner Losh     U16*  matchLength;
28200c16b537SWarner Losh     BYTE* mlCodeStart;
28210c16b537SWarner Losh     U32   longLengthID;   /* 0 == no longLength; 1 == Lit.longLength; 2 == Match.longLength; */
28220c16b537SWarner Losh     U32   longLengthPos;
28230c16b537SWarner Losh     /* opt */
28240c16b537SWarner Losh     ZSTDv07_optimal_t* priceTable;
28250c16b537SWarner Losh     ZSTDv07_match_t* matchTable;
28260c16b537SWarner Losh     U32* matchLengthFreq;
28270c16b537SWarner Losh     U32* litLengthFreq;
28280c16b537SWarner Losh     U32* litFreq;
28290c16b537SWarner Losh     U32* offCodeFreq;
28300c16b537SWarner Losh     U32  matchLengthSum;
28310c16b537SWarner Losh     U32  matchSum;
28320c16b537SWarner Losh     U32  litLengthSum;
28330c16b537SWarner Losh     U32  litSum;
28340c16b537SWarner Losh     U32  offCodeSum;
28350c16b537SWarner Losh     U32  log2matchLengthSum;
28360c16b537SWarner Losh     U32  log2matchSum;
28370c16b537SWarner Losh     U32  log2litLengthSum;
28380c16b537SWarner Losh     U32  log2litSum;
28390c16b537SWarner Losh     U32  log2offCodeSum;
28400c16b537SWarner Losh     U32  factor;
28410c16b537SWarner Losh     U32  cachedPrice;
28420c16b537SWarner Losh     U32  cachedLitLength;
28430c16b537SWarner Losh     const BYTE* cachedLiterals;
28440c16b537SWarner Losh     ZSTDv07_stats_t stats;
28450c16b537SWarner Losh } seqStore_t;
28460c16b537SWarner Losh 
28470c16b537SWarner Losh void ZSTDv07_seqToCodes(const seqStore_t* seqStorePtr, size_t const nbSeq);
28480c16b537SWarner Losh 
28490c16b537SWarner Losh /* custom memory allocation functions */
28500c16b537SWarner Losh static const ZSTDv07_customMem defaultCustomMem = { ZSTDv07_defaultAllocFunction, ZSTDv07_defaultFreeFunction, NULL };
28510c16b537SWarner Losh 
28520c16b537SWarner Losh #endif   /* ZSTDv07_CCOMMON_H_MODULE */
28530c16b537SWarner Losh /*
28540c16b537SWarner Losh     zstd - standard compression library
28550c16b537SWarner Losh     Copyright (C) 2014-2016, Yann Collet.
28560c16b537SWarner Losh 
28570c16b537SWarner Losh     BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
28580c16b537SWarner Losh 
28590c16b537SWarner Losh     Redistribution and use in source and binary forms, with or without
28600c16b537SWarner Losh     modification, are permitted provided that the following conditions are
28610c16b537SWarner Losh     met:
28620c16b537SWarner Losh     * Redistributions of source code must retain the above copyright
28630c16b537SWarner Losh     notice, this list of conditions and the following disclaimer.
28640c16b537SWarner Losh     * Redistributions in binary form must reproduce the above
28650c16b537SWarner Losh     copyright notice, this list of conditions and the following disclaimer
28660c16b537SWarner Losh     in the documentation and/or other materials provided with the
28670c16b537SWarner Losh     distribution.
28680c16b537SWarner Losh     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28690c16b537SWarner Losh     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28700c16b537SWarner Losh     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28710c16b537SWarner Losh     A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28720c16b537SWarner Losh     OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28730c16b537SWarner Losh     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28740c16b537SWarner Losh     LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28750c16b537SWarner Losh     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28760c16b537SWarner Losh     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28770c16b537SWarner Losh     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28780c16b537SWarner Losh     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28790c16b537SWarner Losh 
28800c16b537SWarner Losh     You can contact the author at :
28810c16b537SWarner Losh     - zstd homepage : http://www.zstd.net
28820c16b537SWarner Losh */
28830c16b537SWarner Losh 
28840c16b537SWarner Losh /* ***************************************************************
28850c16b537SWarner Losh *  Tuning parameters
28860c16b537SWarner Losh *****************************************************************/
28870c16b537SWarner Losh /*!
28880c16b537SWarner Losh  * HEAPMODE :
28890c16b537SWarner Losh  * Select how default decompression function ZSTDv07_decompress() will allocate memory,
28900c16b537SWarner Losh  * in memory stack (0), or in memory heap (1, requires malloc())
28910c16b537SWarner Losh  */
28920c16b537SWarner Losh #ifndef ZSTDv07_HEAPMODE
28930c16b537SWarner Losh #  define ZSTDv07_HEAPMODE 1
28940c16b537SWarner Losh #endif
28950c16b537SWarner Losh 
28960c16b537SWarner Losh 
28970c16b537SWarner Losh /*-*******************************************************
28980c16b537SWarner Losh *  Compiler specifics
28990c16b537SWarner Losh *********************************************************/
29000c16b537SWarner Losh #ifdef _MSC_VER    /* Visual Studio */
29010c16b537SWarner Losh #  include <intrin.h>                    /* For Visual 2005 */
29020c16b537SWarner Losh #  pragma warning(disable : 4127)        /* disable: C4127: conditional expression is constant */
29030c16b537SWarner Losh #  pragma warning(disable : 4324)        /* disable: C4324: padded structure */
29040c16b537SWarner Losh #  pragma warning(disable : 4100)        /* disable: C4100: unreferenced formal parameter */
29050c16b537SWarner Losh #endif
29060c16b537SWarner Losh 
29070c16b537SWarner Losh 
29080c16b537SWarner Losh /*-*************************************
29090c16b537SWarner Losh *  Macros
29100c16b537SWarner Losh ***************************************/
29110c16b537SWarner Losh #define ZSTDv07_isError ERR_isError   /* for inlining */
29120c16b537SWarner Losh #define FSEv07_isError  ERR_isError
29130c16b537SWarner Losh #define HUFv07_isError  ERR_isError
29140c16b537SWarner Losh 
29150c16b537SWarner Losh 
29160c16b537SWarner Losh /*_*******************************************************
29170c16b537SWarner Losh *  Memory operations
29180c16b537SWarner Losh **********************************************************/
ZSTDv07_copy4(void * dst,const void * src)29190c16b537SWarner Losh static void ZSTDv07_copy4(void* dst, const void* src) { memcpy(dst, src, 4); }
29200c16b537SWarner Losh 
29210c16b537SWarner Losh 
29220c16b537SWarner Losh /*-*************************************************************
29230c16b537SWarner Losh *   Context management
29240c16b537SWarner Losh ***************************************************************/
29250c16b537SWarner Losh typedef enum { ZSTDds_getFrameHeaderSize, ZSTDds_decodeFrameHeader,
29260c16b537SWarner Losh                ZSTDds_decodeBlockHeader, ZSTDds_decompressBlock,
29270c16b537SWarner Losh                ZSTDds_decodeSkippableHeader, ZSTDds_skipFrame } ZSTDv07_dStage;
29280c16b537SWarner Losh 
29290c16b537SWarner Losh struct ZSTDv07_DCtx_s
29300c16b537SWarner Losh {
29310c16b537SWarner Losh     FSEv07_DTable LLTable[FSEv07_DTABLE_SIZE_U32(LLFSELog)];
29320c16b537SWarner Losh     FSEv07_DTable OffTable[FSEv07_DTABLE_SIZE_U32(OffFSELog)];
29330c16b537SWarner Losh     FSEv07_DTable MLTable[FSEv07_DTABLE_SIZE_U32(MLFSELog)];
29340c16b537SWarner Losh     HUFv07_DTable hufTable[HUFv07_DTABLE_SIZE(HufLog)];  /* can accommodate HUFv07_decompress4X */
29350c16b537SWarner Losh     const void* previousDstEnd;
29360c16b537SWarner Losh     const void* base;
29370c16b537SWarner Losh     const void* vBase;
29380c16b537SWarner Losh     const void* dictEnd;
29390c16b537SWarner Losh     size_t expected;
29400c16b537SWarner Losh     U32 rep[3];
29410c16b537SWarner Losh     ZSTDv07_frameParams fParams;
29420c16b537SWarner Losh     blockType_t bType;   /* used in ZSTDv07_decompressContinue(), to transfer blockType between header decoding and block decoding stages */
29430c16b537SWarner Losh     ZSTDv07_dStage stage;
29440c16b537SWarner Losh     U32 litEntropy;
29450c16b537SWarner Losh     U32 fseEntropy;
29460c16b537SWarner Losh     XXH64_state_t xxhState;
29470c16b537SWarner Losh     size_t headerSize;
29480c16b537SWarner Losh     U32 dictID;
29490c16b537SWarner Losh     const BYTE* litPtr;
29500c16b537SWarner Losh     ZSTDv07_customMem customMem;
29510c16b537SWarner Losh     size_t litSize;
29520c16b537SWarner Losh     BYTE litBuffer[ZSTDv07_BLOCKSIZE_ABSOLUTEMAX + WILDCOPY_OVERLENGTH];
29530c16b537SWarner Losh     BYTE headerBuffer[ZSTDv07_FRAMEHEADERSIZE_MAX];
29540c16b537SWarner Losh };  /* typedef'd to ZSTDv07_DCtx within "zstd_static.h" */
29550c16b537SWarner Losh 
29560c16b537SWarner Losh int ZSTDv07_isSkipFrame(ZSTDv07_DCtx* dctx);
29570c16b537SWarner Losh 
ZSTDv07_sizeofDCtx(const ZSTDv07_DCtx * dctx)29580c16b537SWarner Losh size_t ZSTDv07_sizeofDCtx (const ZSTDv07_DCtx* dctx) { return sizeof(*dctx); }
29590c16b537SWarner Losh 
ZSTDv07_estimateDCtxSize(void)29600c16b537SWarner Losh size_t ZSTDv07_estimateDCtxSize(void) { return sizeof(ZSTDv07_DCtx); }
29610c16b537SWarner Losh 
ZSTDv07_decompressBegin(ZSTDv07_DCtx * dctx)29620c16b537SWarner Losh size_t ZSTDv07_decompressBegin(ZSTDv07_DCtx* dctx)
29630c16b537SWarner Losh {
29640c16b537SWarner Losh     dctx->expected = ZSTDv07_frameHeaderSize_min;
29650c16b537SWarner Losh     dctx->stage = ZSTDds_getFrameHeaderSize;
29660c16b537SWarner Losh     dctx->previousDstEnd = NULL;
29670c16b537SWarner Losh     dctx->base = NULL;
29680c16b537SWarner Losh     dctx->vBase = NULL;
29690c16b537SWarner Losh     dctx->dictEnd = NULL;
29700c16b537SWarner Losh     dctx->hufTable[0] = (HUFv07_DTable)((HufLog)*0x1000001);
29710c16b537SWarner Losh     dctx->litEntropy = dctx->fseEntropy = 0;
29720c16b537SWarner Losh     dctx->dictID = 0;
29730c16b537SWarner Losh     { int i; for (i=0; i<ZSTDv07_REP_NUM; i++) dctx->rep[i] = repStartValue[i]; }
29740c16b537SWarner Losh     return 0;
29750c16b537SWarner Losh }
29760c16b537SWarner Losh 
ZSTDv07_createDCtx_advanced(ZSTDv07_customMem customMem)29770c16b537SWarner Losh ZSTDv07_DCtx* ZSTDv07_createDCtx_advanced(ZSTDv07_customMem customMem)
29780c16b537SWarner Losh {
29790c16b537SWarner Losh     ZSTDv07_DCtx* dctx;
29800c16b537SWarner Losh 
29810c16b537SWarner Losh     if (!customMem.customAlloc && !customMem.customFree)
29820c16b537SWarner Losh         customMem = defaultCustomMem;
29830c16b537SWarner Losh 
29840c16b537SWarner Losh     if (!customMem.customAlloc || !customMem.customFree)
29850c16b537SWarner Losh         return NULL;
29860c16b537SWarner Losh 
29870c16b537SWarner Losh     dctx = (ZSTDv07_DCtx*) customMem.customAlloc(customMem.opaque, sizeof(ZSTDv07_DCtx));
29880c16b537SWarner Losh     if (!dctx) return NULL;
29890c16b537SWarner Losh     memcpy(&dctx->customMem, &customMem, sizeof(ZSTDv07_customMem));
29900c16b537SWarner Losh     ZSTDv07_decompressBegin(dctx);
29910c16b537SWarner Losh     return dctx;
29920c16b537SWarner Losh }
29930c16b537SWarner Losh 
ZSTDv07_createDCtx(void)29940c16b537SWarner Losh ZSTDv07_DCtx* ZSTDv07_createDCtx(void)
29950c16b537SWarner Losh {
29960c16b537SWarner Losh     return ZSTDv07_createDCtx_advanced(defaultCustomMem);
29970c16b537SWarner Losh }
29980c16b537SWarner Losh 
ZSTDv07_freeDCtx(ZSTDv07_DCtx * dctx)29990c16b537SWarner Losh size_t ZSTDv07_freeDCtx(ZSTDv07_DCtx* dctx)
30000c16b537SWarner Losh {
30010c16b537SWarner Losh     if (dctx==NULL) return 0;   /* support free on NULL */
30020c16b537SWarner Losh     dctx->customMem.customFree(dctx->customMem.opaque, dctx);
30030c16b537SWarner Losh     return 0;   /* reserved as a potential error code in the future */
30040c16b537SWarner Losh }
30050c16b537SWarner Losh 
ZSTDv07_copyDCtx(ZSTDv07_DCtx * dstDCtx,const ZSTDv07_DCtx * srcDCtx)30060c16b537SWarner Losh void ZSTDv07_copyDCtx(ZSTDv07_DCtx* dstDCtx, const ZSTDv07_DCtx* srcDCtx)
30070c16b537SWarner Losh {
30080c16b537SWarner Losh     memcpy(dstDCtx, srcDCtx,
30090c16b537SWarner Losh            sizeof(ZSTDv07_DCtx) - (ZSTDv07_BLOCKSIZE_ABSOLUTEMAX+WILDCOPY_OVERLENGTH + ZSTDv07_frameHeaderSize_max));  /* no need to copy workspace */
30100c16b537SWarner Losh }
30110c16b537SWarner Losh 
30120c16b537SWarner Losh 
30130c16b537SWarner Losh /*-*************************************************************
30140c16b537SWarner Losh *   Decompression section
30150c16b537SWarner Losh ***************************************************************/
30160c16b537SWarner Losh 
30170c16b537SWarner Losh /* Frame format description
30180c16b537SWarner Losh    Frame Header -  [ Block Header - Block ] - Frame End
30190c16b537SWarner Losh    1) Frame Header
30200c16b537SWarner Losh       - 4 bytes - Magic Number : ZSTDv07_MAGICNUMBER (defined within zstd.h)
30210c16b537SWarner Losh       - 1 byte  - Frame Descriptor
30220c16b537SWarner Losh    2) Block Header
30230c16b537SWarner Losh       - 3 bytes, starting with a 2-bits descriptor
30240c16b537SWarner Losh                  Uncompressed, Compressed, Frame End, unused
30250c16b537SWarner Losh    3) Block
30260c16b537SWarner Losh       See Block Format Description
30270c16b537SWarner Losh    4) Frame End
30280c16b537SWarner Losh       - 3 bytes, compatible with Block Header
30290c16b537SWarner Losh */
30300c16b537SWarner Losh 
30310c16b537SWarner Losh 
30320c16b537SWarner Losh /* Frame Header :
30330c16b537SWarner Losh 
30340c16b537SWarner Losh    1 byte - FrameHeaderDescription :
30350c16b537SWarner Losh    bit 0-1 : dictID (0, 1, 2 or 4 bytes)
30360c16b537SWarner Losh    bit 2   : checksumFlag
30370c16b537SWarner Losh    bit 3   : reserved (must be zero)
30380c16b537SWarner Losh    bit 4   : reserved (unused, can be any value)
30390c16b537SWarner Losh    bit 5   : Single Segment (if 1, WindowLog byte is not present)
30400c16b537SWarner Losh    bit 6-7 : FrameContentFieldSize (0, 2, 4, or 8)
30410c16b537SWarner Losh              if (SkippedWindowLog && !FrameContentFieldsize) FrameContentFieldsize=1;
30420c16b537SWarner Losh 
30430c16b537SWarner Losh    Optional : WindowLog (0 or 1 byte)
30440c16b537SWarner Losh    bit 0-2 : octal Fractional (1/8th)
30450c16b537SWarner Losh    bit 3-7 : Power of 2, with 0 = 1 KB (up to 2 TB)
30460c16b537SWarner Losh 
30470c16b537SWarner Losh    Optional : dictID (0, 1, 2 or 4 bytes)
30480c16b537SWarner Losh    Automatic adaptation
30490c16b537SWarner Losh    0 : no dictID
30500c16b537SWarner Losh    1 : 1 - 255
30510c16b537SWarner Losh    2 : 256 - 65535
30520c16b537SWarner Losh    4 : all other values
30530c16b537SWarner Losh 
30540c16b537SWarner Losh    Optional : content size (0, 1, 2, 4 or 8 bytes)
30550c16b537SWarner Losh    0 : unknown          (fcfs==0 and swl==0)
30560c16b537SWarner Losh    1 : 0-255 bytes      (fcfs==0 and swl==1)
30570c16b537SWarner Losh    2 : 256 - 65535+256  (fcfs==1)
30580c16b537SWarner Losh    4 : 0 - 4GB-1        (fcfs==2)
30590c16b537SWarner Losh    8 : 0 - 16EB-1       (fcfs==3)
30600c16b537SWarner Losh */
30610c16b537SWarner Losh 
30620c16b537SWarner Losh 
30630c16b537SWarner Losh /* Compressed Block, format description
30640c16b537SWarner Losh 
30650c16b537SWarner Losh    Block = Literal Section - Sequences Section
30660c16b537SWarner Losh    Prerequisite : size of (compressed) block, maximum size of regenerated data
30670c16b537SWarner Losh 
30680c16b537SWarner Losh    1) Literal Section
30690c16b537SWarner Losh 
30700c16b537SWarner Losh    1.1) Header : 1-5 bytes
30710c16b537SWarner Losh         flags: 2 bits
30720c16b537SWarner Losh             00 compressed by Huff0
30730c16b537SWarner Losh             01 unused
30740c16b537SWarner Losh             10 is Raw (uncompressed)
30750c16b537SWarner Losh             11 is Rle
30760c16b537SWarner Losh             Note : using 01 => Huff0 with precomputed table ?
30770c16b537SWarner Losh             Note : delta map ? => compressed ?
30780c16b537SWarner Losh 
30790c16b537SWarner Losh    1.1.1) Huff0-compressed literal block : 3-5 bytes
30800c16b537SWarner Losh             srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream
30810c16b537SWarner Losh             srcSize < 1 KB => 3 bytes (2-2-10-10)
30820c16b537SWarner Losh             srcSize < 16KB => 4 bytes (2-2-14-14)
30830c16b537SWarner Losh             else           => 5 bytes (2-2-18-18)
30840c16b537SWarner Losh             big endian convention
30850c16b537SWarner Losh 
30860c16b537SWarner Losh    1.1.2) Raw (uncompressed) literal block header : 1-3 bytes
30870c16b537SWarner Losh         size :  5 bits: (IS_RAW<<6) + (0<<4) + size
30880c16b537SWarner Losh                12 bits: (IS_RAW<<6) + (2<<4) + (size>>8)
30890c16b537SWarner Losh                         size&255
30900c16b537SWarner Losh                20 bits: (IS_RAW<<6) + (3<<4) + (size>>16)
30910c16b537SWarner Losh                         size>>8&255
30920c16b537SWarner Losh                         size&255
30930c16b537SWarner Losh 
30940c16b537SWarner Losh    1.1.3) Rle (repeated single byte) literal block header : 1-3 bytes
30950c16b537SWarner Losh         size :  5 bits: (IS_RLE<<6) + (0<<4) + size
30960c16b537SWarner Losh                12 bits: (IS_RLE<<6) + (2<<4) + (size>>8)
30970c16b537SWarner Losh                         size&255
30980c16b537SWarner Losh                20 bits: (IS_RLE<<6) + (3<<4) + (size>>16)
30990c16b537SWarner Losh                         size>>8&255
31000c16b537SWarner Losh                         size&255
31010c16b537SWarner Losh 
31020c16b537SWarner Losh    1.1.4) Huff0-compressed literal block, using precomputed CTables : 3-5 bytes
31030c16b537SWarner Losh             srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream
31040c16b537SWarner Losh             srcSize < 1 KB => 3 bytes (2-2-10-10)
31050c16b537SWarner Losh             srcSize < 16KB => 4 bytes (2-2-14-14)
31060c16b537SWarner Losh             else           => 5 bytes (2-2-18-18)
31070c16b537SWarner Losh             big endian convention
31080c16b537SWarner Losh 
31090c16b537SWarner Losh         1- CTable available (stored into workspace ?)
31100c16b537SWarner Losh         2- Small input (fast heuristic ? Full comparison ? depend on clevel ?)
31110c16b537SWarner Losh 
31120c16b537SWarner Losh 
31130c16b537SWarner Losh    1.2) Literal block content
31140c16b537SWarner Losh 
31150c16b537SWarner Losh    1.2.1) Huff0 block, using sizes from header
31160c16b537SWarner Losh         See Huff0 format
31170c16b537SWarner Losh 
31180c16b537SWarner Losh    1.2.2) Huff0 block, using prepared table
31190c16b537SWarner Losh 
31200c16b537SWarner Losh    1.2.3) Raw content
31210c16b537SWarner Losh 
31220c16b537SWarner Losh    1.2.4) single byte
31230c16b537SWarner Losh 
31240c16b537SWarner Losh 
31250c16b537SWarner Losh    2) Sequences section
31260c16b537SWarner Losh       TO DO
31270c16b537SWarner Losh */
31280c16b537SWarner Losh 
31290c16b537SWarner Losh /** ZSTDv07_frameHeaderSize() :
31300c16b537SWarner Losh *   srcSize must be >= ZSTDv07_frameHeaderSize_min.
31310c16b537SWarner Losh *   @return : size of the Frame Header */
ZSTDv07_frameHeaderSize(const void * src,size_t srcSize)31320c16b537SWarner Losh static size_t ZSTDv07_frameHeaderSize(const void* src, size_t srcSize)
31330c16b537SWarner Losh {
31340c16b537SWarner Losh     if (srcSize < ZSTDv07_frameHeaderSize_min) return ERROR(srcSize_wrong);
31350c16b537SWarner Losh     {   BYTE const fhd = ((const BYTE*)src)[4];
31360c16b537SWarner Losh         U32 const dictID= fhd & 3;
31370c16b537SWarner Losh         U32 const directMode = (fhd >> 5) & 1;
31380c16b537SWarner Losh         U32 const fcsId = fhd >> 6;
31390c16b537SWarner Losh         return ZSTDv07_frameHeaderSize_min + !directMode + ZSTDv07_did_fieldSize[dictID] + ZSTDv07_fcs_fieldSize[fcsId]
31400c16b537SWarner Losh                 + (directMode && !ZSTDv07_fcs_fieldSize[fcsId]);
31410c16b537SWarner Losh     }
31420c16b537SWarner Losh }
31430c16b537SWarner Losh 
31440c16b537SWarner Losh 
31450c16b537SWarner Losh /** ZSTDv07_getFrameParams() :
31460c16b537SWarner Losh *   decode Frame Header, or require larger `srcSize`.
31470c16b537SWarner Losh *   @return : 0, `fparamsPtr` is correctly filled,
31480c16b537SWarner Losh *            >0, `srcSize` is too small, result is expected `srcSize`,
31490c16b537SWarner Losh *             or an error code, which can be tested using ZSTDv07_isError() */
ZSTDv07_getFrameParams(ZSTDv07_frameParams * fparamsPtr,const void * src,size_t srcSize)31500c16b537SWarner Losh size_t ZSTDv07_getFrameParams(ZSTDv07_frameParams* fparamsPtr, const void* src, size_t srcSize)
31510c16b537SWarner Losh {
31520c16b537SWarner Losh     const BYTE* ip = (const BYTE*)src;
31530c16b537SWarner Losh 
31540c16b537SWarner Losh     if (srcSize < ZSTDv07_frameHeaderSize_min) return ZSTDv07_frameHeaderSize_min;
31550f743729SConrad Meyer     memset(fparamsPtr, 0, sizeof(*fparamsPtr));
31560c16b537SWarner Losh     if (MEM_readLE32(src) != ZSTDv07_MAGICNUMBER) {
31570c16b537SWarner Losh         if ((MEM_readLE32(src) & 0xFFFFFFF0U) == ZSTDv07_MAGIC_SKIPPABLE_START) {
31580c16b537SWarner Losh             if (srcSize < ZSTDv07_skippableHeaderSize) return ZSTDv07_skippableHeaderSize; /* magic number + skippable frame length */
31590c16b537SWarner Losh             fparamsPtr->frameContentSize = MEM_readLE32((const char *)src + 4);
31600c16b537SWarner Losh             fparamsPtr->windowSize = 0; /* windowSize==0 means a frame is skippable */
31610c16b537SWarner Losh             return 0;
31620c16b537SWarner Losh         }
31630c16b537SWarner Losh         return ERROR(prefix_unknown);
31640c16b537SWarner Losh     }
31650c16b537SWarner Losh 
31660c16b537SWarner Losh     /* ensure there is enough `srcSize` to fully read/decode frame header */
31670c16b537SWarner Losh     { size_t const fhsize = ZSTDv07_frameHeaderSize(src, srcSize);
31680c16b537SWarner Losh       if (srcSize < fhsize) return fhsize; }
31690c16b537SWarner Losh 
31700c16b537SWarner Losh     {   BYTE const fhdByte = ip[4];
31710c16b537SWarner Losh         size_t pos = 5;
31720c16b537SWarner Losh         U32 const dictIDSizeCode = fhdByte&3;
31730c16b537SWarner Losh         U32 const checksumFlag = (fhdByte>>2)&1;
31740c16b537SWarner Losh         U32 const directMode = (fhdByte>>5)&1;
31750c16b537SWarner Losh         U32 const fcsID = fhdByte>>6;
31760c16b537SWarner Losh         U32 const windowSizeMax = 1U << ZSTDv07_WINDOWLOG_MAX;
31770c16b537SWarner Losh         U32 windowSize = 0;
31780c16b537SWarner Losh         U32 dictID = 0;
31790c16b537SWarner Losh         U64 frameContentSize = 0;
31800f743729SConrad Meyer         if ((fhdByte & 0x08) != 0)   /* reserved bits, which must be zero */
31810f743729SConrad Meyer             return ERROR(frameParameter_unsupported);
31820c16b537SWarner Losh         if (!directMode) {
31830c16b537SWarner Losh             BYTE const wlByte = ip[pos++];
31840c16b537SWarner Losh             U32 const windowLog = (wlByte >> 3) + ZSTDv07_WINDOWLOG_ABSOLUTEMIN;
31850f743729SConrad Meyer             if (windowLog > ZSTDv07_WINDOWLOG_MAX)
31860f743729SConrad Meyer                 return ERROR(frameParameter_unsupported);
31870c16b537SWarner Losh             windowSize = (1U << windowLog);
31880c16b537SWarner Losh             windowSize += (windowSize >> 3) * (wlByte&7);
31890c16b537SWarner Losh         }
31900c16b537SWarner Losh 
31910c16b537SWarner Losh         switch(dictIDSizeCode)
31920c16b537SWarner Losh         {
31930c16b537SWarner Losh             default:   /* impossible */
31940c16b537SWarner Losh             case 0 : break;
31950c16b537SWarner Losh             case 1 : dictID = ip[pos]; pos++; break;
31960c16b537SWarner Losh             case 2 : dictID = MEM_readLE16(ip+pos); pos+=2; break;
31970c16b537SWarner Losh             case 3 : dictID = MEM_readLE32(ip+pos); pos+=4; break;
31980c16b537SWarner Losh         }
31990c16b537SWarner Losh         switch(fcsID)
32000c16b537SWarner Losh         {
32010c16b537SWarner Losh             default:   /* impossible */
32020c16b537SWarner Losh             case 0 : if (directMode) frameContentSize = ip[pos]; break;
32030c16b537SWarner Losh             case 1 : frameContentSize = MEM_readLE16(ip+pos)+256; break;
32040c16b537SWarner Losh             case 2 : frameContentSize = MEM_readLE32(ip+pos); break;
32050c16b537SWarner Losh             case 3 : frameContentSize = MEM_readLE64(ip+pos); break;
32060c16b537SWarner Losh         }
32070c16b537SWarner Losh         if (!windowSize) windowSize = (U32)frameContentSize;
32080f743729SConrad Meyer         if (windowSize > windowSizeMax)
32090f743729SConrad Meyer             return ERROR(frameParameter_unsupported);
32100c16b537SWarner Losh         fparamsPtr->frameContentSize = frameContentSize;
32110c16b537SWarner Losh         fparamsPtr->windowSize = windowSize;
32120c16b537SWarner Losh         fparamsPtr->dictID = dictID;
32130c16b537SWarner Losh         fparamsPtr->checksumFlag = checksumFlag;
32140c16b537SWarner Losh     }
32150c16b537SWarner Losh     return 0;
32160c16b537SWarner Losh }
32170c16b537SWarner Losh 
32180c16b537SWarner Losh 
32190c16b537SWarner Losh /** ZSTDv07_getDecompressedSize() :
32200c16b537SWarner Losh *   compatible with legacy mode
32210c16b537SWarner Losh *   @return : decompressed size if known, 0 otherwise
32220c16b537SWarner Losh               note : 0 can mean any of the following :
32230c16b537SWarner Losh                    - decompressed size is not provided within frame header
32240c16b537SWarner Losh                    - frame header unknown / not supported
32250c16b537SWarner Losh                    - frame header not completely provided (`srcSize` too small) */
ZSTDv07_getDecompressedSize(const void * src,size_t srcSize)32260c16b537SWarner Losh unsigned long long ZSTDv07_getDecompressedSize(const void* src, size_t srcSize)
32270c16b537SWarner Losh {
32280f743729SConrad Meyer     ZSTDv07_frameParams fparams;
32290c16b537SWarner Losh     size_t const frResult = ZSTDv07_getFrameParams(&fparams, src, srcSize);
32300c16b537SWarner Losh     if (frResult!=0) return 0;
32310c16b537SWarner Losh     return fparams.frameContentSize;
32320c16b537SWarner Losh }
32330c16b537SWarner Losh 
32340c16b537SWarner Losh 
32350c16b537SWarner Losh /** ZSTDv07_decodeFrameHeader() :
32360c16b537SWarner Losh *   `srcSize` must be the size provided by ZSTDv07_frameHeaderSize().
32370c16b537SWarner Losh *   @return : 0 if success, or an error code, which can be tested using ZSTDv07_isError() */
ZSTDv07_decodeFrameHeader(ZSTDv07_DCtx * dctx,const void * src,size_t srcSize)32380c16b537SWarner Losh static size_t ZSTDv07_decodeFrameHeader(ZSTDv07_DCtx* dctx, const void* src, size_t srcSize)
32390c16b537SWarner Losh {
32400c16b537SWarner Losh     size_t const result = ZSTDv07_getFrameParams(&(dctx->fParams), src, srcSize);
32410c16b537SWarner Losh     if (dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID)) return ERROR(dictionary_wrong);
32420c16b537SWarner Losh     if (dctx->fParams.checksumFlag) XXH64_reset(&dctx->xxhState, 0);
32430c16b537SWarner Losh     return result;
32440c16b537SWarner Losh }
32450c16b537SWarner Losh 
32460c16b537SWarner Losh 
32470c16b537SWarner Losh typedef struct
32480c16b537SWarner Losh {
32490c16b537SWarner Losh     blockType_t blockType;
32500c16b537SWarner Losh     U32 origSize;
32510c16b537SWarner Losh } blockProperties_t;
32520c16b537SWarner Losh 
32530c16b537SWarner Losh /*! ZSTDv07_getcBlockSize() :
32540c16b537SWarner Losh *   Provides the size of compressed block from block header `src` */
ZSTDv07_getcBlockSize(const void * src,size_t srcSize,blockProperties_t * bpPtr)32550f743729SConrad Meyer static size_t ZSTDv07_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr)
32560c16b537SWarner Losh {
3257*5ff13fbcSAllan Jude     const BYTE* const in = (const BYTE*)src;
32580c16b537SWarner Losh     U32 cSize;
32590c16b537SWarner Losh 
32600c16b537SWarner Losh     if (srcSize < ZSTDv07_blockHeaderSize) return ERROR(srcSize_wrong);
32610c16b537SWarner Losh 
32620c16b537SWarner Losh     bpPtr->blockType = (blockType_t)((*in) >> 6);
32630c16b537SWarner Losh     cSize = in[2] + (in[1]<<8) + ((in[0] & 7)<<16);
32640c16b537SWarner Losh     bpPtr->origSize = (bpPtr->blockType == bt_rle) ? cSize : 0;
32650c16b537SWarner Losh 
32660c16b537SWarner Losh     if (bpPtr->blockType == bt_end) return 0;
32670c16b537SWarner Losh     if (bpPtr->blockType == bt_rle) return 1;
32680c16b537SWarner Losh     return cSize;
32690c16b537SWarner Losh }
32700c16b537SWarner Losh 
32710c16b537SWarner Losh 
ZSTDv07_copyRawBlock(void * dst,size_t dstCapacity,const void * src,size_t srcSize)32720c16b537SWarner Losh static size_t ZSTDv07_copyRawBlock(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
32730c16b537SWarner Losh {
32740c16b537SWarner Losh     if (srcSize > dstCapacity) return ERROR(dstSize_tooSmall);
327537f1f268SConrad Meyer     if (srcSize > 0) {
32760c16b537SWarner Losh         memcpy(dst, src, srcSize);
327737f1f268SConrad Meyer     }
32780c16b537SWarner Losh     return srcSize;
32790c16b537SWarner Losh }
32800c16b537SWarner Losh 
32810c16b537SWarner Losh 
32820c16b537SWarner Losh /*! ZSTDv07_decodeLiteralsBlock() :
32830c16b537SWarner Losh     @return : nb of bytes read from src (< srcSize ) */
ZSTDv07_decodeLiteralsBlock(ZSTDv07_DCtx * dctx,const void * src,size_t srcSize)32840f743729SConrad Meyer static size_t ZSTDv07_decodeLiteralsBlock(ZSTDv07_DCtx* dctx,
32850c16b537SWarner Losh                           const void* src, size_t srcSize)   /* note : srcSize < BLOCKSIZE */
32860c16b537SWarner Losh {
32870c16b537SWarner Losh     const BYTE* const istart = (const BYTE*) src;
32880c16b537SWarner Losh 
32890c16b537SWarner Losh     if (srcSize < MIN_CBLOCK_SIZE) return ERROR(corruption_detected);
32900c16b537SWarner Losh 
32910c16b537SWarner Losh     switch((litBlockType_t)(istart[0]>> 6))
32920c16b537SWarner Losh     {
32930c16b537SWarner Losh     case lbt_huffman:
32940c16b537SWarner Losh         {   size_t litSize, litCSize, singleStream=0;
32950c16b537SWarner Losh             U32 lhSize = (istart[0] >> 4) & 3;
32960c16b537SWarner Losh             if (srcSize < 5) return ERROR(corruption_detected);   /* srcSize >= MIN_CBLOCK_SIZE == 3; here we need up to 5 for lhSize, + cSize (+nbSeq) */
32970c16b537SWarner Losh             switch(lhSize)
32980c16b537SWarner Losh             {
32990c16b537SWarner Losh             case 0: case 1: default:   /* note : default is impossible, since lhSize into [0..3] */
33000c16b537SWarner Losh                 /* 2 - 2 - 10 - 10 */
33010c16b537SWarner Losh                 lhSize=3;
33020c16b537SWarner Losh                 singleStream = istart[0] & 16;
33030c16b537SWarner Losh                 litSize  = ((istart[0] & 15) << 6) + (istart[1] >> 2);
33040c16b537SWarner Losh                 litCSize = ((istart[1] &  3) << 8) + istart[2];
33050c16b537SWarner Losh                 break;
33060c16b537SWarner Losh             case 2:
33070c16b537SWarner Losh                 /* 2 - 2 - 14 - 14 */
33080c16b537SWarner Losh                 lhSize=4;
33090c16b537SWarner Losh                 litSize  = ((istart[0] & 15) << 10) + (istart[1] << 2) + (istart[2] >> 6);
33100c16b537SWarner Losh                 litCSize = ((istart[2] & 63) <<  8) + istart[3];
33110c16b537SWarner Losh                 break;
33120c16b537SWarner Losh             case 3:
33130c16b537SWarner Losh                 /* 2 - 2 - 18 - 18 */
33140c16b537SWarner Losh                 lhSize=5;
33150c16b537SWarner Losh                 litSize  = ((istart[0] & 15) << 14) + (istart[1] << 6) + (istart[2] >> 2);
33160c16b537SWarner Losh                 litCSize = ((istart[2] &  3) << 16) + (istart[3] << 8) + istart[4];
33170c16b537SWarner Losh                 break;
33180c16b537SWarner Losh             }
33190c16b537SWarner Losh             if (litSize > ZSTDv07_BLOCKSIZE_ABSOLUTEMAX) return ERROR(corruption_detected);
33200c16b537SWarner Losh             if (litCSize + lhSize > srcSize) return ERROR(corruption_detected);
33210c16b537SWarner Losh 
33220c16b537SWarner Losh             if (HUFv07_isError(singleStream ?
33230c16b537SWarner Losh                             HUFv07_decompress1X2_DCtx(dctx->hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize) :
33240c16b537SWarner Losh                             HUFv07_decompress4X_hufOnly (dctx->hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize) ))
33250c16b537SWarner Losh                 return ERROR(corruption_detected);
33260c16b537SWarner Losh 
33270c16b537SWarner Losh             dctx->litPtr = dctx->litBuffer;
33280c16b537SWarner Losh             dctx->litSize = litSize;
33290c16b537SWarner Losh             dctx->litEntropy = 1;
33300c16b537SWarner Losh             memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH);
33310c16b537SWarner Losh             return litCSize + lhSize;
33320c16b537SWarner Losh         }
33330c16b537SWarner Losh     case lbt_repeat:
33340c16b537SWarner Losh         {   size_t litSize, litCSize;
33350c16b537SWarner Losh             U32 lhSize = ((istart[0]) >> 4) & 3;
33360c16b537SWarner Losh             if (lhSize != 1)  /* only case supported for now : small litSize, single stream */
33370c16b537SWarner Losh                 return ERROR(corruption_detected);
33380c16b537SWarner Losh             if (dctx->litEntropy==0)
33390c16b537SWarner Losh                 return ERROR(dictionary_corrupted);
33400c16b537SWarner Losh 
33410c16b537SWarner Losh             /* 2 - 2 - 10 - 10 */
33420c16b537SWarner Losh             lhSize=3;
33430c16b537SWarner Losh             litSize  = ((istart[0] & 15) << 6) + (istart[1] >> 2);
33440c16b537SWarner Losh             litCSize = ((istart[1] &  3) << 8) + istart[2];
33450c16b537SWarner Losh             if (litCSize + lhSize > srcSize) return ERROR(corruption_detected);
33460c16b537SWarner Losh 
33470c16b537SWarner Losh             {   size_t const errorCode = HUFv07_decompress1X4_usingDTable(dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->hufTable);
33480c16b537SWarner Losh                 if (HUFv07_isError(errorCode)) return ERROR(corruption_detected);
33490c16b537SWarner Losh             }
33500c16b537SWarner Losh             dctx->litPtr = dctx->litBuffer;
33510c16b537SWarner Losh             dctx->litSize = litSize;
33520c16b537SWarner Losh             memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH);
33530c16b537SWarner Losh             return litCSize + lhSize;
33540c16b537SWarner Losh         }
33550c16b537SWarner Losh     case lbt_raw:
33560c16b537SWarner Losh         {   size_t litSize;
33570c16b537SWarner Losh             U32 lhSize = ((istart[0]) >> 4) & 3;
33580c16b537SWarner Losh             switch(lhSize)
33590c16b537SWarner Losh             {
33600c16b537SWarner Losh             case 0: case 1: default:   /* note : default is impossible, since lhSize into [0..3] */
33610c16b537SWarner Losh                 lhSize=1;
33620c16b537SWarner Losh                 litSize = istart[0] & 31;
33630c16b537SWarner Losh                 break;
33640c16b537SWarner Losh             case 2:
33650c16b537SWarner Losh                 litSize = ((istart[0] & 15) << 8) + istart[1];
33660c16b537SWarner Losh                 break;
33670c16b537SWarner Losh             case 3:
33680c16b537SWarner Losh                 litSize = ((istart[0] & 15) << 16) + (istart[1] << 8) + istart[2];
33690c16b537SWarner Losh                 break;
33700c16b537SWarner Losh             }
33710c16b537SWarner Losh 
33720c16b537SWarner Losh             if (lhSize+litSize+WILDCOPY_OVERLENGTH > srcSize) {  /* risk reading beyond src buffer with wildcopy */
33730c16b537SWarner Losh                 if (litSize+lhSize > srcSize) return ERROR(corruption_detected);
33740c16b537SWarner Losh                 memcpy(dctx->litBuffer, istart+lhSize, litSize);
33750c16b537SWarner Losh                 dctx->litPtr = dctx->litBuffer;
33760c16b537SWarner Losh                 dctx->litSize = litSize;
33770c16b537SWarner Losh                 memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH);
33780c16b537SWarner Losh                 return lhSize+litSize;
33790c16b537SWarner Losh             }
33800c16b537SWarner Losh             /* direct reference into compressed stream */
33810c16b537SWarner Losh             dctx->litPtr = istart+lhSize;
33820c16b537SWarner Losh             dctx->litSize = litSize;
33830c16b537SWarner Losh             return lhSize+litSize;
33840c16b537SWarner Losh         }
33850c16b537SWarner Losh     case lbt_rle:
33860c16b537SWarner Losh         {   size_t litSize;
33870c16b537SWarner Losh             U32 lhSize = ((istart[0]) >> 4) & 3;
33880c16b537SWarner Losh             switch(lhSize)
33890c16b537SWarner Losh             {
33900c16b537SWarner Losh             case 0: case 1: default:   /* note : default is impossible, since lhSize into [0..3] */
33910c16b537SWarner Losh                 lhSize = 1;
33920c16b537SWarner Losh                 litSize = istart[0] & 31;
33930c16b537SWarner Losh                 break;
33940c16b537SWarner Losh             case 2:
33950c16b537SWarner Losh                 litSize = ((istart[0] & 15) << 8) + istart[1];
33960c16b537SWarner Losh                 break;
33970c16b537SWarner Losh             case 3:
33980c16b537SWarner Losh                 litSize = ((istart[0] & 15) << 16) + (istart[1] << 8) + istart[2];
33990c16b537SWarner Losh                 if (srcSize<4) return ERROR(corruption_detected);   /* srcSize >= MIN_CBLOCK_SIZE == 3; here we need lhSize+1 = 4 */
34000c16b537SWarner Losh                 break;
34010c16b537SWarner Losh             }
34020c16b537SWarner Losh             if (litSize > ZSTDv07_BLOCKSIZE_ABSOLUTEMAX) return ERROR(corruption_detected);
34030c16b537SWarner Losh             memset(dctx->litBuffer, istart[lhSize], litSize + WILDCOPY_OVERLENGTH);
34040c16b537SWarner Losh             dctx->litPtr = dctx->litBuffer;
34050c16b537SWarner Losh             dctx->litSize = litSize;
34060c16b537SWarner Losh             return lhSize+1;
34070c16b537SWarner Losh         }
34080c16b537SWarner Losh     default:
34090c16b537SWarner Losh         return ERROR(corruption_detected);   /* impossible */
34100c16b537SWarner Losh     }
34110c16b537SWarner Losh }
34120c16b537SWarner Losh 
34130c16b537SWarner Losh 
34140c16b537SWarner Losh /*! ZSTDv07_buildSeqTable() :
34150c16b537SWarner Losh     @return : nb bytes read from src,
34160c16b537SWarner Losh               or an error code if it fails, testable with ZSTDv07_isError()
34170c16b537SWarner Losh */
ZSTDv07_buildSeqTable(FSEv07_DTable * DTable,U32 type,U32 max,U32 maxLog,const void * src,size_t srcSize,const S16 * defaultNorm,U32 defaultLog,U32 flagRepeatTable)34180f743729SConrad Meyer static size_t ZSTDv07_buildSeqTable(FSEv07_DTable* DTable, U32 type, U32 max, U32 maxLog,
34190c16b537SWarner Losh                                  const void* src, size_t srcSize,
34200c16b537SWarner Losh                                  const S16* defaultNorm, U32 defaultLog, U32 flagRepeatTable)
34210c16b537SWarner Losh {
34220c16b537SWarner Losh     switch(type)
34230c16b537SWarner Losh     {
34240c16b537SWarner Losh     case FSEv07_ENCODING_RLE :
34250c16b537SWarner Losh         if (!srcSize) return ERROR(srcSize_wrong);
34260c16b537SWarner Losh         if ( (*(const BYTE*)src) > max) return ERROR(corruption_detected);
34270c16b537SWarner Losh         FSEv07_buildDTable_rle(DTable, *(const BYTE*)src);   /* if *src > max, data is corrupted */
34280c16b537SWarner Losh         return 1;
34290c16b537SWarner Losh     case FSEv07_ENCODING_RAW :
34300c16b537SWarner Losh         FSEv07_buildDTable(DTable, defaultNorm, max, defaultLog);
34310c16b537SWarner Losh         return 0;
34320c16b537SWarner Losh     case FSEv07_ENCODING_STATIC:
34330c16b537SWarner Losh         if (!flagRepeatTable) return ERROR(corruption_detected);
34340c16b537SWarner Losh         return 0;
34350c16b537SWarner Losh     default :   /* impossible */
34360c16b537SWarner Losh     case FSEv07_ENCODING_DYNAMIC :
34370c16b537SWarner Losh         {   U32 tableLog;
34380c16b537SWarner Losh             S16 norm[MaxSeq+1];
34390c16b537SWarner Losh             size_t const headerSize = FSEv07_readNCount(norm, &max, &tableLog, src, srcSize);
34400c16b537SWarner Losh             if (FSEv07_isError(headerSize)) return ERROR(corruption_detected);
34410c16b537SWarner Losh             if (tableLog > maxLog) return ERROR(corruption_detected);
34420c16b537SWarner Losh             FSEv07_buildDTable(DTable, norm, max, tableLog);
34430c16b537SWarner Losh             return headerSize;
34440c16b537SWarner Losh     }   }
34450c16b537SWarner Losh }
34460c16b537SWarner Losh 
34470c16b537SWarner Losh 
ZSTDv07_decodeSeqHeaders(int * nbSeqPtr,FSEv07_DTable * DTableLL,FSEv07_DTable * DTableML,FSEv07_DTable * DTableOffb,U32 flagRepeatTable,const void * src,size_t srcSize)34480f743729SConrad Meyer static size_t ZSTDv07_decodeSeqHeaders(int* nbSeqPtr,
34490c16b537SWarner Losh                              FSEv07_DTable* DTableLL, FSEv07_DTable* DTableML, FSEv07_DTable* DTableOffb, U32 flagRepeatTable,
34500c16b537SWarner Losh                              const void* src, size_t srcSize)
34510c16b537SWarner Losh {
3452*5ff13fbcSAllan Jude     const BYTE* const istart = (const BYTE*)src;
34530c16b537SWarner Losh     const BYTE* const iend = istart + srcSize;
34540c16b537SWarner Losh     const BYTE* ip = istart;
34550c16b537SWarner Losh 
34560c16b537SWarner Losh     /* check */
34570c16b537SWarner Losh     if (srcSize < MIN_SEQUENCES_SIZE) return ERROR(srcSize_wrong);
34580c16b537SWarner Losh 
34590c16b537SWarner Losh     /* SeqHead */
34600c16b537SWarner Losh     {   int nbSeq = *ip++;
34610c16b537SWarner Losh         if (!nbSeq) { *nbSeqPtr=0; return 1; }
34620c16b537SWarner Losh         if (nbSeq > 0x7F) {
34630c16b537SWarner Losh             if (nbSeq == 0xFF) {
34640c16b537SWarner Losh                 if (ip+2 > iend) return ERROR(srcSize_wrong);
34650c16b537SWarner Losh                 nbSeq = MEM_readLE16(ip) + LONGNBSEQ, ip+=2;
34660c16b537SWarner Losh             } else {
34670c16b537SWarner Losh                 if (ip >= iend) return ERROR(srcSize_wrong);
34680c16b537SWarner Losh                 nbSeq = ((nbSeq-0x80)<<8) + *ip++;
34690c16b537SWarner Losh             }
34700c16b537SWarner Losh         }
34710c16b537SWarner Losh         *nbSeqPtr = nbSeq;
34720c16b537SWarner Losh     }
34730c16b537SWarner Losh 
34740c16b537SWarner Losh     /* FSE table descriptors */
34754d3f1eafSConrad Meyer     if (ip + 4 > iend) return ERROR(srcSize_wrong); /* min : header byte + all 3 are "raw", hence no header, but at least xxLog bits per type */
34760c16b537SWarner Losh     {   U32 const LLtype  = *ip >> 6;
34770c16b537SWarner Losh         U32 const OFtype = (*ip >> 4) & 3;
34780c16b537SWarner Losh         U32 const MLtype  = (*ip >> 2) & 3;
34790c16b537SWarner Losh         ip++;
34800c16b537SWarner Losh 
34810c16b537SWarner Losh         /* Build DTables */
34820c16b537SWarner Losh         {   size_t const llhSize = ZSTDv07_buildSeqTable(DTableLL, LLtype, MaxLL, LLFSELog, ip, iend-ip, LL_defaultNorm, LL_defaultNormLog, flagRepeatTable);
34830c16b537SWarner Losh             if (ZSTDv07_isError(llhSize)) return ERROR(corruption_detected);
34840c16b537SWarner Losh             ip += llhSize;
34850c16b537SWarner Losh         }
34860c16b537SWarner Losh         {   size_t const ofhSize = ZSTDv07_buildSeqTable(DTableOffb, OFtype, MaxOff, OffFSELog, ip, iend-ip, OF_defaultNorm, OF_defaultNormLog, flagRepeatTable);
34870c16b537SWarner Losh             if (ZSTDv07_isError(ofhSize)) return ERROR(corruption_detected);
34880c16b537SWarner Losh             ip += ofhSize;
34890c16b537SWarner Losh         }
34900c16b537SWarner Losh         {   size_t const mlhSize = ZSTDv07_buildSeqTable(DTableML, MLtype, MaxML, MLFSELog, ip, iend-ip, ML_defaultNorm, ML_defaultNormLog, flagRepeatTable);
34910c16b537SWarner Losh             if (ZSTDv07_isError(mlhSize)) return ERROR(corruption_detected);
34920c16b537SWarner Losh             ip += mlhSize;
34930c16b537SWarner Losh     }   }
34940c16b537SWarner Losh 
34950c16b537SWarner Losh     return ip-istart;
34960c16b537SWarner Losh }
34970c16b537SWarner Losh 
34980c16b537SWarner Losh 
34990c16b537SWarner Losh typedef struct {
35000c16b537SWarner Losh     size_t litLength;
35010c16b537SWarner Losh     size_t matchLength;
35020c16b537SWarner Losh     size_t offset;
35030c16b537SWarner Losh } seq_t;
35040c16b537SWarner Losh 
35050c16b537SWarner Losh typedef struct {
35060c16b537SWarner Losh     BITv07_DStream_t DStream;
35070c16b537SWarner Losh     FSEv07_DState_t stateLL;
35080c16b537SWarner Losh     FSEv07_DState_t stateOffb;
35090c16b537SWarner Losh     FSEv07_DState_t stateML;
35100c16b537SWarner Losh     size_t prevOffset[ZSTDv07_REP_INIT];
35110c16b537SWarner Losh } seqState_t;
35120c16b537SWarner Losh 
35130c16b537SWarner Losh 
ZSTDv07_decodeSequence(seqState_t * seqState)35140c16b537SWarner Losh static seq_t ZSTDv07_decodeSequence(seqState_t* seqState)
35150c16b537SWarner Losh {
35160c16b537SWarner Losh     seq_t seq;
35170c16b537SWarner Losh 
35180c16b537SWarner Losh     U32 const llCode = FSEv07_peekSymbol(&(seqState->stateLL));
35190c16b537SWarner Losh     U32 const mlCode = FSEv07_peekSymbol(&(seqState->stateML));
35200c16b537SWarner Losh     U32 const ofCode = FSEv07_peekSymbol(&(seqState->stateOffb));   /* <= maxOff, by table construction */
35210c16b537SWarner Losh 
35220c16b537SWarner Losh     U32 const llBits = LL_bits[llCode];
35230c16b537SWarner Losh     U32 const mlBits = ML_bits[mlCode];
35240c16b537SWarner Losh     U32 const ofBits = ofCode;
35250c16b537SWarner Losh     U32 const totalBits = llBits+mlBits+ofBits;
35260c16b537SWarner Losh 
35270c16b537SWarner Losh     static const U32 LL_base[MaxLL+1] = {
35280c16b537SWarner Losh                              0,  1,  2,  3,  4,  5,  6,  7,  8,  9,   10,    11,    12,    13,    14,     15,
35290c16b537SWarner Losh                             16, 18, 20, 22, 24, 28, 32, 40, 48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000,
35300c16b537SWarner Losh                             0x2000, 0x4000, 0x8000, 0x10000 };
35310c16b537SWarner Losh 
35320c16b537SWarner Losh     static const U32 ML_base[MaxML+1] = {
35330c16b537SWarner Losh                              3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13,   14,    15,    16,    17,    18,
35340c16b537SWarner Losh                             19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,   30,    31,    32,    33,    34,
35350c16b537SWarner Losh                             35, 37, 39, 41, 43, 47, 51, 59, 67, 83, 99, 0x83, 0x103, 0x203, 0x403, 0x803,
35360c16b537SWarner Losh                             0x1003, 0x2003, 0x4003, 0x8003, 0x10003 };
35370c16b537SWarner Losh 
35380c16b537SWarner Losh     static const U32 OF_base[MaxOff+1] = {
35390c16b537SWarner Losh                  0,        1,       1,       5,     0xD,     0x1D,     0x3D,     0x7D,
35400c16b537SWarner Losh                  0xFD,   0x1FD,   0x3FD,   0x7FD,   0xFFD,   0x1FFD,   0x3FFD,   0x7FFD,
35410c16b537SWarner Losh                  0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD, 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD,
35420c16b537SWarner Losh                  0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD };
35430c16b537SWarner Losh 
35440c16b537SWarner Losh     /* sequence */
35450c16b537SWarner Losh     {   size_t offset;
35460c16b537SWarner Losh         if (!ofCode)
35470c16b537SWarner Losh             offset = 0;
35480c16b537SWarner Losh         else {
35490c16b537SWarner Losh             offset = OF_base[ofCode] + BITv07_readBits(&(seqState->DStream), ofBits);   /* <=  (ZSTDv07_WINDOWLOG_MAX-1) bits */
35500c16b537SWarner Losh             if (MEM_32bits()) BITv07_reloadDStream(&(seqState->DStream));
35510c16b537SWarner Losh         }
35520c16b537SWarner Losh 
35530c16b537SWarner Losh         if (ofCode <= 1) {
35540c16b537SWarner Losh             if ((llCode == 0) & (offset <= 1)) offset = 1-offset;
35550c16b537SWarner Losh             if (offset) {
35560c16b537SWarner Losh                 size_t const temp = seqState->prevOffset[offset];
35570c16b537SWarner Losh                 if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1];
35580c16b537SWarner Losh                 seqState->prevOffset[1] = seqState->prevOffset[0];
35590c16b537SWarner Losh                 seqState->prevOffset[0] = offset = temp;
35600c16b537SWarner Losh             } else {
35610c16b537SWarner Losh                 offset = seqState->prevOffset[0];
35620c16b537SWarner Losh             }
35630c16b537SWarner Losh         } else {
35640c16b537SWarner Losh             seqState->prevOffset[2] = seqState->prevOffset[1];
35650c16b537SWarner Losh             seqState->prevOffset[1] = seqState->prevOffset[0];
35660c16b537SWarner Losh             seqState->prevOffset[0] = offset;
35670c16b537SWarner Losh         }
35680c16b537SWarner Losh         seq.offset = offset;
35690c16b537SWarner Losh     }
35700c16b537SWarner Losh 
35710c16b537SWarner Losh     seq.matchLength = ML_base[mlCode] + ((mlCode>31) ? BITv07_readBits(&(seqState->DStream), mlBits) : 0);   /* <=  16 bits */
35720c16b537SWarner Losh     if (MEM_32bits() && (mlBits+llBits>24)) BITv07_reloadDStream(&(seqState->DStream));
35730c16b537SWarner Losh 
35740c16b537SWarner Losh     seq.litLength = LL_base[llCode] + ((llCode>15) ? BITv07_readBits(&(seqState->DStream), llBits) : 0);   /* <=  16 bits */
35750c16b537SWarner Losh     if (MEM_32bits() ||
35760c16b537SWarner Losh        (totalBits > 64 - 7 - (LLFSELog+MLFSELog+OffFSELog)) ) BITv07_reloadDStream(&(seqState->DStream));
35770c16b537SWarner Losh 
35780c16b537SWarner Losh     /* ANS state update */
35790c16b537SWarner Losh     FSEv07_updateState(&(seqState->stateLL), &(seqState->DStream));   /* <=  9 bits */
35800c16b537SWarner Losh     FSEv07_updateState(&(seqState->stateML), &(seqState->DStream));   /* <=  9 bits */
35810c16b537SWarner Losh     if (MEM_32bits()) BITv07_reloadDStream(&(seqState->DStream));     /* <= 18 bits */
35820c16b537SWarner Losh     FSEv07_updateState(&(seqState->stateOffb), &(seqState->DStream)); /* <=  8 bits */
35830c16b537SWarner Losh 
35840c16b537SWarner Losh     return seq;
35850c16b537SWarner Losh }
35860c16b537SWarner Losh 
35870c16b537SWarner Losh 
35880c16b537SWarner Losh static
ZSTDv07_execSequence(BYTE * op,BYTE * const oend,seq_t sequence,const BYTE ** litPtr,const BYTE * const litLimit,const BYTE * const base,const BYTE * const vBase,const BYTE * const dictEnd)35890c16b537SWarner Losh size_t ZSTDv07_execSequence(BYTE* op,
35900c16b537SWarner Losh                                 BYTE* const oend, seq_t sequence,
35910c16b537SWarner Losh                                 const BYTE** litPtr, const BYTE* const litLimit,
35920c16b537SWarner Losh                                 const BYTE* const base, const BYTE* const vBase, const BYTE* const dictEnd)
35930c16b537SWarner Losh {
35940c16b537SWarner Losh     BYTE* const oLitEnd = op + sequence.litLength;
35950c16b537SWarner Losh     size_t const sequenceLength = sequence.litLength + sequence.matchLength;
35960c16b537SWarner Losh     BYTE* const oMatchEnd = op + sequenceLength;   /* risk : address space overflow (32-bits) */
35970c16b537SWarner Losh     BYTE* const oend_w = oend-WILDCOPY_OVERLENGTH;
35980c16b537SWarner Losh     const BYTE* const iLitEnd = *litPtr + sequence.litLength;
35990c16b537SWarner Losh     const BYTE* match = oLitEnd - sequence.offset;
36000c16b537SWarner Losh 
36010c16b537SWarner Losh     /* check */
36020c16b537SWarner Losh     if ((oLitEnd>oend_w) | (oMatchEnd>oend)) return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of WILDCOPY_OVERLENGTH from oend */
36030c16b537SWarner Losh     if (iLitEnd > litLimit) return ERROR(corruption_detected);   /* over-read beyond lit buffer */
36040c16b537SWarner Losh 
36050c16b537SWarner Losh     /* copy Literals */
36060c16b537SWarner Losh     ZSTDv07_wildcopy(op, *litPtr, sequence.litLength);   /* note : since oLitEnd <= oend-WILDCOPY_OVERLENGTH, no risk of overwrite beyond oend */
36070c16b537SWarner Losh     op = oLitEnd;
36080c16b537SWarner Losh     *litPtr = iLitEnd;   /* update for next sequence */
36090c16b537SWarner Losh 
36100c16b537SWarner Losh     /* copy Match */
36110c16b537SWarner Losh     if (sequence.offset > (size_t)(oLitEnd - base)) {
36120c16b537SWarner Losh         /* offset beyond prefix */
36130c16b537SWarner Losh         if (sequence.offset > (size_t)(oLitEnd - vBase)) return ERROR(corruption_detected);
36140c16b537SWarner Losh         match = dictEnd - (base-match);
36150c16b537SWarner Losh         if (match + sequence.matchLength <= dictEnd) {
36160c16b537SWarner Losh             memmove(oLitEnd, match, sequence.matchLength);
36170c16b537SWarner Losh             return sequenceLength;
36180c16b537SWarner Losh         }
36190c16b537SWarner Losh         /* span extDict & currentPrefixSegment */
36200c16b537SWarner Losh         {   size_t const length1 = dictEnd - match;
36210c16b537SWarner Losh             memmove(oLitEnd, match, length1);
36220c16b537SWarner Losh             op = oLitEnd + length1;
36230c16b537SWarner Losh             sequence.matchLength -= length1;
36240c16b537SWarner Losh             match = base;
36250c16b537SWarner Losh             if (op > oend_w || sequence.matchLength < MINMATCH) {
36260c16b537SWarner Losh               while (op < oMatchEnd) *op++ = *match++;
36270c16b537SWarner Losh               return sequenceLength;
36280c16b537SWarner Losh             }
36290c16b537SWarner Losh     }   }
36300c16b537SWarner Losh     /* Requirement: op <= oend_w */
36310c16b537SWarner Losh 
36320c16b537SWarner Losh     /* match within prefix */
36330c16b537SWarner Losh     if (sequence.offset < 8) {
36340c16b537SWarner Losh         /* close range match, overlap */
36350c16b537SWarner Losh         static const U32 dec32table[] = { 0, 1, 2, 1, 4, 4, 4, 4 };   /* added */
36362b9c00cbSConrad Meyer         static const int dec64table[] = { 8, 8, 8, 7, 8, 9,10,11 };   /* subtracted */
36370c16b537SWarner Losh         int const sub2 = dec64table[sequence.offset];
36380c16b537SWarner Losh         op[0] = match[0];
36390c16b537SWarner Losh         op[1] = match[1];
36400c16b537SWarner Losh         op[2] = match[2];
36410c16b537SWarner Losh         op[3] = match[3];
36420c16b537SWarner Losh         match += dec32table[sequence.offset];
36430c16b537SWarner Losh         ZSTDv07_copy4(op+4, match);
36440c16b537SWarner Losh         match -= sub2;
36450c16b537SWarner Losh     } else {
36460c16b537SWarner Losh         ZSTDv07_copy8(op, match);
36470c16b537SWarner Losh     }
36480c16b537SWarner Losh     op += 8; match += 8;
36490c16b537SWarner Losh 
36500c16b537SWarner Losh     if (oMatchEnd > oend-(16-MINMATCH)) {
36510c16b537SWarner Losh         if (op < oend_w) {
36520c16b537SWarner Losh             ZSTDv07_wildcopy(op, match, oend_w - op);
36530c16b537SWarner Losh             match += oend_w - op;
36540c16b537SWarner Losh             op = oend_w;
36550c16b537SWarner Losh         }
36560c16b537SWarner Losh         while (op < oMatchEnd) *op++ = *match++;
36570c16b537SWarner Losh     } else {
36580c16b537SWarner Losh         ZSTDv07_wildcopy(op, match, (ptrdiff_t)sequence.matchLength-8);   /* works even if matchLength < 8 */
36590c16b537SWarner Losh     }
36600c16b537SWarner Losh     return sequenceLength;
36610c16b537SWarner Losh }
36620c16b537SWarner Losh 
36630c16b537SWarner Losh 
ZSTDv07_decompressSequences(ZSTDv07_DCtx * dctx,void * dst,size_t maxDstSize,const void * seqStart,size_t seqSize)36640c16b537SWarner Losh static size_t ZSTDv07_decompressSequences(
36650c16b537SWarner Losh                                ZSTDv07_DCtx* dctx,
36660c16b537SWarner Losh                                void* dst, size_t maxDstSize,
36670c16b537SWarner Losh                          const void* seqStart, size_t seqSize)
36680c16b537SWarner Losh {
36690c16b537SWarner Losh     const BYTE* ip = (const BYTE*)seqStart;
36700c16b537SWarner Losh     const BYTE* const iend = ip + seqSize;
3671*5ff13fbcSAllan Jude     BYTE* const ostart = (BYTE*)dst;
36720c16b537SWarner Losh     BYTE* const oend = ostart + maxDstSize;
36730c16b537SWarner Losh     BYTE* op = ostart;
36740c16b537SWarner Losh     const BYTE* litPtr = dctx->litPtr;
36750c16b537SWarner Losh     const BYTE* const litEnd = litPtr + dctx->litSize;
36760c16b537SWarner Losh     FSEv07_DTable* DTableLL = dctx->LLTable;
36770c16b537SWarner Losh     FSEv07_DTable* DTableML = dctx->MLTable;
36780c16b537SWarner Losh     FSEv07_DTable* DTableOffb = dctx->OffTable;
36790c16b537SWarner Losh     const BYTE* const base = (const BYTE*) (dctx->base);
36800c16b537SWarner Losh     const BYTE* const vBase = (const BYTE*) (dctx->vBase);
36810c16b537SWarner Losh     const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd);
36820c16b537SWarner Losh     int nbSeq;
36830c16b537SWarner Losh 
36840c16b537SWarner Losh     /* Build Decoding Tables */
36850c16b537SWarner Losh     {   size_t const seqHSize = ZSTDv07_decodeSeqHeaders(&nbSeq, DTableLL, DTableML, DTableOffb, dctx->fseEntropy, ip, seqSize);
36860c16b537SWarner Losh         if (ZSTDv07_isError(seqHSize)) return seqHSize;
36870c16b537SWarner Losh         ip += seqHSize;
36880c16b537SWarner Losh     }
36890c16b537SWarner Losh 
36900c16b537SWarner Losh     /* Regen sequences */
36910c16b537SWarner Losh     if (nbSeq) {
36920c16b537SWarner Losh         seqState_t seqState;
36930c16b537SWarner Losh         dctx->fseEntropy = 1;
36940c16b537SWarner Losh         { U32 i; for (i=0; i<ZSTDv07_REP_INIT; i++) seqState.prevOffset[i] = dctx->rep[i]; }
36950c16b537SWarner Losh         { size_t const errorCode = BITv07_initDStream(&(seqState.DStream), ip, iend-ip);
36960c16b537SWarner Losh           if (ERR_isError(errorCode)) return ERROR(corruption_detected); }
36970c16b537SWarner Losh         FSEv07_initDState(&(seqState.stateLL), &(seqState.DStream), DTableLL);
36980c16b537SWarner Losh         FSEv07_initDState(&(seqState.stateOffb), &(seqState.DStream), DTableOffb);
36990c16b537SWarner Losh         FSEv07_initDState(&(seqState.stateML), &(seqState.DStream), DTableML);
37000c16b537SWarner Losh 
37010c16b537SWarner Losh         for ( ; (BITv07_reloadDStream(&(seqState.DStream)) <= BITv07_DStream_completed) && nbSeq ; ) {
37020c16b537SWarner Losh             nbSeq--;
37030c16b537SWarner Losh             {   seq_t const sequence = ZSTDv07_decodeSequence(&seqState);
37040c16b537SWarner Losh                 size_t const oneSeqSize = ZSTDv07_execSequence(op, oend, sequence, &litPtr, litEnd, base, vBase, dictEnd);
37050c16b537SWarner Losh                 if (ZSTDv07_isError(oneSeqSize)) return oneSeqSize;
37060c16b537SWarner Losh                 op += oneSeqSize;
37070c16b537SWarner Losh         }   }
37080c16b537SWarner Losh 
37090c16b537SWarner Losh         /* check if reached exact end */
37100c16b537SWarner Losh         if (nbSeq) return ERROR(corruption_detected);
37110c16b537SWarner Losh         /* save reps for next block */
37120c16b537SWarner Losh         { U32 i; for (i=0; i<ZSTDv07_REP_INIT; i++) dctx->rep[i] = (U32)(seqState.prevOffset[i]); }
37130c16b537SWarner Losh     }
37140c16b537SWarner Losh 
37150c16b537SWarner Losh     /* last literal segment */
37160c16b537SWarner Losh     {   size_t const lastLLSize = litEnd - litPtr;
371737f1f268SConrad Meyer         /* if (litPtr > litEnd) return ERROR(corruption_detected); */   /* too many literals already used */
37180c16b537SWarner Losh         if (lastLLSize > (size_t)(oend-op)) return ERROR(dstSize_tooSmall);
371937f1f268SConrad Meyer         if (lastLLSize > 0) {
37200c16b537SWarner Losh             memcpy(op, litPtr, lastLLSize);
37210c16b537SWarner Losh             op += lastLLSize;
37220c16b537SWarner Losh         }
372337f1f268SConrad Meyer     }
37240c16b537SWarner Losh 
37250c16b537SWarner Losh     return op-ostart;
37260c16b537SWarner Losh }
37270c16b537SWarner Losh 
37280c16b537SWarner Losh 
ZSTDv07_checkContinuity(ZSTDv07_DCtx * dctx,const void * dst)37290c16b537SWarner Losh static void ZSTDv07_checkContinuity(ZSTDv07_DCtx* dctx, const void* dst)
37300c16b537SWarner Losh {
37310c16b537SWarner Losh     if (dst != dctx->previousDstEnd) {   /* not contiguous */
37320c16b537SWarner Losh         dctx->dictEnd = dctx->previousDstEnd;
37330c16b537SWarner Losh         dctx->vBase = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->base));
37340c16b537SWarner Losh         dctx->base = dst;
37350c16b537SWarner Losh         dctx->previousDstEnd = dst;
37360c16b537SWarner Losh     }
37370c16b537SWarner Losh }
37380c16b537SWarner Losh 
37390c16b537SWarner Losh 
ZSTDv07_decompressBlock_internal(ZSTDv07_DCtx * dctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize)37400c16b537SWarner Losh static size_t ZSTDv07_decompressBlock_internal(ZSTDv07_DCtx* dctx,
37410c16b537SWarner Losh                             void* dst, size_t dstCapacity,
37420c16b537SWarner Losh                       const void* src, size_t srcSize)
37430c16b537SWarner Losh {   /* blockType == blockCompressed */
37440c16b537SWarner Losh     const BYTE* ip = (const BYTE*)src;
37450c16b537SWarner Losh 
37460c16b537SWarner Losh     if (srcSize >= ZSTDv07_BLOCKSIZE_ABSOLUTEMAX) return ERROR(srcSize_wrong);
37470c16b537SWarner Losh 
37480c16b537SWarner Losh     /* Decode literals sub-block */
37490c16b537SWarner Losh     {   size_t const litCSize = ZSTDv07_decodeLiteralsBlock(dctx, src, srcSize);
37500c16b537SWarner Losh         if (ZSTDv07_isError(litCSize)) return litCSize;
37510c16b537SWarner Losh         ip += litCSize;
37520c16b537SWarner Losh         srcSize -= litCSize;
37530c16b537SWarner Losh     }
37540c16b537SWarner Losh     return ZSTDv07_decompressSequences(dctx, dst, dstCapacity, ip, srcSize);
37550c16b537SWarner Losh }
37560c16b537SWarner Losh 
37570c16b537SWarner Losh 
ZSTDv07_decompressBlock(ZSTDv07_DCtx * dctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize)37580c16b537SWarner Losh size_t ZSTDv07_decompressBlock(ZSTDv07_DCtx* dctx,
37590c16b537SWarner Losh                             void* dst, size_t dstCapacity,
37600c16b537SWarner Losh                       const void* src, size_t srcSize)
37610c16b537SWarner Losh {
37620c16b537SWarner Losh     size_t dSize;
37630c16b537SWarner Losh     ZSTDv07_checkContinuity(dctx, dst);
37640c16b537SWarner Losh     dSize = ZSTDv07_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize);
37650c16b537SWarner Losh     dctx->previousDstEnd = (char*)dst + dSize;
37660c16b537SWarner Losh     return dSize;
37670c16b537SWarner Losh }
37680c16b537SWarner Losh 
37690c16b537SWarner Losh 
37700c16b537SWarner Losh /** ZSTDv07_insertBlock() :
37710c16b537SWarner Losh     insert `src` block into `dctx` history. Useful to track uncompressed blocks. */
ZSTDv07_insertBlock(ZSTDv07_DCtx * dctx,const void * blockStart,size_t blockSize)37720c16b537SWarner Losh ZSTDLIBv07_API size_t ZSTDv07_insertBlock(ZSTDv07_DCtx* dctx, const void* blockStart, size_t blockSize)
37730c16b537SWarner Losh {
37740c16b537SWarner Losh     ZSTDv07_checkContinuity(dctx, blockStart);
37750c16b537SWarner Losh     dctx->previousDstEnd = (const char*)blockStart + blockSize;
37760c16b537SWarner Losh     return blockSize;
37770c16b537SWarner Losh }
37780c16b537SWarner Losh 
37790c16b537SWarner Losh 
ZSTDv07_generateNxBytes(void * dst,size_t dstCapacity,BYTE byte,size_t length)37800f743729SConrad Meyer static size_t ZSTDv07_generateNxBytes(void* dst, size_t dstCapacity, BYTE byte, size_t length)
37810c16b537SWarner Losh {
37820c16b537SWarner Losh     if (length > dstCapacity) return ERROR(dstSize_tooSmall);
378337f1f268SConrad Meyer     if (length > 0) {
37840c16b537SWarner Losh         memset(dst, byte, length);
378537f1f268SConrad Meyer     }
37860c16b537SWarner Losh     return length;
37870c16b537SWarner Losh }
37880c16b537SWarner Losh 
37890c16b537SWarner Losh 
37900c16b537SWarner Losh /*! ZSTDv07_decompressFrame() :
37910c16b537SWarner Losh *   `dctx` must be properly initialized */
ZSTDv07_decompressFrame(ZSTDv07_DCtx * dctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize)37920c16b537SWarner Losh static size_t ZSTDv07_decompressFrame(ZSTDv07_DCtx* dctx,
37930c16b537SWarner Losh                                  void* dst, size_t dstCapacity,
37940c16b537SWarner Losh                                  const void* src, size_t srcSize)
37950c16b537SWarner Losh {
37960c16b537SWarner Losh     const BYTE* ip = (const BYTE*)src;
37970c16b537SWarner Losh     const BYTE* const iend = ip + srcSize;
3798*5ff13fbcSAllan Jude     BYTE* const ostart = (BYTE*)dst;
37990c16b537SWarner Losh     BYTE* const oend = ostart + dstCapacity;
38000c16b537SWarner Losh     BYTE* op = ostart;
38010c16b537SWarner Losh     size_t remainingSize = srcSize;
38020c16b537SWarner Losh 
38030c16b537SWarner Losh     /* check */
38040c16b537SWarner Losh     if (srcSize < ZSTDv07_frameHeaderSize_min+ZSTDv07_blockHeaderSize) return ERROR(srcSize_wrong);
38050c16b537SWarner Losh 
38060c16b537SWarner Losh     /* Frame Header */
38070c16b537SWarner Losh     {   size_t const frameHeaderSize = ZSTDv07_frameHeaderSize(src, ZSTDv07_frameHeaderSize_min);
38080c16b537SWarner Losh         if (ZSTDv07_isError(frameHeaderSize)) return frameHeaderSize;
38090c16b537SWarner Losh         if (srcSize < frameHeaderSize+ZSTDv07_blockHeaderSize) return ERROR(srcSize_wrong);
38100c16b537SWarner Losh         if (ZSTDv07_decodeFrameHeader(dctx, src, frameHeaderSize)) return ERROR(corruption_detected);
38110c16b537SWarner Losh         ip += frameHeaderSize; remainingSize -= frameHeaderSize;
38120c16b537SWarner Losh     }
38130c16b537SWarner Losh 
38140c16b537SWarner Losh     /* Loop on each block */
38150c16b537SWarner Losh     while (1) {
38160c16b537SWarner Losh         size_t decodedSize;
38170c16b537SWarner Losh         blockProperties_t blockProperties;
38180c16b537SWarner Losh         size_t const cBlockSize = ZSTDv07_getcBlockSize(ip, iend-ip, &blockProperties);
38190c16b537SWarner Losh         if (ZSTDv07_isError(cBlockSize)) return cBlockSize;
38200c16b537SWarner Losh 
38210c16b537SWarner Losh         ip += ZSTDv07_blockHeaderSize;
38220c16b537SWarner Losh         remainingSize -= ZSTDv07_blockHeaderSize;
38230c16b537SWarner Losh         if (cBlockSize > remainingSize) return ERROR(srcSize_wrong);
38240c16b537SWarner Losh 
38250c16b537SWarner Losh         switch(blockProperties.blockType)
38260c16b537SWarner Losh         {
38270c16b537SWarner Losh         case bt_compressed:
38280c16b537SWarner Losh             decodedSize = ZSTDv07_decompressBlock_internal(dctx, op, oend-op, ip, cBlockSize);
38290c16b537SWarner Losh             break;
38300c16b537SWarner Losh         case bt_raw :
38310c16b537SWarner Losh             decodedSize = ZSTDv07_copyRawBlock(op, oend-op, ip, cBlockSize);
38320c16b537SWarner Losh             break;
38330c16b537SWarner Losh         case bt_rle :
38340c16b537SWarner Losh             decodedSize = ZSTDv07_generateNxBytes(op, oend-op, *ip, blockProperties.origSize);
38350c16b537SWarner Losh             break;
38360c16b537SWarner Losh         case bt_end :
38370c16b537SWarner Losh             /* end of frame */
38380c16b537SWarner Losh             if (remainingSize) return ERROR(srcSize_wrong);
38390c16b537SWarner Losh             decodedSize = 0;
38400c16b537SWarner Losh             break;
38410c16b537SWarner Losh         default:
38420c16b537SWarner Losh             return ERROR(GENERIC);   /* impossible */
38430c16b537SWarner Losh         }
38440c16b537SWarner Losh         if (blockProperties.blockType == bt_end) break;   /* bt_end */
38450c16b537SWarner Losh 
38460c16b537SWarner Losh         if (ZSTDv07_isError(decodedSize)) return decodedSize;
38470c16b537SWarner Losh         if (dctx->fParams.checksumFlag) XXH64_update(&dctx->xxhState, op, decodedSize);
38480c16b537SWarner Losh         op += decodedSize;
38490c16b537SWarner Losh         ip += cBlockSize;
38500c16b537SWarner Losh         remainingSize -= cBlockSize;
38510c16b537SWarner Losh     }
38520c16b537SWarner Losh 
38530c16b537SWarner Losh     return op-ostart;
38540c16b537SWarner Losh }
38550c16b537SWarner Losh 
38560c16b537SWarner Losh 
38570c16b537SWarner Losh /*! ZSTDv07_decompress_usingPreparedDCtx() :
38580c16b537SWarner Losh *   Same as ZSTDv07_decompress_usingDict, but using a reference context `preparedDCtx`, where dictionary has been loaded.
38590c16b537SWarner Losh *   It avoids reloading the dictionary each time.
38600c16b537SWarner Losh *   `preparedDCtx` must have been properly initialized using ZSTDv07_decompressBegin_usingDict().
38610c16b537SWarner Losh *   Requires 2 contexts : 1 for reference (preparedDCtx), which will not be modified, and 1 to run the decompression operation (dctx) */
ZSTDv07_decompress_usingPreparedDCtx(ZSTDv07_DCtx * dctx,const ZSTDv07_DCtx * refDCtx,void * dst,size_t dstCapacity,const void * src,size_t srcSize)38620f743729SConrad Meyer static size_t ZSTDv07_decompress_usingPreparedDCtx(ZSTDv07_DCtx* dctx, const ZSTDv07_DCtx* refDCtx,
38630c16b537SWarner Losh                                          void* dst, size_t dstCapacity,
38640c16b537SWarner Losh                                    const void* src, size_t srcSize)
38650c16b537SWarner Losh {
38660c16b537SWarner Losh     ZSTDv07_copyDCtx(dctx, refDCtx);
38670c16b537SWarner Losh     ZSTDv07_checkContinuity(dctx, dst);
38680c16b537SWarner Losh     return ZSTDv07_decompressFrame(dctx, dst, dstCapacity, src, srcSize);
38690c16b537SWarner Losh }
38700c16b537SWarner Losh 
38710c16b537SWarner Losh 
ZSTDv07_decompress_usingDict(ZSTDv07_DCtx * dctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize,const void * dict,size_t dictSize)38720c16b537SWarner Losh size_t ZSTDv07_decompress_usingDict(ZSTDv07_DCtx* dctx,
38730c16b537SWarner Losh                                  void* dst, size_t dstCapacity,
38740c16b537SWarner Losh                                  const void* src, size_t srcSize,
38750c16b537SWarner Losh                                  const void* dict, size_t dictSize)
38760c16b537SWarner Losh {
38770c16b537SWarner Losh     ZSTDv07_decompressBegin_usingDict(dctx, dict, dictSize);
38780c16b537SWarner Losh     ZSTDv07_checkContinuity(dctx, dst);
38790c16b537SWarner Losh     return ZSTDv07_decompressFrame(dctx, dst, dstCapacity, src, srcSize);
38800c16b537SWarner Losh }
38810c16b537SWarner Losh 
38820c16b537SWarner Losh 
ZSTDv07_decompressDCtx(ZSTDv07_DCtx * dctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize)38830c16b537SWarner Losh size_t ZSTDv07_decompressDCtx(ZSTDv07_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
38840c16b537SWarner Losh {
38850c16b537SWarner Losh     return ZSTDv07_decompress_usingDict(dctx, dst, dstCapacity, src, srcSize, NULL, 0);
38860c16b537SWarner Losh }
38870c16b537SWarner Losh 
38880c16b537SWarner Losh 
ZSTDv07_decompress(void * dst,size_t dstCapacity,const void * src,size_t srcSize)38890c16b537SWarner Losh size_t ZSTDv07_decompress(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
38900c16b537SWarner Losh {
38910c16b537SWarner Losh #if defined(ZSTDv07_HEAPMODE) && (ZSTDv07_HEAPMODE==1)
38920c16b537SWarner Losh     size_t regenSize;
38930c16b537SWarner Losh     ZSTDv07_DCtx* const dctx = ZSTDv07_createDCtx();
38940c16b537SWarner Losh     if (dctx==NULL) return ERROR(memory_allocation);
38950c16b537SWarner Losh     regenSize = ZSTDv07_decompressDCtx(dctx, dst, dstCapacity, src, srcSize);
38960c16b537SWarner Losh     ZSTDv07_freeDCtx(dctx);
38970c16b537SWarner Losh     return regenSize;
38980c16b537SWarner Losh #else   /* stack mode */
38990c16b537SWarner Losh     ZSTDv07_DCtx dctx;
39000c16b537SWarner Losh     return ZSTDv07_decompressDCtx(&dctx, dst, dstCapacity, src, srcSize);
39010c16b537SWarner Losh #endif
39020c16b537SWarner Losh }
39030c16b537SWarner Losh 
39042b9c00cbSConrad Meyer /* ZSTD_errorFrameSizeInfoLegacy() :
39052b9c00cbSConrad Meyer    assumes `cSize` and `dBound` are _not_ NULL */
ZSTD_errorFrameSizeInfoLegacy(size_t * cSize,unsigned long long * dBound,size_t ret)39062b9c00cbSConrad Meyer static void ZSTD_errorFrameSizeInfoLegacy(size_t* cSize, unsigned long long* dBound, size_t ret)
39072b9c00cbSConrad Meyer {
39082b9c00cbSConrad Meyer     *cSize = ret;
39092b9c00cbSConrad Meyer     *dBound = ZSTD_CONTENTSIZE_ERROR;
39102b9c00cbSConrad Meyer }
39112b9c00cbSConrad Meyer 
ZSTDv07_findFrameSizeInfoLegacy(const void * src,size_t srcSize,size_t * cSize,unsigned long long * dBound)39122b9c00cbSConrad Meyer void ZSTDv07_findFrameSizeInfoLegacy(const void *src, size_t srcSize, size_t* cSize, unsigned long long* dBound)
39130c16b537SWarner Losh {
39140c16b537SWarner Losh     const BYTE* ip = (const BYTE*)src;
39150c16b537SWarner Losh     size_t remainingSize = srcSize;
39162b9c00cbSConrad Meyer     size_t nbBlocks = 0;
39170c16b537SWarner Losh 
39180c16b537SWarner Losh     /* check */
39192b9c00cbSConrad Meyer     if (srcSize < ZSTDv07_frameHeaderSize_min+ZSTDv07_blockHeaderSize) {
39202b9c00cbSConrad Meyer         ZSTD_errorFrameSizeInfoLegacy(cSize, dBound, ERROR(srcSize_wrong));
39212b9c00cbSConrad Meyer         return;
39222b9c00cbSConrad Meyer     }
39230c16b537SWarner Losh 
39240c16b537SWarner Losh     /* Frame Header */
39254d3f1eafSConrad Meyer     {   size_t const frameHeaderSize = ZSTDv07_frameHeaderSize(src, srcSize);
39262b9c00cbSConrad Meyer         if (ZSTDv07_isError(frameHeaderSize)) {
39272b9c00cbSConrad Meyer             ZSTD_errorFrameSizeInfoLegacy(cSize, dBound, frameHeaderSize);
39282b9c00cbSConrad Meyer             return;
39292b9c00cbSConrad Meyer         }
39302b9c00cbSConrad Meyer         if (MEM_readLE32(src) != ZSTDv07_MAGICNUMBER) {
39312b9c00cbSConrad Meyer             ZSTD_errorFrameSizeInfoLegacy(cSize, dBound, ERROR(prefix_unknown));
39322b9c00cbSConrad Meyer             return;
39332b9c00cbSConrad Meyer         }
39342b9c00cbSConrad Meyer         if (srcSize < frameHeaderSize+ZSTDv07_blockHeaderSize) {
39352b9c00cbSConrad Meyer             ZSTD_errorFrameSizeInfoLegacy(cSize, dBound, ERROR(srcSize_wrong));
39362b9c00cbSConrad Meyer             return;
39372b9c00cbSConrad Meyer         }
39380c16b537SWarner Losh         ip += frameHeaderSize; remainingSize -= frameHeaderSize;
39390c16b537SWarner Losh     }
39400c16b537SWarner Losh 
39410c16b537SWarner Losh     /* Loop on each block */
39420c16b537SWarner Losh     while (1) {
39430c16b537SWarner Losh         blockProperties_t blockProperties;
39440c16b537SWarner Losh         size_t const cBlockSize = ZSTDv07_getcBlockSize(ip, remainingSize, &blockProperties);
39452b9c00cbSConrad Meyer         if (ZSTDv07_isError(cBlockSize)) {
39462b9c00cbSConrad Meyer             ZSTD_errorFrameSizeInfoLegacy(cSize, dBound, cBlockSize);
39472b9c00cbSConrad Meyer             return;
39482b9c00cbSConrad Meyer         }
39490c16b537SWarner Losh 
39500c16b537SWarner Losh         ip += ZSTDv07_blockHeaderSize;
39510c16b537SWarner Losh         remainingSize -= ZSTDv07_blockHeaderSize;
39520c16b537SWarner Losh 
39530c16b537SWarner Losh         if (blockProperties.blockType == bt_end) break;
39540c16b537SWarner Losh 
39552b9c00cbSConrad Meyer         if (cBlockSize > remainingSize) {
39562b9c00cbSConrad Meyer             ZSTD_errorFrameSizeInfoLegacy(cSize, dBound, ERROR(srcSize_wrong));
39572b9c00cbSConrad Meyer             return;
39582b9c00cbSConrad Meyer         }
39590c16b537SWarner Losh 
39600c16b537SWarner Losh         ip += cBlockSize;
39610c16b537SWarner Losh         remainingSize -= cBlockSize;
39622b9c00cbSConrad Meyer         nbBlocks++;
39630c16b537SWarner Losh     }
39640c16b537SWarner Losh 
39652b9c00cbSConrad Meyer     *cSize = ip - (const BYTE*)src;
39662b9c00cbSConrad Meyer     *dBound = nbBlocks * ZSTDv07_BLOCKSIZE_ABSOLUTEMAX;
39670c16b537SWarner Losh }
39680c16b537SWarner Losh 
39690c16b537SWarner Losh /*_******************************
39700c16b537SWarner Losh *  Streaming Decompression API
39710c16b537SWarner Losh ********************************/
ZSTDv07_nextSrcSizeToDecompress(ZSTDv07_DCtx * dctx)39720c16b537SWarner Losh size_t ZSTDv07_nextSrcSizeToDecompress(ZSTDv07_DCtx* dctx)
39730c16b537SWarner Losh {
39740c16b537SWarner Losh     return dctx->expected;
39750c16b537SWarner Losh }
39760c16b537SWarner Losh 
ZSTDv07_isSkipFrame(ZSTDv07_DCtx * dctx)39770c16b537SWarner Losh int ZSTDv07_isSkipFrame(ZSTDv07_DCtx* dctx)
39780c16b537SWarner Losh {
39790c16b537SWarner Losh     return dctx->stage == ZSTDds_skipFrame;
39800c16b537SWarner Losh }
39810c16b537SWarner Losh 
39820c16b537SWarner Losh /** ZSTDv07_decompressContinue() :
39830c16b537SWarner Losh *   @return : nb of bytes generated into `dst` (necessarily <= `dstCapacity)
39840c16b537SWarner Losh *             or an error code, which can be tested using ZSTDv07_isError() */
ZSTDv07_decompressContinue(ZSTDv07_DCtx * dctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize)39850c16b537SWarner Losh size_t ZSTDv07_decompressContinue(ZSTDv07_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
39860c16b537SWarner Losh {
39870c16b537SWarner Losh     /* Sanity check */
39880c16b537SWarner Losh     if (srcSize != dctx->expected) return ERROR(srcSize_wrong);
39890c16b537SWarner Losh     if (dstCapacity) ZSTDv07_checkContinuity(dctx, dst);
39900c16b537SWarner Losh 
39910c16b537SWarner Losh     switch (dctx->stage)
39920c16b537SWarner Losh     {
39930c16b537SWarner Losh     case ZSTDds_getFrameHeaderSize :
39940c16b537SWarner Losh         if (srcSize != ZSTDv07_frameHeaderSize_min) return ERROR(srcSize_wrong);   /* impossible */
39950c16b537SWarner Losh         if ((MEM_readLE32(src) & 0xFFFFFFF0U) == ZSTDv07_MAGIC_SKIPPABLE_START) {
39960c16b537SWarner Losh             memcpy(dctx->headerBuffer, src, ZSTDv07_frameHeaderSize_min);
39970c16b537SWarner Losh             dctx->expected = ZSTDv07_skippableHeaderSize - ZSTDv07_frameHeaderSize_min; /* magic number + skippable frame length */
39980c16b537SWarner Losh             dctx->stage = ZSTDds_decodeSkippableHeader;
39990c16b537SWarner Losh             return 0;
40000c16b537SWarner Losh         }
40010c16b537SWarner Losh         dctx->headerSize = ZSTDv07_frameHeaderSize(src, ZSTDv07_frameHeaderSize_min);
40020c16b537SWarner Losh         if (ZSTDv07_isError(dctx->headerSize)) return dctx->headerSize;
40030c16b537SWarner Losh         memcpy(dctx->headerBuffer, src, ZSTDv07_frameHeaderSize_min);
40040c16b537SWarner Losh         if (dctx->headerSize > ZSTDv07_frameHeaderSize_min) {
40050c16b537SWarner Losh             dctx->expected = dctx->headerSize - ZSTDv07_frameHeaderSize_min;
40060c16b537SWarner Losh             dctx->stage = ZSTDds_decodeFrameHeader;
40070c16b537SWarner Losh             return 0;
40080c16b537SWarner Losh         }
40090c16b537SWarner Losh         dctx->expected = 0;   /* not necessary to copy more */
40100c16b537SWarner Losh 	/* fall-through */
40110c16b537SWarner Losh     case ZSTDds_decodeFrameHeader:
40120c16b537SWarner Losh         {   size_t result;
40130c16b537SWarner Losh             memcpy(dctx->headerBuffer + ZSTDv07_frameHeaderSize_min, src, dctx->expected);
40140c16b537SWarner Losh             result = ZSTDv07_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize);
40150c16b537SWarner Losh             if (ZSTDv07_isError(result)) return result;
40160c16b537SWarner Losh             dctx->expected = ZSTDv07_blockHeaderSize;
40170c16b537SWarner Losh             dctx->stage = ZSTDds_decodeBlockHeader;
40180c16b537SWarner Losh             return 0;
40190c16b537SWarner Losh         }
40200c16b537SWarner Losh     case ZSTDds_decodeBlockHeader:
40210c16b537SWarner Losh         {   blockProperties_t bp;
40220c16b537SWarner Losh             size_t const cBlockSize = ZSTDv07_getcBlockSize(src, ZSTDv07_blockHeaderSize, &bp);
40230c16b537SWarner Losh             if (ZSTDv07_isError(cBlockSize)) return cBlockSize;
40240c16b537SWarner Losh             if (bp.blockType == bt_end) {
40250c16b537SWarner Losh                 if (dctx->fParams.checksumFlag) {
40260c16b537SWarner Losh                     U64 const h64 = XXH64_digest(&dctx->xxhState);
40270c16b537SWarner Losh                     U32 const h32 = (U32)(h64>>11) & ((1<<22)-1);
40280c16b537SWarner Losh                     const BYTE* const ip = (const BYTE*)src;
40290c16b537SWarner Losh                     U32 const check32 = ip[2] + (ip[1] << 8) + ((ip[0] & 0x3F) << 16);
40300c16b537SWarner Losh                     if (check32 != h32) return ERROR(checksum_wrong);
40310c16b537SWarner Losh                 }
40320c16b537SWarner Losh                 dctx->expected = 0;
40330c16b537SWarner Losh                 dctx->stage = ZSTDds_getFrameHeaderSize;
40340c16b537SWarner Losh             } else {
40350c16b537SWarner Losh                 dctx->expected = cBlockSize;
40360c16b537SWarner Losh                 dctx->bType = bp.blockType;
40370c16b537SWarner Losh                 dctx->stage = ZSTDds_decompressBlock;
40380c16b537SWarner Losh             }
40390c16b537SWarner Losh             return 0;
40400c16b537SWarner Losh         }
40410c16b537SWarner Losh     case ZSTDds_decompressBlock:
40420c16b537SWarner Losh         {   size_t rSize;
40430c16b537SWarner Losh             switch(dctx->bType)
40440c16b537SWarner Losh             {
40450c16b537SWarner Losh             case bt_compressed:
40460c16b537SWarner Losh                 rSize = ZSTDv07_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize);
40470c16b537SWarner Losh                 break;
40480c16b537SWarner Losh             case bt_raw :
40490c16b537SWarner Losh                 rSize = ZSTDv07_copyRawBlock(dst, dstCapacity, src, srcSize);
40500c16b537SWarner Losh                 break;
40510c16b537SWarner Losh             case bt_rle :
40520c16b537SWarner Losh                 return ERROR(GENERIC);   /* not yet handled */
40530c16b537SWarner Losh                 break;
40540c16b537SWarner Losh             case bt_end :   /* should never happen (filtered at phase 1) */
40550c16b537SWarner Losh                 rSize = 0;
40560c16b537SWarner Losh                 break;
40570c16b537SWarner Losh             default:
40580c16b537SWarner Losh                 return ERROR(GENERIC);   /* impossible */
40590c16b537SWarner Losh             }
40600c16b537SWarner Losh             dctx->stage = ZSTDds_decodeBlockHeader;
40610c16b537SWarner Losh             dctx->expected = ZSTDv07_blockHeaderSize;
40620c16b537SWarner Losh             dctx->previousDstEnd = (char*)dst + rSize;
40630c16b537SWarner Losh             if (ZSTDv07_isError(rSize)) return rSize;
40640c16b537SWarner Losh             if (dctx->fParams.checksumFlag) XXH64_update(&dctx->xxhState, dst, rSize);
40650c16b537SWarner Losh             return rSize;
40660c16b537SWarner Losh         }
40670c16b537SWarner Losh     case ZSTDds_decodeSkippableHeader:
40680c16b537SWarner Losh         {   memcpy(dctx->headerBuffer + ZSTDv07_frameHeaderSize_min, src, dctx->expected);
40690c16b537SWarner Losh             dctx->expected = MEM_readLE32(dctx->headerBuffer + 4);
40700c16b537SWarner Losh             dctx->stage = ZSTDds_skipFrame;
40710c16b537SWarner Losh             return 0;
40720c16b537SWarner Losh         }
40730c16b537SWarner Losh     case ZSTDds_skipFrame:
40740c16b537SWarner Losh         {   dctx->expected = 0;
40750c16b537SWarner Losh             dctx->stage = ZSTDds_getFrameHeaderSize;
40760c16b537SWarner Losh             return 0;
40770c16b537SWarner Losh         }
40780c16b537SWarner Losh     default:
40790c16b537SWarner Losh         return ERROR(GENERIC);   /* impossible */
40800c16b537SWarner Losh     }
40810c16b537SWarner Losh }
40820c16b537SWarner Losh 
40830c16b537SWarner Losh 
ZSTDv07_refDictContent(ZSTDv07_DCtx * dctx,const void * dict,size_t dictSize)40840c16b537SWarner Losh static size_t ZSTDv07_refDictContent(ZSTDv07_DCtx* dctx, const void* dict, size_t dictSize)
40850c16b537SWarner Losh {
40860c16b537SWarner Losh     dctx->dictEnd = dctx->previousDstEnd;
40870c16b537SWarner Losh     dctx->vBase = (const char*)dict - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->base));
40880c16b537SWarner Losh     dctx->base = dict;
40890c16b537SWarner Losh     dctx->previousDstEnd = (const char*)dict + dictSize;
40900c16b537SWarner Losh     return 0;
40910c16b537SWarner Losh }
40920c16b537SWarner Losh 
ZSTDv07_loadEntropy(ZSTDv07_DCtx * dctx,const void * const dict,size_t const dictSize)40930c16b537SWarner Losh static size_t ZSTDv07_loadEntropy(ZSTDv07_DCtx* dctx, const void* const dict, size_t const dictSize)
40940c16b537SWarner Losh {
40950c16b537SWarner Losh     const BYTE* dictPtr = (const BYTE*)dict;
40960c16b537SWarner Losh     const BYTE* const dictEnd = dictPtr + dictSize;
40970c16b537SWarner Losh 
40980c16b537SWarner Losh     {   size_t const hSize = HUFv07_readDTableX4(dctx->hufTable, dict, dictSize);
40990c16b537SWarner Losh         if (HUFv07_isError(hSize)) return ERROR(dictionary_corrupted);
41000c16b537SWarner Losh         dictPtr += hSize;
41010c16b537SWarner Losh     }
41020c16b537SWarner Losh 
41030c16b537SWarner Losh     {   short offcodeNCount[MaxOff+1];
41040c16b537SWarner Losh         U32 offcodeMaxValue=MaxOff, offcodeLog;
41050c16b537SWarner Losh         size_t const offcodeHeaderSize = FSEv07_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
41060c16b537SWarner Losh         if (FSEv07_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
41070c16b537SWarner Losh         if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted);
41080c16b537SWarner Losh         { size_t const errorCode = FSEv07_buildDTable(dctx->OffTable, offcodeNCount, offcodeMaxValue, offcodeLog);
41090c16b537SWarner Losh           if (FSEv07_isError(errorCode)) return ERROR(dictionary_corrupted); }
41100c16b537SWarner Losh         dictPtr += offcodeHeaderSize;
41110c16b537SWarner Losh     }
41120c16b537SWarner Losh 
41130c16b537SWarner Losh     {   short matchlengthNCount[MaxML+1];
41140c16b537SWarner Losh         unsigned matchlengthMaxValue = MaxML, matchlengthLog;
41150c16b537SWarner Losh         size_t const matchlengthHeaderSize = FSEv07_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
41160c16b537SWarner Losh         if (FSEv07_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
41170c16b537SWarner Losh         if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
41180c16b537SWarner Losh         { size_t const errorCode = FSEv07_buildDTable(dctx->MLTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog);
41190c16b537SWarner Losh           if (FSEv07_isError(errorCode)) return ERROR(dictionary_corrupted); }
41200c16b537SWarner Losh         dictPtr += matchlengthHeaderSize;
41210c16b537SWarner Losh     }
41220c16b537SWarner Losh 
41230c16b537SWarner Losh     {   short litlengthNCount[MaxLL+1];
41240c16b537SWarner Losh         unsigned litlengthMaxValue = MaxLL, litlengthLog;
41250c16b537SWarner Losh         size_t const litlengthHeaderSize = FSEv07_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
41260c16b537SWarner Losh         if (FSEv07_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
41270c16b537SWarner Losh         if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
41280c16b537SWarner Losh         { size_t const errorCode = FSEv07_buildDTable(dctx->LLTable, litlengthNCount, litlengthMaxValue, litlengthLog);
41290c16b537SWarner Losh           if (FSEv07_isError(errorCode)) return ERROR(dictionary_corrupted); }
41300c16b537SWarner Losh         dictPtr += litlengthHeaderSize;
41310c16b537SWarner Losh     }
41320c16b537SWarner Losh 
41330c16b537SWarner Losh     if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
41340c16b537SWarner Losh     dctx->rep[0] = MEM_readLE32(dictPtr+0); if (dctx->rep[0] == 0 || dctx->rep[0] >= dictSize) return ERROR(dictionary_corrupted);
41350c16b537SWarner Losh     dctx->rep[1] = MEM_readLE32(dictPtr+4); if (dctx->rep[1] == 0 || dctx->rep[1] >= dictSize) return ERROR(dictionary_corrupted);
41360c16b537SWarner Losh     dctx->rep[2] = MEM_readLE32(dictPtr+8); if (dctx->rep[2] == 0 || dctx->rep[2] >= dictSize) return ERROR(dictionary_corrupted);
41370c16b537SWarner Losh     dictPtr += 12;
41380c16b537SWarner Losh 
41390c16b537SWarner Losh     dctx->litEntropy = dctx->fseEntropy = 1;
41400c16b537SWarner Losh     return dictPtr - (const BYTE*)dict;
41410c16b537SWarner Losh }
41420c16b537SWarner Losh 
ZSTDv07_decompress_insertDictionary(ZSTDv07_DCtx * dctx,const void * dict,size_t dictSize)41430c16b537SWarner Losh static size_t ZSTDv07_decompress_insertDictionary(ZSTDv07_DCtx* dctx, const void* dict, size_t dictSize)
41440c16b537SWarner Losh {
41450c16b537SWarner Losh     if (dictSize < 8) return ZSTDv07_refDictContent(dctx, dict, dictSize);
41460c16b537SWarner Losh     {   U32 const magic = MEM_readLE32(dict);
41470c16b537SWarner Losh         if (magic != ZSTDv07_DICT_MAGIC) {
41480c16b537SWarner Losh             return ZSTDv07_refDictContent(dctx, dict, dictSize);   /* pure content mode */
41490c16b537SWarner Losh     }   }
41500c16b537SWarner Losh     dctx->dictID = MEM_readLE32((const char*)dict + 4);
41510c16b537SWarner Losh 
41520c16b537SWarner Losh     /* load entropy tables */
41530c16b537SWarner Losh     dict = (const char*)dict + 8;
41540c16b537SWarner Losh     dictSize -= 8;
41550c16b537SWarner Losh     {   size_t const eSize = ZSTDv07_loadEntropy(dctx, dict, dictSize);
41560c16b537SWarner Losh         if (ZSTDv07_isError(eSize)) return ERROR(dictionary_corrupted);
41570c16b537SWarner Losh         dict = (const char*)dict + eSize;
41580c16b537SWarner Losh         dictSize -= eSize;
41590c16b537SWarner Losh     }
41600c16b537SWarner Losh 
41610c16b537SWarner Losh     /* reference dictionary content */
41620c16b537SWarner Losh     return ZSTDv07_refDictContent(dctx, dict, dictSize);
41630c16b537SWarner Losh }
41640c16b537SWarner Losh 
41650c16b537SWarner Losh 
ZSTDv07_decompressBegin_usingDict(ZSTDv07_DCtx * dctx,const void * dict,size_t dictSize)41660c16b537SWarner Losh size_t ZSTDv07_decompressBegin_usingDict(ZSTDv07_DCtx* dctx, const void* dict, size_t dictSize)
41670c16b537SWarner Losh {
41680c16b537SWarner Losh     { size_t const errorCode = ZSTDv07_decompressBegin(dctx);
41690c16b537SWarner Losh       if (ZSTDv07_isError(errorCode)) return errorCode; }
41700c16b537SWarner Losh 
41710c16b537SWarner Losh     if (dict && dictSize) {
41720c16b537SWarner Losh         size_t const errorCode = ZSTDv07_decompress_insertDictionary(dctx, dict, dictSize);
41730c16b537SWarner Losh         if (ZSTDv07_isError(errorCode)) return ERROR(dictionary_corrupted);
41740c16b537SWarner Losh     }
41750c16b537SWarner Losh 
41760c16b537SWarner Losh     return 0;
41770c16b537SWarner Losh }
41780c16b537SWarner Losh 
41790c16b537SWarner Losh 
41800c16b537SWarner Losh struct ZSTDv07_DDict_s {
41810c16b537SWarner Losh     void* dict;
41820c16b537SWarner Losh     size_t dictSize;
41830c16b537SWarner Losh     ZSTDv07_DCtx* refContext;
41840c16b537SWarner Losh };  /* typedef'd tp ZSTDv07_CDict within zstd.h */
41850c16b537SWarner Losh 
ZSTDv07_createDDict_advanced(const void * dict,size_t dictSize,ZSTDv07_customMem customMem)41860f743729SConrad Meyer static ZSTDv07_DDict* ZSTDv07_createDDict_advanced(const void* dict, size_t dictSize, ZSTDv07_customMem customMem)
41870c16b537SWarner Losh {
41880c16b537SWarner Losh     if (!customMem.customAlloc && !customMem.customFree)
41890c16b537SWarner Losh         customMem = defaultCustomMem;
41900c16b537SWarner Losh 
41910c16b537SWarner Losh     if (!customMem.customAlloc || !customMem.customFree)
41920c16b537SWarner Losh         return NULL;
41930c16b537SWarner Losh 
41940c16b537SWarner Losh     {   ZSTDv07_DDict* const ddict = (ZSTDv07_DDict*) customMem.customAlloc(customMem.opaque, sizeof(*ddict));
41950c16b537SWarner Losh         void* const dictContent = customMem.customAlloc(customMem.opaque, dictSize);
41960c16b537SWarner Losh         ZSTDv07_DCtx* const dctx = ZSTDv07_createDCtx_advanced(customMem);
41970c16b537SWarner Losh 
41980c16b537SWarner Losh         if (!dictContent || !ddict || !dctx) {
41990c16b537SWarner Losh             customMem.customFree(customMem.opaque, dictContent);
42000c16b537SWarner Losh             customMem.customFree(customMem.opaque, ddict);
42010c16b537SWarner Losh             customMem.customFree(customMem.opaque, dctx);
42020c16b537SWarner Losh             return NULL;
42030c16b537SWarner Losh         }
42040c16b537SWarner Losh 
42050c16b537SWarner Losh         memcpy(dictContent, dict, dictSize);
42060c16b537SWarner Losh         {   size_t const errorCode = ZSTDv07_decompressBegin_usingDict(dctx, dictContent, dictSize);
42070c16b537SWarner Losh             if (ZSTDv07_isError(errorCode)) {
42080c16b537SWarner Losh                 customMem.customFree(customMem.opaque, dictContent);
42090c16b537SWarner Losh                 customMem.customFree(customMem.opaque, ddict);
42100c16b537SWarner Losh                 customMem.customFree(customMem.opaque, dctx);
42110c16b537SWarner Losh                 return NULL;
42120c16b537SWarner Losh         }   }
42130c16b537SWarner Losh 
42140c16b537SWarner Losh         ddict->dict = dictContent;
42150c16b537SWarner Losh         ddict->dictSize = dictSize;
42160c16b537SWarner Losh         ddict->refContext = dctx;
42170c16b537SWarner Losh         return ddict;
42180c16b537SWarner Losh     }
42190c16b537SWarner Losh }
42200c16b537SWarner Losh 
42210c16b537SWarner Losh /*! ZSTDv07_createDDict() :
42220c16b537SWarner Losh *   Create a digested dictionary, ready to start decompression without startup delay.
42230c16b537SWarner Losh *   `dict` can be released after `ZSTDv07_DDict` creation */
ZSTDv07_createDDict(const void * dict,size_t dictSize)42240c16b537SWarner Losh ZSTDv07_DDict* ZSTDv07_createDDict(const void* dict, size_t dictSize)
42250c16b537SWarner Losh {
42260c16b537SWarner Losh     ZSTDv07_customMem const allocator = { NULL, NULL, NULL };
42270c16b537SWarner Losh     return ZSTDv07_createDDict_advanced(dict, dictSize, allocator);
42280c16b537SWarner Losh }
42290c16b537SWarner Losh 
ZSTDv07_freeDDict(ZSTDv07_DDict * ddict)42300c16b537SWarner Losh size_t ZSTDv07_freeDDict(ZSTDv07_DDict* ddict)
42310c16b537SWarner Losh {
42320c16b537SWarner Losh     ZSTDv07_freeFunction const cFree = ddict->refContext->customMem.customFree;
42330c16b537SWarner Losh     void* const opaque = ddict->refContext->customMem.opaque;
42340c16b537SWarner Losh     ZSTDv07_freeDCtx(ddict->refContext);
42350c16b537SWarner Losh     cFree(opaque, ddict->dict);
42360c16b537SWarner Losh     cFree(opaque, ddict);
42370c16b537SWarner Losh     return 0;
42380c16b537SWarner Losh }
42390c16b537SWarner Losh 
42400c16b537SWarner Losh /*! ZSTDv07_decompress_usingDDict() :
42410c16b537SWarner Losh *   Decompression using a pre-digested Dictionary
42420c16b537SWarner Losh *   Use dictionary without significant overhead. */
ZSTDv07_decompress_usingDDict(ZSTDv07_DCtx * dctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize,const ZSTDv07_DDict * ddict)42430c16b537SWarner Losh ZSTDLIBv07_API size_t ZSTDv07_decompress_usingDDict(ZSTDv07_DCtx* dctx,
42440c16b537SWarner Losh                                            void* dst, size_t dstCapacity,
42450c16b537SWarner Losh                                      const void* src, size_t srcSize,
42460c16b537SWarner Losh                                      const ZSTDv07_DDict* ddict)
42470c16b537SWarner Losh {
42480c16b537SWarner Losh     return ZSTDv07_decompress_usingPreparedDCtx(dctx, ddict->refContext,
42490c16b537SWarner Losh                                            dst, dstCapacity,
42500c16b537SWarner Losh                                            src, srcSize);
42510c16b537SWarner Losh }
42520c16b537SWarner Losh /*
42530c16b537SWarner Losh     Buffered version of Zstd compression library
42540c16b537SWarner Losh     Copyright (C) 2015-2016, Yann Collet.
42550c16b537SWarner Losh 
42560c16b537SWarner Losh     BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
42570c16b537SWarner Losh 
42580c16b537SWarner Losh     Redistribution and use in source and binary forms, with or without
42590c16b537SWarner Losh     modification, are permitted provided that the following conditions are
42600c16b537SWarner Losh     met:
42610c16b537SWarner Losh     * Redistributions of source code must retain the above copyright
42620c16b537SWarner Losh     notice, this list of conditions and the following disclaimer.
42630c16b537SWarner Losh     * Redistributions in binary form must reproduce the above
42640c16b537SWarner Losh     copyright notice, this list of conditions and the following disclaimer
42650c16b537SWarner Losh     in the documentation and/or other materials provided with the
42660c16b537SWarner Losh     distribution.
42670c16b537SWarner Losh     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
42680c16b537SWarner Losh     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
42690c16b537SWarner Losh     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
42700c16b537SWarner Losh     A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
42710c16b537SWarner Losh     OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42720c16b537SWarner Losh     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42730c16b537SWarner Losh     LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42740c16b537SWarner Losh     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
42750c16b537SWarner Losh     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
42760c16b537SWarner Losh     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
42770c16b537SWarner Losh     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42780c16b537SWarner Losh 
42790c16b537SWarner Losh     You can contact the author at :
42800c16b537SWarner Losh     - zstd homepage : http://www.zstd.net/
42810c16b537SWarner Losh */
42820c16b537SWarner Losh 
42830c16b537SWarner Losh 
42840c16b537SWarner Losh 
42850c16b537SWarner Losh /*-***************************************************************************
42860c16b537SWarner Losh *  Streaming decompression howto
42870c16b537SWarner Losh *
42880c16b537SWarner Losh *  A ZBUFFv07_DCtx object is required to track streaming operations.
42890c16b537SWarner Losh *  Use ZBUFFv07_createDCtx() and ZBUFFv07_freeDCtx() to create/release resources.
42900c16b537SWarner Losh *  Use ZBUFFv07_decompressInit() to start a new decompression operation,
42910c16b537SWarner Losh *   or ZBUFFv07_decompressInitDictionary() if decompression requires a dictionary.
42920c16b537SWarner Losh *  Note that ZBUFFv07_DCtx objects can be re-init multiple times.
42930c16b537SWarner Losh *
42940c16b537SWarner Losh *  Use ZBUFFv07_decompressContinue() repetitively to consume your input.
42950c16b537SWarner Losh *  *srcSizePtr and *dstCapacityPtr can be any size.
42960c16b537SWarner Losh *  The function will report how many bytes were read or written by modifying *srcSizePtr and *dstCapacityPtr.
42970c16b537SWarner Losh *  Note that it may not consume the entire input, in which case it's up to the caller to present remaining input again.
42980c16b537SWarner Losh *  The content of @dst will be overwritten (up to *dstCapacityPtr) at each function call, so save its content if it matters, or change @dst.
42990c16b537SWarner Losh *  @return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to help latency),
43000c16b537SWarner Losh *            or 0 when a frame is completely decoded,
43010c16b537SWarner Losh *            or an error code, which can be tested using ZBUFFv07_isError().
43020c16b537SWarner Losh *
43030c16b537SWarner Losh *  Hint : recommended buffer sizes (not compulsory) : ZBUFFv07_recommendedDInSize() and ZBUFFv07_recommendedDOutSize()
43040c16b537SWarner Losh *  output : ZBUFFv07_recommendedDOutSize==128 KB block size is the internal unit, it ensures it's always possible to write a full block when decoded.
43050c16b537SWarner Losh *  input  : ZBUFFv07_recommendedDInSize == 128KB + 3;
43060c16b537SWarner Losh *           just follow indications from ZBUFFv07_decompressContinue() to minimize latency. It should always be <= 128 KB + 3 .
43070c16b537SWarner Losh * *******************************************************************************/
43080c16b537SWarner Losh 
43090c16b537SWarner Losh typedef enum { ZBUFFds_init, ZBUFFds_loadHeader,
43100c16b537SWarner Losh                ZBUFFds_read, ZBUFFds_load, ZBUFFds_flush } ZBUFFv07_dStage;
43110c16b537SWarner Losh 
43120c16b537SWarner Losh /* *** Resource management *** */
43130c16b537SWarner Losh struct ZBUFFv07_DCtx_s {
43140c16b537SWarner Losh     ZSTDv07_DCtx* zd;
43150c16b537SWarner Losh     ZSTDv07_frameParams fParams;
43160c16b537SWarner Losh     ZBUFFv07_dStage stage;
43170c16b537SWarner Losh     char*  inBuff;
43180c16b537SWarner Losh     size_t inBuffSize;
43190c16b537SWarner Losh     size_t inPos;
43200c16b537SWarner Losh     char*  outBuff;
43210c16b537SWarner Losh     size_t outBuffSize;
43220c16b537SWarner Losh     size_t outStart;
43230c16b537SWarner Losh     size_t outEnd;
43240c16b537SWarner Losh     size_t blockSize;
43250c16b537SWarner Losh     BYTE headerBuffer[ZSTDv07_FRAMEHEADERSIZE_MAX];
43260c16b537SWarner Losh     size_t lhSize;
43270c16b537SWarner Losh     ZSTDv07_customMem customMem;
43280c16b537SWarner Losh };   /* typedef'd to ZBUFFv07_DCtx within "zstd_buffered.h" */
43290c16b537SWarner Losh 
43300c16b537SWarner Losh ZSTDLIBv07_API ZBUFFv07_DCtx* ZBUFFv07_createDCtx_advanced(ZSTDv07_customMem customMem);
43310c16b537SWarner Losh 
ZBUFFv07_createDCtx(void)43320c16b537SWarner Losh ZBUFFv07_DCtx* ZBUFFv07_createDCtx(void)
43330c16b537SWarner Losh {
43340c16b537SWarner Losh     return ZBUFFv07_createDCtx_advanced(defaultCustomMem);
43350c16b537SWarner Losh }
43360c16b537SWarner Losh 
ZBUFFv07_createDCtx_advanced(ZSTDv07_customMem customMem)43370c16b537SWarner Losh ZBUFFv07_DCtx* ZBUFFv07_createDCtx_advanced(ZSTDv07_customMem customMem)
43380c16b537SWarner Losh {
43390c16b537SWarner Losh     ZBUFFv07_DCtx* zbd;
43400c16b537SWarner Losh 
43410c16b537SWarner Losh     if (!customMem.customAlloc && !customMem.customFree)
43420c16b537SWarner Losh         customMem = defaultCustomMem;
43430c16b537SWarner Losh 
43440c16b537SWarner Losh     if (!customMem.customAlloc || !customMem.customFree)
43450c16b537SWarner Losh         return NULL;
43460c16b537SWarner Losh 
43470c16b537SWarner Losh     zbd = (ZBUFFv07_DCtx*)customMem.customAlloc(customMem.opaque, sizeof(ZBUFFv07_DCtx));
43480c16b537SWarner Losh     if (zbd==NULL) return NULL;
43490c16b537SWarner Losh     memset(zbd, 0, sizeof(ZBUFFv07_DCtx));
43500c16b537SWarner Losh     memcpy(&zbd->customMem, &customMem, sizeof(ZSTDv07_customMem));
43510c16b537SWarner Losh     zbd->zd = ZSTDv07_createDCtx_advanced(customMem);
43520c16b537SWarner Losh     if (zbd->zd == NULL) { ZBUFFv07_freeDCtx(zbd); return NULL; }
43530c16b537SWarner Losh     zbd->stage = ZBUFFds_init;
43540c16b537SWarner Losh     return zbd;
43550c16b537SWarner Losh }
43560c16b537SWarner Losh 
ZBUFFv07_freeDCtx(ZBUFFv07_DCtx * zbd)43570c16b537SWarner Losh size_t ZBUFFv07_freeDCtx(ZBUFFv07_DCtx* zbd)
43580c16b537SWarner Losh {
43590c16b537SWarner Losh     if (zbd==NULL) return 0;   /* support free on null */
43600c16b537SWarner Losh     ZSTDv07_freeDCtx(zbd->zd);
43610c16b537SWarner Losh     if (zbd->inBuff) zbd->customMem.customFree(zbd->customMem.opaque, zbd->inBuff);
43620c16b537SWarner Losh     if (zbd->outBuff) zbd->customMem.customFree(zbd->customMem.opaque, zbd->outBuff);
43630c16b537SWarner Losh     zbd->customMem.customFree(zbd->customMem.opaque, zbd);
43640c16b537SWarner Losh     return 0;
43650c16b537SWarner Losh }
43660c16b537SWarner Losh 
43670c16b537SWarner Losh 
43680c16b537SWarner Losh /* *** Initialization *** */
43690c16b537SWarner Losh 
ZBUFFv07_decompressInitDictionary(ZBUFFv07_DCtx * zbd,const void * dict,size_t dictSize)43700c16b537SWarner Losh size_t ZBUFFv07_decompressInitDictionary(ZBUFFv07_DCtx* zbd, const void* dict, size_t dictSize)
43710c16b537SWarner Losh {
43720c16b537SWarner Losh     zbd->stage = ZBUFFds_loadHeader;
43730c16b537SWarner Losh     zbd->lhSize = zbd->inPos = zbd->outStart = zbd->outEnd = 0;
43740c16b537SWarner Losh     return ZSTDv07_decompressBegin_usingDict(zbd->zd, dict, dictSize);
43750c16b537SWarner Losh }
43760c16b537SWarner Losh 
ZBUFFv07_decompressInit(ZBUFFv07_DCtx * zbd)43770c16b537SWarner Losh size_t ZBUFFv07_decompressInit(ZBUFFv07_DCtx* zbd)
43780c16b537SWarner Losh {
43790c16b537SWarner Losh     return ZBUFFv07_decompressInitDictionary(zbd, NULL, 0);
43800c16b537SWarner Losh }
43810c16b537SWarner Losh 
43820c16b537SWarner Losh 
43830c16b537SWarner Losh /* internal util function */
ZBUFFv07_limitCopy(void * dst,size_t dstCapacity,const void * src,size_t srcSize)43840c16b537SWarner Losh MEM_STATIC size_t ZBUFFv07_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
43850c16b537SWarner Losh {
43860c16b537SWarner Losh     size_t const length = MIN(dstCapacity, srcSize);
438737f1f268SConrad Meyer     if (length > 0) {
43880c16b537SWarner Losh         memcpy(dst, src, length);
438937f1f268SConrad Meyer     }
43900c16b537SWarner Losh     return length;
43910c16b537SWarner Losh }
43920c16b537SWarner Losh 
43930c16b537SWarner Losh 
43940c16b537SWarner Losh /* *** Decompression *** */
43950c16b537SWarner Losh 
ZBUFFv07_decompressContinue(ZBUFFv07_DCtx * zbd,void * dst,size_t * dstCapacityPtr,const void * src,size_t * srcSizePtr)43960c16b537SWarner Losh size_t ZBUFFv07_decompressContinue(ZBUFFv07_DCtx* zbd,
43970c16b537SWarner Losh                                 void* dst, size_t* dstCapacityPtr,
43980c16b537SWarner Losh                           const void* src, size_t* srcSizePtr)
43990c16b537SWarner Losh {
44000c16b537SWarner Losh     const char* const istart = (const char*)src;
44010c16b537SWarner Losh     const char* const iend = istart + *srcSizePtr;
44020c16b537SWarner Losh     const char* ip = istart;
44030c16b537SWarner Losh     char* const ostart = (char*)dst;
44040c16b537SWarner Losh     char* const oend = ostart + *dstCapacityPtr;
44050c16b537SWarner Losh     char* op = ostart;
44060c16b537SWarner Losh     U32 notDone = 1;
44070c16b537SWarner Losh 
44080c16b537SWarner Losh     while (notDone) {
44090c16b537SWarner Losh         switch(zbd->stage)
44100c16b537SWarner Losh         {
44110c16b537SWarner Losh         case ZBUFFds_init :
44120c16b537SWarner Losh             return ERROR(init_missing);
44130c16b537SWarner Losh 
44140c16b537SWarner Losh         case ZBUFFds_loadHeader :
44150c16b537SWarner Losh             {   size_t const hSize = ZSTDv07_getFrameParams(&(zbd->fParams), zbd->headerBuffer, zbd->lhSize);
44160c16b537SWarner Losh                 if (ZSTDv07_isError(hSize)) return hSize;
44170c16b537SWarner Losh                 if (hSize != 0) {
44180c16b537SWarner Losh                     size_t const toLoad = hSize - zbd->lhSize;   /* if hSize!=0, hSize > zbd->lhSize */
44190c16b537SWarner Losh                     if (toLoad > (size_t)(iend-ip)) {   /* not enough input to load full header */
44200c16b537SWarner Losh                         memcpy(zbd->headerBuffer + zbd->lhSize, ip, iend-ip);
44210c16b537SWarner Losh                         zbd->lhSize += iend-ip;
44220c16b537SWarner Losh                         *dstCapacityPtr = 0;
44230c16b537SWarner Losh                         return (hSize - zbd->lhSize) + ZSTDv07_blockHeaderSize;   /* remaining header bytes + next block header */
44240c16b537SWarner Losh                     }
44250c16b537SWarner Losh                     memcpy(zbd->headerBuffer + zbd->lhSize, ip, toLoad); zbd->lhSize = hSize; ip += toLoad;
44260c16b537SWarner Losh                     break;
44270c16b537SWarner Losh             }   }
44280c16b537SWarner Losh 
44290c16b537SWarner Losh             /* Consume header */
44300c16b537SWarner Losh             {   size_t const h1Size = ZSTDv07_nextSrcSizeToDecompress(zbd->zd);  /* == ZSTDv07_frameHeaderSize_min */
44310c16b537SWarner Losh                 size_t const h1Result = ZSTDv07_decompressContinue(zbd->zd, NULL, 0, zbd->headerBuffer, h1Size);
44320c16b537SWarner Losh                 if (ZSTDv07_isError(h1Result)) return h1Result;
44330c16b537SWarner Losh                 if (h1Size < zbd->lhSize) {   /* long header */
44340c16b537SWarner Losh                     size_t const h2Size = ZSTDv07_nextSrcSizeToDecompress(zbd->zd);
44350c16b537SWarner Losh                     size_t const h2Result = ZSTDv07_decompressContinue(zbd->zd, NULL, 0, zbd->headerBuffer+h1Size, h2Size);
44360c16b537SWarner Losh                     if (ZSTDv07_isError(h2Result)) return h2Result;
44370c16b537SWarner Losh             }   }
44380c16b537SWarner Losh 
44390c16b537SWarner Losh             zbd->fParams.windowSize = MAX(zbd->fParams.windowSize, 1U << ZSTDv07_WINDOWLOG_ABSOLUTEMIN);
44400c16b537SWarner Losh 
44410c16b537SWarner Losh             /* Frame header instruct buffer sizes */
44420c16b537SWarner Losh             {   size_t const blockSize = MIN(zbd->fParams.windowSize, ZSTDv07_BLOCKSIZE_ABSOLUTEMAX);
44430c16b537SWarner Losh                 zbd->blockSize = blockSize;
44440c16b537SWarner Losh                 if (zbd->inBuffSize < blockSize) {
44450c16b537SWarner Losh                     zbd->customMem.customFree(zbd->customMem.opaque, zbd->inBuff);
44460c16b537SWarner Losh                     zbd->inBuffSize = blockSize;
44470c16b537SWarner Losh                     zbd->inBuff = (char*)zbd->customMem.customAlloc(zbd->customMem.opaque, blockSize);
44480c16b537SWarner Losh                     if (zbd->inBuff == NULL) return ERROR(memory_allocation);
44490c16b537SWarner Losh                 }
44500c16b537SWarner Losh                 {   size_t const neededOutSize = zbd->fParams.windowSize + blockSize + WILDCOPY_OVERLENGTH * 2;
44510c16b537SWarner Losh                     if (zbd->outBuffSize < neededOutSize) {
44520c16b537SWarner Losh                         zbd->customMem.customFree(zbd->customMem.opaque, zbd->outBuff);
44530c16b537SWarner Losh                         zbd->outBuffSize = neededOutSize;
44540c16b537SWarner Losh                         zbd->outBuff = (char*)zbd->customMem.customAlloc(zbd->customMem.opaque, neededOutSize);
44550c16b537SWarner Losh                         if (zbd->outBuff == NULL) return ERROR(memory_allocation);
44560c16b537SWarner Losh             }   }   }
44570c16b537SWarner Losh             zbd->stage = ZBUFFds_read;
44580c16b537SWarner Losh             /* pass-through */
44590c16b537SWarner Losh 	    /* fall-through */
44600c16b537SWarner Losh         case ZBUFFds_read:
44610c16b537SWarner Losh             {   size_t const neededInSize = ZSTDv07_nextSrcSizeToDecompress(zbd->zd);
44620c16b537SWarner Losh                 if (neededInSize==0) {  /* end of frame */
44630c16b537SWarner Losh                     zbd->stage = ZBUFFds_init;
44640c16b537SWarner Losh                     notDone = 0;
44650c16b537SWarner Losh                     break;
44660c16b537SWarner Losh                 }
44670c16b537SWarner Losh                 if ((size_t)(iend-ip) >= neededInSize) {  /* decode directly from src */
44680c16b537SWarner Losh                     const int isSkipFrame = ZSTDv07_isSkipFrame(zbd->zd);
44690c16b537SWarner Losh                     size_t const decodedSize = ZSTDv07_decompressContinue(zbd->zd,
44700c16b537SWarner Losh                         zbd->outBuff + zbd->outStart, (isSkipFrame ? 0 : zbd->outBuffSize - zbd->outStart),
44710c16b537SWarner Losh                         ip, neededInSize);
44720c16b537SWarner Losh                     if (ZSTDv07_isError(decodedSize)) return decodedSize;
44730c16b537SWarner Losh                     ip += neededInSize;
44740c16b537SWarner Losh                     if (!decodedSize && !isSkipFrame) break;   /* this was just a header */
44750c16b537SWarner Losh                     zbd->outEnd = zbd->outStart +  decodedSize;
44760c16b537SWarner Losh                     zbd->stage = ZBUFFds_flush;
44770c16b537SWarner Losh                     break;
44780c16b537SWarner Losh                 }
44790c16b537SWarner Losh                 if (ip==iend) { notDone = 0; break; }   /* no more input */
44800c16b537SWarner Losh                 zbd->stage = ZBUFFds_load;
44810c16b537SWarner Losh             }
44820c16b537SWarner Losh 	    /* fall-through */
44830c16b537SWarner Losh         case ZBUFFds_load:
44840c16b537SWarner Losh             {   size_t const neededInSize = ZSTDv07_nextSrcSizeToDecompress(zbd->zd);
44850c16b537SWarner Losh                 size_t const toLoad = neededInSize - zbd->inPos;   /* should always be <= remaining space within inBuff */
44860c16b537SWarner Losh                 size_t loadedSize;
44870c16b537SWarner Losh                 if (toLoad > zbd->inBuffSize - zbd->inPos) return ERROR(corruption_detected);   /* should never happen */
44880c16b537SWarner Losh                 loadedSize = ZBUFFv07_limitCopy(zbd->inBuff + zbd->inPos, toLoad, ip, iend-ip);
44890c16b537SWarner Losh                 ip += loadedSize;
44900c16b537SWarner Losh                 zbd->inPos += loadedSize;
44910c16b537SWarner Losh                 if (loadedSize < toLoad) { notDone = 0; break; }   /* not enough input, wait for more */
44920c16b537SWarner Losh 
44930c16b537SWarner Losh                 /* decode loaded input */
44940c16b537SWarner Losh                 {  const int isSkipFrame = ZSTDv07_isSkipFrame(zbd->zd);
44950c16b537SWarner Losh                    size_t const decodedSize = ZSTDv07_decompressContinue(zbd->zd,
44960c16b537SWarner Losh                         zbd->outBuff + zbd->outStart, zbd->outBuffSize - zbd->outStart,
44970c16b537SWarner Losh                         zbd->inBuff, neededInSize);
44980c16b537SWarner Losh                     if (ZSTDv07_isError(decodedSize)) return decodedSize;
44990c16b537SWarner Losh                     zbd->inPos = 0;   /* input is consumed */
45000c16b537SWarner Losh                     if (!decodedSize && !isSkipFrame) { zbd->stage = ZBUFFds_read; break; }   /* this was just a header */
45010c16b537SWarner Losh                     zbd->outEnd = zbd->outStart +  decodedSize;
45020c16b537SWarner Losh                     zbd->stage = ZBUFFds_flush;
45030c16b537SWarner Losh                     /* break; */
45040c16b537SWarner Losh                     /* pass-through */
45050c16b537SWarner Losh                 }
45060c16b537SWarner Losh 	    }
45070c16b537SWarner Losh 	    /* fall-through */
45080c16b537SWarner Losh         case ZBUFFds_flush:
45090c16b537SWarner Losh             {   size_t const toFlushSize = zbd->outEnd - zbd->outStart;
45100c16b537SWarner Losh                 size_t const flushedSize = ZBUFFv07_limitCopy(op, oend-op, zbd->outBuff + zbd->outStart, toFlushSize);
45110c16b537SWarner Losh                 op += flushedSize;
45120c16b537SWarner Losh                 zbd->outStart += flushedSize;
45130c16b537SWarner Losh                 if (flushedSize == toFlushSize) {
45140c16b537SWarner Losh                     zbd->stage = ZBUFFds_read;
45150c16b537SWarner Losh                     if (zbd->outStart + zbd->blockSize > zbd->outBuffSize)
45160c16b537SWarner Losh                         zbd->outStart = zbd->outEnd = 0;
45170c16b537SWarner Losh                     break;
45180c16b537SWarner Losh                 }
45190c16b537SWarner Losh                 /* cannot flush everything */
45200c16b537SWarner Losh                 notDone = 0;
45210c16b537SWarner Losh                 break;
45220c16b537SWarner Losh             }
45230c16b537SWarner Losh         default: return ERROR(GENERIC);   /* impossible */
45240c16b537SWarner Losh     }   }
45250c16b537SWarner Losh 
45260c16b537SWarner Losh     /* result */
45270c16b537SWarner Losh     *srcSizePtr = ip-istart;
45280c16b537SWarner Losh     *dstCapacityPtr = op-ostart;
45290c16b537SWarner Losh     {   size_t nextSrcSizeHint = ZSTDv07_nextSrcSizeToDecompress(zbd->zd);
45300c16b537SWarner Losh         nextSrcSizeHint -= zbd->inPos;   /* already loaded*/
45310c16b537SWarner Losh         return nextSrcSizeHint;
45320c16b537SWarner Losh     }
45330c16b537SWarner Losh }
45340c16b537SWarner Losh 
45350c16b537SWarner Losh 
45360c16b537SWarner Losh 
45370c16b537SWarner Losh /* *************************************
45380c16b537SWarner Losh *  Tool functions
45390c16b537SWarner Losh ***************************************/
ZBUFFv07_recommendedDInSize(void)45400c16b537SWarner Losh size_t ZBUFFv07_recommendedDInSize(void)  { return ZSTDv07_BLOCKSIZE_ABSOLUTEMAX + ZSTDv07_blockHeaderSize /* block header size*/ ; }
ZBUFFv07_recommendedDOutSize(void)45410c16b537SWarner Losh size_t ZBUFFv07_recommendedDOutSize(void) { return ZSTDv07_BLOCKSIZE_ABSOLUTEMAX; }
4542