xref: /freebsd/sys/contrib/zstd/lib/legacy/zstd_v05.c (revision 0f743729abbfc5c9d78a713f72241a4d4bd601ec)
10c16b537SWarner Losh /*
20c16b537SWarner Losh  * Copyright (c) 2016-present, 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 "zstd_v05.h"
140c16b537SWarner Losh #include "error_private.h"
150c16b537SWarner Losh 
160c16b537SWarner Losh 
170c16b537SWarner Losh /* ******************************************************************
180c16b537SWarner Losh    mem.h
190c16b537SWarner Losh    low-level memory access routines
200c16b537SWarner Losh    Copyright (C) 2013-2015, Yann Collet.
210c16b537SWarner Losh 
220c16b537SWarner Losh    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
230c16b537SWarner Losh 
240c16b537SWarner Losh    Redistribution and use in source and binary forms, with or without
250c16b537SWarner Losh    modification, are permitted provided that the following conditions are
260c16b537SWarner Losh    met:
270c16b537SWarner Losh 
280c16b537SWarner Losh        * Redistributions of source code must retain the above copyright
290c16b537SWarner Losh    notice, this list of conditions and the following disclaimer.
300c16b537SWarner Losh        * Redistributions in binary form must reproduce the above
310c16b537SWarner Losh    copyright notice, this list of conditions and the following disclaimer
320c16b537SWarner Losh    in the documentation and/or other materials provided with the
330c16b537SWarner Losh    distribution.
340c16b537SWarner Losh 
350c16b537SWarner Losh    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
360c16b537SWarner Losh    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
370c16b537SWarner Losh    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
380c16b537SWarner Losh    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
390c16b537SWarner Losh    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
400c16b537SWarner Losh    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
410c16b537SWarner Losh    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
420c16b537SWarner Losh    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
430c16b537SWarner Losh    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
440c16b537SWarner Losh    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
450c16b537SWarner Losh    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
460c16b537SWarner Losh 
470c16b537SWarner Losh     You can contact the author at :
480c16b537SWarner Losh     - FSEv05 source repository : https://github.com/Cyan4973/FiniteStateEntropy
490c16b537SWarner Losh     - Public forum : https://groups.google.com/forum/#!forum/lz4c
500c16b537SWarner Losh ****************************************************************** */
510c16b537SWarner Losh #ifndef MEM_H_MODULE
520c16b537SWarner Losh #define MEM_H_MODULE
530c16b537SWarner Losh 
540c16b537SWarner Losh #if defined (__cplusplus)
550c16b537SWarner Losh extern "C" {
560c16b537SWarner Losh #endif
570c16b537SWarner Losh 
580c16b537SWarner Losh /*-****************************************
590c16b537SWarner Losh *  Dependencies
600c16b537SWarner Losh ******************************************/
610c16b537SWarner Losh #include <stddef.h>    /* size_t, ptrdiff_t */
620c16b537SWarner Losh #include <string.h>    /* memcpy */
630c16b537SWarner Losh 
640c16b537SWarner Losh 
650c16b537SWarner Losh /*-****************************************
660c16b537SWarner Losh *  Compiler specifics
670c16b537SWarner Losh ******************************************/
680c16b537SWarner Losh #if defined(__GNUC__)
690c16b537SWarner Losh #  define MEM_STATIC static __attribute__((unused))
700c16b537SWarner Losh #elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
710c16b537SWarner Losh #  define MEM_STATIC static inline
720c16b537SWarner Losh #elif defined(_MSC_VER)
730c16b537SWarner Losh #  define MEM_STATIC static __inline
740c16b537SWarner Losh #else
750c16b537SWarner Losh #  define MEM_STATIC static  /* this version may generate warnings for unused static functions; disable the relevant warning */
760c16b537SWarner Losh #endif
770c16b537SWarner Losh 
780c16b537SWarner Losh 
790c16b537SWarner Losh /*-**************************************************************
800c16b537SWarner Losh *  Basic Types
810c16b537SWarner Losh *****************************************************************/
820c16b537SWarner Losh #if defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
830c16b537SWarner Losh # include <stdint.h>
840c16b537SWarner Losh   typedef  uint8_t BYTE;
850c16b537SWarner Losh   typedef uint16_t U16;
860c16b537SWarner Losh   typedef  int16_t S16;
870c16b537SWarner Losh   typedef uint32_t U32;
880c16b537SWarner Losh   typedef  int32_t S32;
890c16b537SWarner Losh   typedef uint64_t U64;
900c16b537SWarner Losh   typedef  int64_t S64;
910c16b537SWarner Losh #else
920c16b537SWarner Losh   typedef unsigned char       BYTE;
930c16b537SWarner Losh   typedef unsigned short      U16;
940c16b537SWarner Losh   typedef   signed short      S16;
950c16b537SWarner Losh   typedef unsigned int        U32;
960c16b537SWarner Losh   typedef   signed int        S32;
970c16b537SWarner Losh   typedef unsigned long long  U64;
980c16b537SWarner Losh   typedef   signed long long  S64;
990c16b537SWarner Losh #endif
1000c16b537SWarner Losh 
1010c16b537SWarner Losh 
1020c16b537SWarner Losh /*-**************************************************************
1030c16b537SWarner Losh *  Memory I/O
1040c16b537SWarner Losh *****************************************************************/
1050c16b537SWarner Losh /* MEM_FORCE_MEMORY_ACCESS :
1060c16b537SWarner Losh  * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.
1070c16b537SWarner Losh  * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.
1080c16b537SWarner Losh  * The below switch allow to select different access method for improved performance.
1090c16b537SWarner Losh  * Method 0 (default) : use `memcpy()`. Safe and portable.
1100c16b537SWarner Losh  * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable).
1110c16b537SWarner Losh  *            This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.
1120c16b537SWarner Losh  * Method 2 : direct access. This method is portable but violate C standard.
1130c16b537SWarner Losh  *            It can generate buggy code on targets depending on alignment.
1140c16b537SWarner Losh  *            In some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)
1150c16b537SWarner Losh  * See http://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details.
1160c16b537SWarner Losh  * Prefer these methods in priority order (0 > 1 > 2)
1170c16b537SWarner Losh  */
1180c16b537SWarner Losh #ifndef MEM_FORCE_MEMORY_ACCESS   /* can be defined externally, on command line for example */
1190c16b537SWarner Losh #  if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) )
1200c16b537SWarner Losh #    define MEM_FORCE_MEMORY_ACCESS 2
1210c16b537SWarner Losh #  elif (defined(__INTEL_COMPILER) && !defined(WIN32)) || \
1220c16b537SWarner Losh   (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) ))
1230c16b537SWarner Losh #    define MEM_FORCE_MEMORY_ACCESS 1
1240c16b537SWarner Losh #  endif
1250c16b537SWarner Losh #endif
1260c16b537SWarner Losh 
1270c16b537SWarner Losh MEM_STATIC unsigned MEM_32bits(void) { return sizeof(void*)==4; }
1280c16b537SWarner Losh MEM_STATIC unsigned MEM_64bits(void) { return sizeof(void*)==8; }
1290c16b537SWarner Losh 
1300c16b537SWarner Losh MEM_STATIC unsigned MEM_isLittleEndian(void)
1310c16b537SWarner Losh {
1320c16b537SWarner Losh     const union { U32 u; BYTE c[4]; } one = { 1 };   /* don't use static : performance detrimental  */
1330c16b537SWarner Losh     return one.c[0];
1340c16b537SWarner Losh }
1350c16b537SWarner Losh 
1360c16b537SWarner Losh #if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2)
1370c16b537SWarner Losh 
1380c16b537SWarner Losh /* violates C standard, by lying on structure alignment.
1390c16b537SWarner Losh Only use if no other choice to achieve best performance on target platform */
1400c16b537SWarner Losh MEM_STATIC U16 MEM_read16(const void* memPtr) { return *(const U16*) memPtr; }
1410c16b537SWarner Losh MEM_STATIC U32 MEM_read32(const void* memPtr) { return *(const U32*) memPtr; }
1420c16b537SWarner Losh MEM_STATIC U64 MEM_read64(const void* memPtr) { return *(const U64*) memPtr; }
1430c16b537SWarner Losh 
1440c16b537SWarner Losh MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; }
1450c16b537SWarner Losh MEM_STATIC void MEM_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; }
1460c16b537SWarner Losh MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(U64*)memPtr = value; }
1470c16b537SWarner Losh 
1480c16b537SWarner Losh #elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1)
1490c16b537SWarner Losh 
1500c16b537SWarner Losh /* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
1510c16b537SWarner Losh /* currently only defined for gcc and icc */
1520c16b537SWarner Losh typedef union { U16 u16; U32 u32; U64 u64; size_t st; } __attribute__((packed)) unalign;
1530c16b537SWarner Losh 
1540c16b537SWarner Losh MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign*)ptr)->u16; }
1550c16b537SWarner Losh MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign*)ptr)->u32; }
1560c16b537SWarner Losh MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign*)ptr)->u64; }
1570c16b537SWarner Losh 
1580c16b537SWarner Losh MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; }
1590c16b537SWarner Losh MEM_STATIC void MEM_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = value; }
1600c16b537SWarner Losh MEM_STATIC void MEM_write64(void* memPtr, U64 value) { ((unalign*)memPtr)->u64 = value; }
1610c16b537SWarner Losh 
1620c16b537SWarner Losh #else
1630c16b537SWarner Losh 
1640c16b537SWarner Losh /* default method, safe and standard.
1650c16b537SWarner Losh    can sometimes prove slower */
1660c16b537SWarner Losh 
1670c16b537SWarner Losh MEM_STATIC U16 MEM_read16(const void* memPtr)
1680c16b537SWarner Losh {
1690c16b537SWarner Losh     U16 val; memcpy(&val, memPtr, sizeof(val)); return val;
1700c16b537SWarner Losh }
1710c16b537SWarner Losh 
1720c16b537SWarner Losh MEM_STATIC U32 MEM_read32(const void* memPtr)
1730c16b537SWarner Losh {
1740c16b537SWarner Losh     U32 val; memcpy(&val, memPtr, sizeof(val)); return val;
1750c16b537SWarner Losh }
1760c16b537SWarner Losh 
1770c16b537SWarner Losh MEM_STATIC U64 MEM_read64(const void* memPtr)
1780c16b537SWarner Losh {
1790c16b537SWarner Losh     U64 val; memcpy(&val, memPtr, sizeof(val)); return val;
1800c16b537SWarner Losh }
1810c16b537SWarner Losh 
1820c16b537SWarner Losh MEM_STATIC void MEM_write16(void* memPtr, U16 value)
1830c16b537SWarner Losh {
1840c16b537SWarner Losh     memcpy(memPtr, &value, sizeof(value));
1850c16b537SWarner Losh }
1860c16b537SWarner Losh 
1870c16b537SWarner Losh MEM_STATIC void MEM_write32(void* memPtr, U32 value)
1880c16b537SWarner Losh {
1890c16b537SWarner Losh     memcpy(memPtr, &value, sizeof(value));
1900c16b537SWarner Losh }
1910c16b537SWarner Losh 
1920c16b537SWarner Losh MEM_STATIC void MEM_write64(void* memPtr, U64 value)
1930c16b537SWarner Losh {
1940c16b537SWarner Losh     memcpy(memPtr, &value, sizeof(value));
1950c16b537SWarner Losh }
1960c16b537SWarner Losh 
1970c16b537SWarner Losh #endif /* MEM_FORCE_MEMORY_ACCESS */
1980c16b537SWarner Losh 
1990c16b537SWarner Losh 
2000c16b537SWarner Losh MEM_STATIC U16 MEM_readLE16(const void* memPtr)
2010c16b537SWarner Losh {
2020c16b537SWarner Losh     if (MEM_isLittleEndian())
2030c16b537SWarner Losh         return MEM_read16(memPtr);
2040c16b537SWarner Losh     else {
2050c16b537SWarner Losh         const BYTE* p = (const BYTE*)memPtr;
2060c16b537SWarner Losh         return (U16)(p[0] + (p[1]<<8));
2070c16b537SWarner Losh     }
2080c16b537SWarner Losh }
2090c16b537SWarner Losh 
2100c16b537SWarner Losh MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val)
2110c16b537SWarner Losh {
2120c16b537SWarner Losh     if (MEM_isLittleEndian()) {
2130c16b537SWarner Losh         MEM_write16(memPtr, val);
2140c16b537SWarner Losh     } else {
2150c16b537SWarner Losh         BYTE* p = (BYTE*)memPtr;
2160c16b537SWarner Losh         p[0] = (BYTE)val;
2170c16b537SWarner Losh         p[1] = (BYTE)(val>>8);
2180c16b537SWarner Losh     }
2190c16b537SWarner Losh }
2200c16b537SWarner Losh 
2210c16b537SWarner Losh MEM_STATIC U32 MEM_readLE32(const void* memPtr)
2220c16b537SWarner Losh {
2230c16b537SWarner Losh     if (MEM_isLittleEndian())
2240c16b537SWarner Losh         return MEM_read32(memPtr);
2250c16b537SWarner Losh     else {
2260c16b537SWarner Losh         const BYTE* p = (const BYTE*)memPtr;
2270c16b537SWarner Losh         return (U32)((U32)p[0] + ((U32)p[1]<<8) + ((U32)p[2]<<16) + ((U32)p[3]<<24));
2280c16b537SWarner Losh     }
2290c16b537SWarner Losh }
2300c16b537SWarner Losh 
2310c16b537SWarner Losh 
2320c16b537SWarner Losh MEM_STATIC U64 MEM_readLE64(const void* memPtr)
2330c16b537SWarner Losh {
2340c16b537SWarner Losh     if (MEM_isLittleEndian())
2350c16b537SWarner Losh         return MEM_read64(memPtr);
2360c16b537SWarner Losh     else {
2370c16b537SWarner Losh         const BYTE* p = (const BYTE*)memPtr;
2380c16b537SWarner Losh         return (U64)((U64)p[0] + ((U64)p[1]<<8) + ((U64)p[2]<<16) + ((U64)p[3]<<24)
2390c16b537SWarner Losh                      + ((U64)p[4]<<32) + ((U64)p[5]<<40) + ((U64)p[6]<<48) + ((U64)p[7]<<56));
2400c16b537SWarner Losh     }
2410c16b537SWarner Losh }
2420c16b537SWarner Losh 
2430c16b537SWarner Losh 
2440c16b537SWarner Losh MEM_STATIC size_t MEM_readLEST(const void* memPtr)
2450c16b537SWarner Losh {
2460c16b537SWarner Losh     if (MEM_32bits())
2470c16b537SWarner Losh         return (size_t)MEM_readLE32(memPtr);
2480c16b537SWarner Losh     else
2490c16b537SWarner Losh         return (size_t)MEM_readLE64(memPtr);
2500c16b537SWarner Losh }
2510c16b537SWarner Losh 
2520c16b537SWarner Losh 
2530c16b537SWarner Losh #if defined (__cplusplus)
2540c16b537SWarner Losh }
2550c16b537SWarner Losh #endif
2560c16b537SWarner Losh 
2570c16b537SWarner Losh #endif /* MEM_H_MODULE */
2580c16b537SWarner Losh 
2590c16b537SWarner Losh /*
2600c16b537SWarner Losh     zstd - standard compression library
2610c16b537SWarner Losh     Header File for static linking only
2620c16b537SWarner Losh     Copyright (C) 2014-2016, Yann Collet.
2630c16b537SWarner Losh 
2640c16b537SWarner Losh     BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
2650c16b537SWarner Losh 
2660c16b537SWarner Losh     Redistribution and use in source and binary forms, with or without
2670c16b537SWarner Losh     modification, are permitted provided that the following conditions are
2680c16b537SWarner Losh     met:
2690c16b537SWarner Losh     * Redistributions of source code must retain the above copyright
2700c16b537SWarner Losh     notice, this list of conditions and the following disclaimer.
2710c16b537SWarner Losh     * Redistributions in binary form must reproduce the above
2720c16b537SWarner Losh     copyright notice, this list of conditions and the following disclaimer
2730c16b537SWarner Losh     in the documentation and/or other materials provided with the
2740c16b537SWarner Losh     distribution.
2750c16b537SWarner Losh     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2760c16b537SWarner Losh     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2770c16b537SWarner Losh     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2780c16b537SWarner Losh     A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2790c16b537SWarner Losh     OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2800c16b537SWarner Losh     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2810c16b537SWarner Losh     LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2820c16b537SWarner Losh     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2830c16b537SWarner Losh     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2840c16b537SWarner Losh     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2850c16b537SWarner Losh     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2860c16b537SWarner Losh 
2870c16b537SWarner Losh     You can contact the author at :
2880c16b537SWarner Losh     - zstd homepage : http://www.zstd.net
2890c16b537SWarner Losh */
2900c16b537SWarner Losh #ifndef ZSTD_STATIC_H
2910c16b537SWarner Losh #define ZSTD_STATIC_H
2920c16b537SWarner Losh 
2930c16b537SWarner Losh /* The prototypes defined within this file are considered experimental.
2940c16b537SWarner Losh  * They should not be used in the context DLL as they may change in the future.
2950c16b537SWarner Losh  * Prefer static linking if you need them, to control breaking version changes issues.
2960c16b537SWarner Losh  */
2970c16b537SWarner Losh 
2980c16b537SWarner Losh #if defined (__cplusplus)
2990c16b537SWarner Losh extern "C" {
3000c16b537SWarner Losh #endif
3010c16b537SWarner Losh 
3020c16b537SWarner Losh 
3030c16b537SWarner Losh 
3040c16b537SWarner Losh /*-*************************************
3050c16b537SWarner Losh *  Types
3060c16b537SWarner Losh ***************************************/
3070c16b537SWarner Losh #define ZSTDv05_WINDOWLOG_ABSOLUTEMIN 11
3080c16b537SWarner Losh 
3090c16b537SWarner Losh 
3100c16b537SWarner Losh /*-*************************************
3110c16b537SWarner Losh *  Advanced functions
3120c16b537SWarner Losh ***************************************/
3130c16b537SWarner Losh /*- Advanced Decompression functions -*/
3140c16b537SWarner Losh 
3150c16b537SWarner Losh /*! ZSTDv05_decompress_usingPreparedDCtx() :
3160c16b537SWarner Losh *   Same as ZSTDv05_decompress_usingDict, but using a reference context `preparedDCtx`, where dictionary has been loaded.
3170c16b537SWarner Losh *   It avoids reloading the dictionary each time.
3180c16b537SWarner Losh *   `preparedDCtx` must have been properly initialized using ZSTDv05_decompressBegin_usingDict().
3190c16b537SWarner Losh *   Requires 2 contexts : 1 for reference, which will not be modified, and 1 to run the decompression operation */
3200c16b537SWarner Losh size_t ZSTDv05_decompress_usingPreparedDCtx(
3210c16b537SWarner Losh                                              ZSTDv05_DCtx* dctx, const ZSTDv05_DCtx* preparedDCtx,
3220c16b537SWarner Losh                                              void* dst, size_t dstCapacity,
3230c16b537SWarner Losh                                        const void* src, size_t srcSize);
3240c16b537SWarner Losh 
3250c16b537SWarner Losh 
3260c16b537SWarner Losh /* **************************************
3270c16b537SWarner Losh *  Streaming functions (direct mode)
3280c16b537SWarner Losh ****************************************/
3290c16b537SWarner Losh size_t ZSTDv05_decompressBegin(ZSTDv05_DCtx* dctx);
3300c16b537SWarner Losh 
3310c16b537SWarner Losh /*
3320c16b537SWarner Losh   Streaming decompression, direct mode (bufferless)
3330c16b537SWarner Losh 
3340c16b537SWarner Losh   A ZSTDv05_DCtx object is required to track streaming operations.
3350c16b537SWarner Losh   Use ZSTDv05_createDCtx() / ZSTDv05_freeDCtx() to manage it.
3360c16b537SWarner Losh   A ZSTDv05_DCtx object can be re-used multiple times.
3370c16b537SWarner Losh 
3380c16b537SWarner Losh   First typical operation is to retrieve frame parameters, using ZSTDv05_getFrameParams().
3390c16b537SWarner Losh   This operation is independent, and just needs enough input data to properly decode the frame header.
3400c16b537SWarner Losh   Objective is to retrieve *params.windowlog, to know minimum amount of memory required during decoding.
3410c16b537SWarner Losh   Result : 0 when successful, it means the ZSTDv05_parameters structure has been filled.
3420c16b537SWarner Losh            >0 : means there is not enough data into src. Provides the expected size to successfully decode header.
3430c16b537SWarner Losh            errorCode, which can be tested using ZSTDv05_isError()
3440c16b537SWarner Losh 
3450c16b537SWarner Losh   Start decompression, with ZSTDv05_decompressBegin() or ZSTDv05_decompressBegin_usingDict()
3460c16b537SWarner Losh   Alternatively, you can copy a prepared context, using ZSTDv05_copyDCtx()
3470c16b537SWarner Losh 
3480c16b537SWarner Losh   Then use ZSTDv05_nextSrcSizeToDecompress() and ZSTDv05_decompressContinue() alternatively.
3490c16b537SWarner Losh   ZSTDv05_nextSrcSizeToDecompress() tells how much bytes to provide as 'srcSize' to ZSTDv05_decompressContinue().
3500c16b537SWarner Losh   ZSTDv05_decompressContinue() requires this exact amount of bytes, or it will fail.
3510c16b537SWarner Losh   ZSTDv05_decompressContinue() needs previous data blocks during decompression, up to (1 << windowlog).
3520c16b537SWarner Losh   They should preferably be located contiguously, prior to current block. Alternatively, a round buffer is also possible.
3530c16b537SWarner Losh 
3540c16b537SWarner Losh   @result of ZSTDv05_decompressContinue() is the number of bytes regenerated within 'dst'.
3550c16b537SWarner Losh   It can be zero, which is not an error; it just means ZSTDv05_decompressContinue() has decoded some header.
3560c16b537SWarner Losh 
3570c16b537SWarner Losh   A frame is fully decoded when ZSTDv05_nextSrcSizeToDecompress() returns zero.
3580c16b537SWarner Losh   Context can then be reset to start a new decompression.
3590c16b537SWarner Losh */
3600c16b537SWarner Losh 
3610c16b537SWarner Losh 
3620c16b537SWarner Losh /* **************************************
3630c16b537SWarner Losh *  Block functions
3640c16b537SWarner Losh ****************************************/
3650c16b537SWarner Losh /*! Block functions produce and decode raw zstd blocks, without frame metadata.
3660c16b537SWarner Losh     User will have to take in charge required information to regenerate data, such as block sizes.
3670c16b537SWarner Losh 
3680c16b537SWarner Losh     A few rules to respect :
3690c16b537SWarner Losh     - Uncompressed block size must be <= 128 KB
3700c16b537SWarner Losh     - Compressing or decompressing requires a context structure
3710c16b537SWarner Losh       + Use ZSTDv05_createCCtx() and ZSTDv05_createDCtx()
3720c16b537SWarner Losh     - It is necessary to init context before starting
3730c16b537SWarner Losh       + compression : ZSTDv05_compressBegin()
3740c16b537SWarner Losh       + decompression : ZSTDv05_decompressBegin()
3750c16b537SWarner Losh       + variants _usingDict() are also allowed
3760c16b537SWarner Losh       + copyCCtx() and copyDCtx() work too
3770c16b537SWarner Losh     - When a block is considered not compressible enough, ZSTDv05_compressBlock() result will be zero.
3780c16b537SWarner Losh       In which case, nothing is produced into `dst`.
3790c16b537SWarner Losh       + User must test for such outcome and deal directly with uncompressed data
3800c16b537SWarner Losh       + ZSTDv05_decompressBlock() doesn't accept uncompressed data as input !!
3810c16b537SWarner Losh */
3820c16b537SWarner Losh 
3830c16b537SWarner Losh size_t ZSTDv05_decompressBlock(ZSTDv05_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
3840c16b537SWarner Losh 
3850c16b537SWarner Losh 
3860c16b537SWarner Losh 
3870c16b537SWarner Losh 
3880c16b537SWarner Losh #if defined (__cplusplus)
3890c16b537SWarner Losh }
3900c16b537SWarner Losh #endif
3910c16b537SWarner Losh 
3920c16b537SWarner Losh #endif  /* ZSTDv05_STATIC_H */
3930c16b537SWarner Losh 
3940c16b537SWarner Losh 
3950c16b537SWarner Losh /*
3960c16b537SWarner Losh     zstd_internal - common functions to include
3970c16b537SWarner Losh     Header File for include
3980c16b537SWarner Losh     Copyright (C) 2014-2016, Yann Collet.
3990c16b537SWarner Losh 
4000c16b537SWarner Losh     BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
4010c16b537SWarner Losh 
4020c16b537SWarner Losh     Redistribution and use in source and binary forms, with or without
4030c16b537SWarner Losh     modification, are permitted provided that the following conditions are
4040c16b537SWarner Losh     met:
4050c16b537SWarner Losh     * Redistributions of source code must retain the above copyright
4060c16b537SWarner Losh     notice, this list of conditions and the following disclaimer.
4070c16b537SWarner Losh     * Redistributions in binary form must reproduce the above
4080c16b537SWarner Losh     copyright notice, this list of conditions and the following disclaimer
4090c16b537SWarner Losh     in the documentation and/or other materials provided with the
4100c16b537SWarner Losh     distribution.
4110c16b537SWarner Losh     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4120c16b537SWarner Losh     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
4130c16b537SWarner Losh     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
4140c16b537SWarner Losh     A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
4150c16b537SWarner Losh     OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4160c16b537SWarner Losh     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4170c16b537SWarner Losh     LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
4180c16b537SWarner Losh     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
4190c16b537SWarner Losh     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4200c16b537SWarner Losh     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
4210c16b537SWarner Losh     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4220c16b537SWarner Losh 
4230c16b537SWarner Losh     You can contact the author at :
4240c16b537SWarner Losh     - zstd source repository : https://github.com/Cyan4973/zstd
4250c16b537SWarner Losh */
4260c16b537SWarner Losh #ifndef ZSTD_CCOMMON_H_MODULE
4270c16b537SWarner Losh #define ZSTD_CCOMMON_H_MODULE
4280c16b537SWarner Losh 
4290c16b537SWarner Losh 
4300c16b537SWarner Losh 
4310c16b537SWarner Losh /*-*************************************
4320c16b537SWarner Losh *  Common macros
4330c16b537SWarner Losh ***************************************/
4340c16b537SWarner Losh #define MIN(a,b) ((a)<(b) ? (a) : (b))
4350c16b537SWarner Losh #define MAX(a,b) ((a)>(b) ? (a) : (b))
4360c16b537SWarner Losh 
4370c16b537SWarner Losh 
4380c16b537SWarner Losh /*-*************************************
4390c16b537SWarner Losh *  Common constants
4400c16b537SWarner Losh ***************************************/
4410c16b537SWarner Losh #define ZSTDv05_DICT_MAGIC  0xEC30A435
4420c16b537SWarner Losh 
4430c16b537SWarner Losh #define KB *(1 <<10)
4440c16b537SWarner Losh #define MB *(1 <<20)
4450c16b537SWarner Losh #define GB *(1U<<30)
4460c16b537SWarner Losh 
4470c16b537SWarner Losh #define BLOCKSIZE (128 KB)                 /* define, for static allocation */
4480c16b537SWarner Losh 
4490c16b537SWarner Losh static const size_t ZSTDv05_blockHeaderSize = 3;
4500c16b537SWarner Losh static const size_t ZSTDv05_frameHeaderSize_min = 5;
4510c16b537SWarner Losh #define ZSTDv05_frameHeaderSize_max 5         /* define, for static allocation */
4520c16b537SWarner Losh 
4530c16b537SWarner Losh #define BITv057 128
4540c16b537SWarner Losh #define BITv056  64
4550c16b537SWarner Losh #define BITv055  32
4560c16b537SWarner Losh #define BITv054  16
4570c16b537SWarner Losh #define BITv051   2
4580c16b537SWarner Losh #define BITv050   1
4590c16b537SWarner Losh 
4600c16b537SWarner Losh #define IS_HUFv05 0
4610c16b537SWarner Losh #define IS_PCH 1
4620c16b537SWarner Losh #define IS_RAW 2
4630c16b537SWarner Losh #define IS_RLE 3
4640c16b537SWarner Losh 
4650c16b537SWarner Losh #define MINMATCH 4
4660c16b537SWarner Losh #define REPCODE_STARTVALUE 1
4670c16b537SWarner Losh 
4680c16b537SWarner Losh #define Litbits  8
4690c16b537SWarner Losh #define MLbits   7
4700c16b537SWarner Losh #define LLbits   6
4710c16b537SWarner Losh #define Offbits  5
4720c16b537SWarner Losh #define MaxLit ((1<<Litbits) - 1)
4730c16b537SWarner Losh #define MaxML  ((1<<MLbits) - 1)
4740c16b537SWarner Losh #define MaxLL  ((1<<LLbits) - 1)
4750c16b537SWarner Losh #define MaxOff ((1<<Offbits)- 1)
4760c16b537SWarner Losh #define MLFSEv05Log   10
4770c16b537SWarner Losh #define LLFSEv05Log   10
4780c16b537SWarner Losh #define OffFSEv05Log   9
4790c16b537SWarner Losh #define MaxSeq MAX(MaxLL, MaxML)
4800c16b537SWarner Losh 
4810c16b537SWarner Losh #define FSEv05_ENCODING_RAW     0
4820c16b537SWarner Losh #define FSEv05_ENCODING_RLE     1
4830c16b537SWarner Losh #define FSEv05_ENCODING_STATIC  2
4840c16b537SWarner Losh #define FSEv05_ENCODING_DYNAMIC 3
4850c16b537SWarner Losh 
4860c16b537SWarner Losh 
4870c16b537SWarner Losh #define HufLog 12
4880c16b537SWarner Losh 
4890c16b537SWarner Losh #define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */
4900c16b537SWarner Losh #define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */)   /* for a non-null block */
4910c16b537SWarner Losh 
4920c16b537SWarner Losh #define WILDCOPY_OVERLENGTH 8
4930c16b537SWarner Losh 
4940c16b537SWarner Losh typedef enum { bt_compressed, bt_raw, bt_rle, bt_end } blockType_t;
4950c16b537SWarner Losh 
4960c16b537SWarner Losh 
4970c16b537SWarner Losh /*-*******************************************
4980c16b537SWarner Losh *  Shared functions to include for inlining
4990c16b537SWarner Losh *********************************************/
5000c16b537SWarner Losh static void ZSTDv05_copy8(void* dst, const void* src) { memcpy(dst, src, 8); }
5010c16b537SWarner Losh 
5020c16b537SWarner Losh #define COPY8(d,s) { ZSTDv05_copy8(d,s); d+=8; s+=8; }
5030c16b537SWarner Losh 
5040c16b537SWarner Losh /*! ZSTDv05_wildcopy() :
5050c16b537SWarner Losh *   custom version of memcpy(), can copy up to 7 bytes too many (8 bytes if length==0) */
5060c16b537SWarner Losh MEM_STATIC void ZSTDv05_wildcopy(void* dst, const void* src, ptrdiff_t length)
5070c16b537SWarner Losh {
5080c16b537SWarner Losh     const BYTE* ip = (const BYTE*)src;
5090c16b537SWarner Losh     BYTE* op = (BYTE*)dst;
5100c16b537SWarner Losh     BYTE* const oend = op + length;
5110c16b537SWarner Losh     do
5120c16b537SWarner Losh         COPY8(op, ip)
5130c16b537SWarner Losh     while (op < oend);
5140c16b537SWarner Losh }
5150c16b537SWarner Losh 
5160c16b537SWarner Losh 
5170c16b537SWarner Losh /*-*******************************************
5180c16b537SWarner Losh *  Private interfaces
5190c16b537SWarner Losh *********************************************/
5200c16b537SWarner Losh typedef struct {
5210c16b537SWarner Losh     void* buffer;
5220c16b537SWarner Losh     U32*  offsetStart;
5230c16b537SWarner Losh     U32*  offset;
5240c16b537SWarner Losh     BYTE* offCodeStart;
5250c16b537SWarner Losh     BYTE* offCode;
5260c16b537SWarner Losh     BYTE* litStart;
5270c16b537SWarner Losh     BYTE* lit;
5280c16b537SWarner Losh     BYTE* litLengthStart;
5290c16b537SWarner Losh     BYTE* litLength;
5300c16b537SWarner Losh     BYTE* matchLengthStart;
5310c16b537SWarner Losh     BYTE* matchLength;
5320c16b537SWarner Losh     BYTE* dumpsStart;
5330c16b537SWarner Losh     BYTE* dumps;
5340c16b537SWarner Losh     /* opt */
5350c16b537SWarner Losh     U32* matchLengthFreq;
5360c16b537SWarner Losh     U32* litLengthFreq;
5370c16b537SWarner Losh     U32* litFreq;
5380c16b537SWarner Losh     U32* offCodeFreq;
5390c16b537SWarner Losh     U32  matchLengthSum;
5400c16b537SWarner Losh     U32  litLengthSum;
5410c16b537SWarner Losh     U32  litSum;
5420c16b537SWarner Losh     U32  offCodeSum;
5430c16b537SWarner Losh } seqStore_t;
5440c16b537SWarner Losh 
5450c16b537SWarner Losh 
5460c16b537SWarner Losh 
5470c16b537SWarner Losh #endif   /* ZSTDv05_CCOMMON_H_MODULE */
5480c16b537SWarner Losh /* ******************************************************************
5490c16b537SWarner Losh    FSEv05 : Finite State Entropy coder
5500c16b537SWarner Losh    header file
5510c16b537SWarner Losh    Copyright (C) 2013-2015, Yann Collet.
5520c16b537SWarner Losh 
5530c16b537SWarner Losh    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
5540c16b537SWarner Losh 
5550c16b537SWarner Losh    Redistribution and use in source and binary forms, with or without
5560c16b537SWarner Losh    modification, are permitted provided that the following conditions are
5570c16b537SWarner Losh    met:
5580c16b537SWarner Losh 
5590c16b537SWarner Losh        * Redistributions of source code must retain the above copyright
5600c16b537SWarner Losh    notice, this list of conditions and the following disclaimer.
5610c16b537SWarner Losh        * Redistributions in binary form must reproduce the above
5620c16b537SWarner Losh    copyright notice, this list of conditions and the following disclaimer
5630c16b537SWarner Losh    in the documentation and/or other materials provided with the
5640c16b537SWarner Losh    distribution.
5650c16b537SWarner Losh 
5660c16b537SWarner Losh    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
5670c16b537SWarner Losh    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5680c16b537SWarner Losh    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
5690c16b537SWarner Losh    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
5700c16b537SWarner Losh    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
5710c16b537SWarner Losh    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
5720c16b537SWarner Losh    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
5730c16b537SWarner Losh    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
5740c16b537SWarner Losh    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
5750c16b537SWarner Losh    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
5760c16b537SWarner Losh    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5770c16b537SWarner Losh 
5780c16b537SWarner Losh    You can contact the author at :
5790c16b537SWarner Losh    - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
5800c16b537SWarner Losh    - Public forum : https://groups.google.com/forum/#!forum/lz4c
5810c16b537SWarner Losh ****************************************************************** */
5820c16b537SWarner Losh #ifndef FSEv05_H
5830c16b537SWarner Losh #define FSEv05_H
5840c16b537SWarner Losh 
5850c16b537SWarner Losh #if defined (__cplusplus)
5860c16b537SWarner Losh extern "C" {
5870c16b537SWarner Losh #endif
5880c16b537SWarner Losh 
5890c16b537SWarner Losh 
5900c16b537SWarner Losh /* *****************************************
5910c16b537SWarner Losh *  Includes
5920c16b537SWarner Losh ******************************************/
5930c16b537SWarner Losh #include <stddef.h>    /* size_t, ptrdiff_t */
5940c16b537SWarner Losh 
5950c16b537SWarner Losh 
5960c16b537SWarner Losh /*-****************************************
5970c16b537SWarner Losh *  FSEv05 simple functions
5980c16b537SWarner Losh ******************************************/
5990c16b537SWarner Losh size_t FSEv05_decompress(void* dst,  size_t maxDstSize,
6000c16b537SWarner Losh                 const void* cSrc, size_t cSrcSize);
6010c16b537SWarner Losh /*!
6020c16b537SWarner Losh FSEv05_decompress():
6030c16b537SWarner Losh     Decompress FSEv05 data from buffer 'cSrc', of size 'cSrcSize',
6040c16b537SWarner Losh     into already allocated destination buffer 'dst', of size 'maxDstSize'.
6050c16b537SWarner Losh     return : size of regenerated data (<= maxDstSize)
6060c16b537SWarner Losh              or an error code, which can be tested using FSEv05_isError()
6070c16b537SWarner Losh 
6080c16b537SWarner Losh     ** Important ** : FSEv05_decompress() doesn't decompress non-compressible nor RLE data !!!
6090c16b537SWarner Losh     Why ? : making this distinction requires a header.
6100c16b537SWarner Losh     Header management is intentionally delegated to the user layer, which can better manage special cases.
6110c16b537SWarner Losh */
6120c16b537SWarner Losh 
6130c16b537SWarner Losh 
6140c16b537SWarner Losh /* *****************************************
6150c16b537SWarner Losh *  Tool functions
6160c16b537SWarner Losh ******************************************/
6170c16b537SWarner Losh /* Error Management */
6180c16b537SWarner Losh unsigned    FSEv05_isError(size_t code);        /* tells if a return value is an error code */
6190c16b537SWarner Losh const char* FSEv05_getErrorName(size_t code);   /* provides error code string (useful for debugging) */
6200c16b537SWarner Losh 
6210c16b537SWarner Losh 
6220c16b537SWarner Losh 
6230c16b537SWarner Losh 
6240c16b537SWarner Losh /* *****************************************
6250c16b537SWarner Losh *  FSEv05 detailed API
6260c16b537SWarner Losh ******************************************/
6270c16b537SWarner Losh /* *** DECOMPRESSION *** */
6280c16b537SWarner Losh 
6290c16b537SWarner Losh /*!
6300c16b537SWarner Losh FSEv05_readNCount():
6310c16b537SWarner Losh    Read compactly saved 'normalizedCounter' from 'rBuffer'.
6320c16b537SWarner Losh    return : size read from 'rBuffer'
6330c16b537SWarner Losh             or an errorCode, which can be tested using FSEv05_isError()
6340c16b537SWarner Losh             maxSymbolValuePtr[0] and tableLogPtr[0] will also be updated with their respective values */
6350c16b537SWarner Losh size_t FSEv05_readNCount (short* normalizedCounter, unsigned* maxSymbolValuePtr, unsigned* tableLogPtr, const void* rBuffer, size_t rBuffSize);
6360c16b537SWarner Losh 
6370c16b537SWarner Losh /*!
6380c16b537SWarner Losh Constructor and Destructor of type FSEv05_DTable
6390c16b537SWarner Losh     Note that its size depends on 'tableLog' */
6400c16b537SWarner Losh typedef unsigned FSEv05_DTable;   /* don't allocate that. It's just a way to be more restrictive than void* */
6410c16b537SWarner Losh FSEv05_DTable* FSEv05_createDTable(unsigned tableLog);
6420c16b537SWarner Losh void        FSEv05_freeDTable(FSEv05_DTable* dt);
6430c16b537SWarner Losh 
6440c16b537SWarner Losh /*!
6450c16b537SWarner Losh FSEv05_buildDTable():
6460c16b537SWarner Losh    Builds 'dt', which must be already allocated, using FSEv05_createDTable()
6470c16b537SWarner Losh    @return : 0,
6480c16b537SWarner Losh              or an errorCode, which can be tested using FSEv05_isError() */
6490c16b537SWarner Losh size_t FSEv05_buildDTable (FSEv05_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);
6500c16b537SWarner Losh 
6510c16b537SWarner Losh /*!
6520c16b537SWarner Losh FSEv05_decompress_usingDTable():
6530c16b537SWarner Losh    Decompress compressed source @cSrc of size @cSrcSize using `dt`
6540c16b537SWarner Losh    into `dst` which must be already allocated.
6550c16b537SWarner Losh    @return : size of regenerated data (necessarily <= @dstCapacity)
6560c16b537SWarner Losh              or an errorCode, which can be tested using FSEv05_isError() */
6570c16b537SWarner Losh size_t FSEv05_decompress_usingDTable(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, const FSEv05_DTable* dt);
6580c16b537SWarner Losh 
6590c16b537SWarner Losh 
6600c16b537SWarner Losh 
6610c16b537SWarner Losh #if defined (__cplusplus)
6620c16b537SWarner Losh }
6630c16b537SWarner Losh #endif
6640c16b537SWarner Losh 
6650c16b537SWarner Losh #endif  /* FSEv05_H */
6660c16b537SWarner Losh /* ******************************************************************
6670c16b537SWarner Losh    bitstream
6680c16b537SWarner Losh    Part of FSEv05 library
6690c16b537SWarner Losh    header file (to include)
6700c16b537SWarner Losh    Copyright (C) 2013-2016, Yann Collet.
6710c16b537SWarner Losh 
6720c16b537SWarner Losh    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6730c16b537SWarner Losh 
6740c16b537SWarner Losh    Redistribution and use in source and binary forms, with or without
6750c16b537SWarner Losh    modification, are permitted provided that the following conditions are
6760c16b537SWarner Losh    met:
6770c16b537SWarner Losh 
6780c16b537SWarner Losh        * Redistributions of source code must retain the above copyright
6790c16b537SWarner Losh    notice, this list of conditions and the following disclaimer.
6800c16b537SWarner Losh        * Redistributions in binary form must reproduce the above
6810c16b537SWarner Losh    copyright notice, this list of conditions and the following disclaimer
6820c16b537SWarner Losh    in the documentation and/or other materials provided with the
6830c16b537SWarner Losh    distribution.
6840c16b537SWarner Losh 
6850c16b537SWarner Losh    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
6860c16b537SWarner Losh    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
6870c16b537SWarner Losh    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6880c16b537SWarner Losh    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
6890c16b537SWarner Losh    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
6900c16b537SWarner Losh    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
6910c16b537SWarner Losh    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
6920c16b537SWarner Losh    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
6930c16b537SWarner Losh    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
6940c16b537SWarner Losh    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
6950c16b537SWarner Losh    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
6960c16b537SWarner Losh 
6970c16b537SWarner Losh    You can contact the author at :
6980c16b537SWarner Losh    - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
6990c16b537SWarner Losh ****************************************************************** */
7000c16b537SWarner Losh #ifndef BITv05STREAM_H_MODULE
7010c16b537SWarner Losh #define BITv05STREAM_H_MODULE
7020c16b537SWarner Losh 
7030c16b537SWarner Losh #if defined (__cplusplus)
7040c16b537SWarner Losh extern "C" {
7050c16b537SWarner Losh #endif
7060c16b537SWarner Losh 
7070c16b537SWarner Losh 
7080c16b537SWarner Losh /*
7090c16b537SWarner Losh *  This API consists of small unitary functions, which highly benefit from being inlined.
7100c16b537SWarner Losh *  Since link-time-optimization is not available for all compilers,
7110c16b537SWarner Losh *  these functions are defined into a .h to be included.
7120c16b537SWarner Losh */
7130c16b537SWarner Losh 
7140c16b537SWarner Losh 
7150c16b537SWarner Losh 
7160c16b537SWarner Losh /*-********************************************
7170c16b537SWarner Losh *  bitStream decoding API (read backward)
7180c16b537SWarner Losh **********************************************/
7190c16b537SWarner Losh typedef struct
7200c16b537SWarner Losh {
7210c16b537SWarner Losh     size_t   bitContainer;
7220c16b537SWarner Losh     unsigned bitsConsumed;
7230c16b537SWarner Losh     const char* ptr;
7240c16b537SWarner Losh     const char* start;
7250c16b537SWarner Losh } BITv05_DStream_t;
7260c16b537SWarner Losh 
7270c16b537SWarner Losh typedef enum { BITv05_DStream_unfinished = 0,
7280c16b537SWarner Losh                BITv05_DStream_endOfBuffer = 1,
7290c16b537SWarner Losh                BITv05_DStream_completed = 2,
7300c16b537SWarner Losh                BITv05_DStream_overflow = 3 } BITv05_DStream_status;  /* result of BITv05_reloadDStream() */
7310c16b537SWarner Losh                /* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */
7320c16b537SWarner Losh 
7330c16b537SWarner Losh MEM_STATIC size_t   BITv05_initDStream(BITv05_DStream_t* bitD, const void* srcBuffer, size_t srcSize);
7340c16b537SWarner Losh MEM_STATIC size_t   BITv05_readBits(BITv05_DStream_t* bitD, unsigned nbBits);
7350c16b537SWarner Losh MEM_STATIC BITv05_DStream_status BITv05_reloadDStream(BITv05_DStream_t* bitD);
7360c16b537SWarner Losh MEM_STATIC unsigned BITv05_endOfDStream(const BITv05_DStream_t* bitD);
7370c16b537SWarner Losh 
7380c16b537SWarner Losh 
7390c16b537SWarner Losh /*-****************************************
7400c16b537SWarner Losh *  unsafe API
7410c16b537SWarner Losh ******************************************/
7420c16b537SWarner Losh MEM_STATIC size_t BITv05_readBitsFast(BITv05_DStream_t* bitD, unsigned nbBits);
7430c16b537SWarner Losh /* faster, but works only if nbBits >= 1 */
7440c16b537SWarner Losh 
7450c16b537SWarner Losh 
7460c16b537SWarner Losh 
7470c16b537SWarner Losh /*-**************************************************************
7480c16b537SWarner Losh *  Helper functions
7490c16b537SWarner Losh ****************************************************************/
750052d3c12SConrad Meyer MEM_STATIC unsigned BITv05_highbit32 (U32 val)
7510c16b537SWarner Losh {
7520c16b537SWarner Losh #   if defined(_MSC_VER)   /* Visual */
7530c16b537SWarner Losh     unsigned long r=0;
7540c16b537SWarner Losh     _BitScanReverse ( &r, val );
7550c16b537SWarner Losh     return (unsigned) r;
7560c16b537SWarner Losh #   elif defined(__GNUC__) && (__GNUC__ >= 3)   /* Use GCC Intrinsic */
7570c16b537SWarner Losh     return 31 - __builtin_clz (val);
7580c16b537SWarner Losh #   else   /* Software version */
7590c16b537SWarner 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 };
7600c16b537SWarner Losh     U32 v = val;
7610c16b537SWarner Losh     unsigned r;
7620c16b537SWarner Losh     v |= v >> 1;
7630c16b537SWarner Losh     v |= v >> 2;
7640c16b537SWarner Losh     v |= v >> 4;
7650c16b537SWarner Losh     v |= v >> 8;
7660c16b537SWarner Losh     v |= v >> 16;
7670c16b537SWarner Losh     r = DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27];
7680c16b537SWarner Losh     return r;
7690c16b537SWarner Losh #   endif
7700c16b537SWarner Losh }
7710c16b537SWarner Losh 
7720c16b537SWarner Losh 
7730c16b537SWarner Losh 
7740c16b537SWarner Losh /*-********************************************************
7750c16b537SWarner Losh * bitStream decoding
7760c16b537SWarner Losh **********************************************************/
7770c16b537SWarner Losh /*!BITv05_initDStream
7780c16b537SWarner Losh *  Initialize a BITv05_DStream_t.
7790c16b537SWarner Losh *  @bitD : a pointer to an already allocated BITv05_DStream_t structure
7800c16b537SWarner Losh *  @srcBuffer must point at the beginning of a bitStream
7810c16b537SWarner Losh *  @srcSize must be the exact size of the bitStream
7820c16b537SWarner Losh *  @result : size of stream (== srcSize) or an errorCode if a problem is detected
7830c16b537SWarner Losh */
7840c16b537SWarner Losh MEM_STATIC size_t BITv05_initDStream(BITv05_DStream_t* bitD, const void* srcBuffer, size_t srcSize)
7850c16b537SWarner Losh {
7860c16b537SWarner Losh     if (srcSize < 1) { memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); }
7870c16b537SWarner Losh 
7880c16b537SWarner Losh     if (srcSize >=  sizeof(size_t)) {  /* normal case */
7890c16b537SWarner Losh         U32 contain32;
7900c16b537SWarner Losh         bitD->start = (const char*)srcBuffer;
7910c16b537SWarner Losh         bitD->ptr   = (const char*)srcBuffer + srcSize - sizeof(size_t);
7920c16b537SWarner Losh         bitD->bitContainer = MEM_readLEST(bitD->ptr);
7930c16b537SWarner Losh         contain32 = ((const BYTE*)srcBuffer)[srcSize-1];
7940c16b537SWarner Losh         if (contain32 == 0) return ERROR(GENERIC);   /* endMark not present */
7950c16b537SWarner Losh         bitD->bitsConsumed = 8 - BITv05_highbit32(contain32);
7960c16b537SWarner Losh     } else {
7970c16b537SWarner Losh         U32 contain32;
7980c16b537SWarner Losh         bitD->start = (const char*)srcBuffer;
7990c16b537SWarner Losh         bitD->ptr   = bitD->start;
8000c16b537SWarner Losh         bitD->bitContainer = *(const BYTE*)(bitD->start);
8010c16b537SWarner Losh         switch(srcSize)
8020c16b537SWarner Losh         {
8030c16b537SWarner Losh             case 7: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[6]) << (sizeof(size_t)*8 - 16);/* fall-through */
8040c16b537SWarner Losh             case 6: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[5]) << (sizeof(size_t)*8 - 24);/* fall-through */
8050c16b537SWarner Losh             case 5: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[4]) << (sizeof(size_t)*8 - 32);/* fall-through */
8060c16b537SWarner Losh             case 4: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[3]) << 24; /* fall-through */
8070c16b537SWarner Losh             case 3: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[2]) << 16; /* fall-through */
8080c16b537SWarner Losh             case 2: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[1]) <<  8; /* fall-through */
8090c16b537SWarner Losh             default: break;
8100c16b537SWarner Losh         }
8110c16b537SWarner Losh         contain32 = ((const BYTE*)srcBuffer)[srcSize-1];
8120c16b537SWarner Losh         if (contain32 == 0) return ERROR(GENERIC);   /* endMark not present */
8130c16b537SWarner Losh         bitD->bitsConsumed = 8 - BITv05_highbit32(contain32);
8140c16b537SWarner Losh         bitD->bitsConsumed += (U32)(sizeof(size_t) - srcSize)*8;
8150c16b537SWarner Losh     }
8160c16b537SWarner Losh 
8170c16b537SWarner Losh     return srcSize;
8180c16b537SWarner Losh }
8190c16b537SWarner Losh 
8200c16b537SWarner Losh MEM_STATIC size_t BITv05_lookBits(BITv05_DStream_t* bitD, U32 nbBits)
8210c16b537SWarner Losh {
8220c16b537SWarner Losh     const U32 bitMask = sizeof(bitD->bitContainer)*8 - 1;
8230c16b537SWarner Losh     return ((bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> 1) >> ((bitMask-nbBits) & bitMask);
8240c16b537SWarner Losh }
8250c16b537SWarner Losh 
8260c16b537SWarner Losh /*! BITv05_lookBitsFast :
8270c16b537SWarner Losh *   unsafe version; only works only if nbBits >= 1 */
8280c16b537SWarner Losh MEM_STATIC size_t BITv05_lookBitsFast(BITv05_DStream_t* bitD, U32 nbBits)
8290c16b537SWarner Losh {
8300c16b537SWarner Losh     const U32 bitMask = sizeof(bitD->bitContainer)*8 - 1;
8310c16b537SWarner Losh     return (bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> (((bitMask+1)-nbBits) & bitMask);
8320c16b537SWarner Losh }
8330c16b537SWarner Losh 
8340c16b537SWarner Losh MEM_STATIC void BITv05_skipBits(BITv05_DStream_t* bitD, U32 nbBits)
8350c16b537SWarner Losh {
8360c16b537SWarner Losh     bitD->bitsConsumed += nbBits;
8370c16b537SWarner Losh }
8380c16b537SWarner Losh 
8390c16b537SWarner Losh MEM_STATIC size_t BITv05_readBits(BITv05_DStream_t* bitD, U32 nbBits)
8400c16b537SWarner Losh {
8410c16b537SWarner Losh     size_t value = BITv05_lookBits(bitD, nbBits);
8420c16b537SWarner Losh     BITv05_skipBits(bitD, nbBits);
8430c16b537SWarner Losh     return value;
8440c16b537SWarner Losh }
8450c16b537SWarner Losh 
8460c16b537SWarner Losh /*!BITv05_readBitsFast :
8470c16b537SWarner Losh *  unsafe version; only works only if nbBits >= 1 */
8480c16b537SWarner Losh MEM_STATIC size_t BITv05_readBitsFast(BITv05_DStream_t* bitD, U32 nbBits)
8490c16b537SWarner Losh {
8500c16b537SWarner Losh     size_t value = BITv05_lookBitsFast(bitD, nbBits);
8510c16b537SWarner Losh     BITv05_skipBits(bitD, nbBits);
8520c16b537SWarner Losh     return value;
8530c16b537SWarner Losh }
8540c16b537SWarner Losh 
8550c16b537SWarner Losh MEM_STATIC BITv05_DStream_status BITv05_reloadDStream(BITv05_DStream_t* bitD)
8560c16b537SWarner Losh {
8570c16b537SWarner Losh     if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8))  /* should never happen */
8580c16b537SWarner Losh         return BITv05_DStream_overflow;
8590c16b537SWarner Losh 
8600c16b537SWarner Losh     if (bitD->ptr >= bitD->start + sizeof(bitD->bitContainer)) {
8610c16b537SWarner Losh         bitD->ptr -= bitD->bitsConsumed >> 3;
8620c16b537SWarner Losh         bitD->bitsConsumed &= 7;
8630c16b537SWarner Losh         bitD->bitContainer = MEM_readLEST(bitD->ptr);
8640c16b537SWarner Losh         return BITv05_DStream_unfinished;
8650c16b537SWarner Losh     }
8660c16b537SWarner Losh     if (bitD->ptr == bitD->start) {
8670c16b537SWarner Losh         if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BITv05_DStream_endOfBuffer;
8680c16b537SWarner Losh         return BITv05_DStream_completed;
8690c16b537SWarner Losh     }
8700c16b537SWarner Losh     {
8710c16b537SWarner Losh         U32 nbBytes = bitD->bitsConsumed >> 3;
8720c16b537SWarner Losh         BITv05_DStream_status result = BITv05_DStream_unfinished;
8730c16b537SWarner Losh         if (bitD->ptr - nbBytes < bitD->start) {
8740c16b537SWarner Losh             nbBytes = (U32)(bitD->ptr - bitD->start);  /* ptr > start */
8750c16b537SWarner Losh             result = BITv05_DStream_endOfBuffer;
8760c16b537SWarner Losh         }
8770c16b537SWarner Losh         bitD->ptr -= nbBytes;
8780c16b537SWarner Losh         bitD->bitsConsumed -= nbBytes*8;
8790c16b537SWarner Losh         bitD->bitContainer = MEM_readLEST(bitD->ptr);   /* reminder : srcSize > sizeof(bitD) */
8800c16b537SWarner Losh         return result;
8810c16b537SWarner Losh     }
8820c16b537SWarner Losh }
8830c16b537SWarner Losh 
8840c16b537SWarner Losh /*! BITv05_endOfDStream
8850c16b537SWarner Losh *   @return Tells if DStream has reached its exact end
8860c16b537SWarner Losh */
8870c16b537SWarner Losh MEM_STATIC unsigned BITv05_endOfDStream(const BITv05_DStream_t* DStream)
8880c16b537SWarner Losh {
8890c16b537SWarner Losh     return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer)*8));
8900c16b537SWarner Losh }
8910c16b537SWarner Losh 
8920c16b537SWarner Losh #if defined (__cplusplus)
8930c16b537SWarner Losh }
8940c16b537SWarner Losh #endif
8950c16b537SWarner Losh 
8960c16b537SWarner Losh #endif /* BITv05STREAM_H_MODULE */
8970c16b537SWarner Losh /* ******************************************************************
8980c16b537SWarner Losh    FSEv05 : Finite State Entropy coder
8990c16b537SWarner Losh    header file for static linking (only)
9000c16b537SWarner Losh    Copyright (C) 2013-2015, Yann Collet
9010c16b537SWarner Losh 
9020c16b537SWarner Losh    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
9030c16b537SWarner Losh 
9040c16b537SWarner Losh    Redistribution and use in source and binary forms, with or without
9050c16b537SWarner Losh    modification, are permitted provided that the following conditions are
9060c16b537SWarner Losh    met:
9070c16b537SWarner Losh 
9080c16b537SWarner Losh        * Redistributions of source code must retain the above copyright
9090c16b537SWarner Losh    notice, this list of conditions and the following disclaimer.
9100c16b537SWarner Losh        * Redistributions in binary form must reproduce the above
9110c16b537SWarner Losh    copyright notice, this list of conditions and the following disclaimer
9120c16b537SWarner Losh    in the documentation and/or other materials provided with the
9130c16b537SWarner Losh    distribution.
9140c16b537SWarner Losh 
9150c16b537SWarner Losh    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
9160c16b537SWarner Losh    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
9170c16b537SWarner Losh    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
9180c16b537SWarner Losh    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
9190c16b537SWarner Losh    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
9200c16b537SWarner Losh    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9210c16b537SWarner Losh    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
9220c16b537SWarner Losh    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
9230c16b537SWarner Losh    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
9240c16b537SWarner Losh    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
9250c16b537SWarner Losh    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
9260c16b537SWarner Losh 
9270c16b537SWarner Losh    You can contact the author at :
9280c16b537SWarner Losh    - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
9290c16b537SWarner Losh    - Public forum : https://groups.google.com/forum/#!forum/lz4c
9300c16b537SWarner Losh ****************************************************************** */
9310c16b537SWarner Losh #ifndef FSEv05_STATIC_H
9320c16b537SWarner Losh #define FSEv05_STATIC_H
9330c16b537SWarner Losh 
9340c16b537SWarner Losh #if defined (__cplusplus)
9350c16b537SWarner Losh extern "C" {
9360c16b537SWarner Losh #endif
9370c16b537SWarner Losh 
9380c16b537SWarner Losh 
9390c16b537SWarner Losh 
9400c16b537SWarner Losh /* *****************************************
9410c16b537SWarner Losh *  Static allocation
9420c16b537SWarner Losh *******************************************/
9430c16b537SWarner Losh /* It is possible to statically allocate FSEv05 CTable/DTable as a table of unsigned using below macros */
9440c16b537SWarner Losh #define FSEv05_DTABLE_SIZE_U32(maxTableLog)                   (1 + (1<<maxTableLog))
9450c16b537SWarner Losh 
9460c16b537SWarner Losh 
9470c16b537SWarner Losh /* *****************************************
9480c16b537SWarner Losh *  FSEv05 advanced API
9490c16b537SWarner Losh *******************************************/
9500c16b537SWarner Losh size_t FSEv05_buildDTable_raw (FSEv05_DTable* dt, unsigned nbBits);
9510c16b537SWarner Losh /* build a fake FSEv05_DTable, designed to read an uncompressed bitstream where each symbol uses nbBits */
9520c16b537SWarner Losh 
9530c16b537SWarner Losh size_t FSEv05_buildDTable_rle (FSEv05_DTable* dt, unsigned char symbolValue);
9540c16b537SWarner Losh /* build a fake FSEv05_DTable, designed to always generate the same symbolValue */
9550c16b537SWarner Losh 
9560c16b537SWarner Losh 
9570c16b537SWarner Losh 
9580c16b537SWarner Losh /* *****************************************
9590c16b537SWarner Losh *  FSEv05 symbol decompression API
9600c16b537SWarner Losh *******************************************/
9610c16b537SWarner Losh typedef struct
9620c16b537SWarner Losh {
9630c16b537SWarner Losh     size_t      state;
9640c16b537SWarner Losh     const void* table;   /* precise table may vary, depending on U16 */
9650c16b537SWarner Losh } FSEv05_DState_t;
9660c16b537SWarner Losh 
9670c16b537SWarner Losh 
9680c16b537SWarner Losh static void     FSEv05_initDState(FSEv05_DState_t* DStatePtr, BITv05_DStream_t* bitD, const FSEv05_DTable* dt);
9690c16b537SWarner Losh 
9700c16b537SWarner Losh static unsigned char FSEv05_decodeSymbol(FSEv05_DState_t* DStatePtr, BITv05_DStream_t* bitD);
9710c16b537SWarner Losh 
9720c16b537SWarner Losh static unsigned FSEv05_endOfDState(const FSEv05_DState_t* DStatePtr);
9730c16b537SWarner Losh 
9740c16b537SWarner Losh 
9750c16b537SWarner Losh 
9760c16b537SWarner Losh /* *****************************************
9770c16b537SWarner Losh *  FSEv05 unsafe API
9780c16b537SWarner Losh *******************************************/
9790c16b537SWarner Losh static unsigned char FSEv05_decodeSymbolFast(FSEv05_DState_t* DStatePtr, BITv05_DStream_t* bitD);
9800c16b537SWarner Losh /* faster, but works only if nbBits is always >= 1 (otherwise, result will be corrupted) */
9810c16b537SWarner Losh 
9820c16b537SWarner Losh 
9830c16b537SWarner Losh /* *****************************************
9840c16b537SWarner Losh *  Implementation of inlined functions
9850c16b537SWarner Losh *******************************************/
9860c16b537SWarner Losh /* decompression */
9870c16b537SWarner Losh 
9880c16b537SWarner Losh typedef struct {
9890c16b537SWarner Losh     U16 tableLog;
9900c16b537SWarner Losh     U16 fastMode;
9910c16b537SWarner Losh } FSEv05_DTableHeader;   /* sizeof U32 */
9920c16b537SWarner Losh 
9930c16b537SWarner Losh typedef struct
9940c16b537SWarner Losh {
9950c16b537SWarner Losh     unsigned short newState;
9960c16b537SWarner Losh     unsigned char  symbol;
9970c16b537SWarner Losh     unsigned char  nbBits;
9980c16b537SWarner Losh } FSEv05_decode_t;   /* size == U32 */
9990c16b537SWarner Losh 
10000c16b537SWarner Losh MEM_STATIC void FSEv05_initDState(FSEv05_DState_t* DStatePtr, BITv05_DStream_t* bitD, const FSEv05_DTable* dt)
10010c16b537SWarner Losh {
10020c16b537SWarner Losh     const void* ptr = dt;
10030c16b537SWarner Losh     const FSEv05_DTableHeader* const DTableH = (const FSEv05_DTableHeader*)ptr;
10040c16b537SWarner Losh     DStatePtr->state = BITv05_readBits(bitD, DTableH->tableLog);
10050c16b537SWarner Losh     BITv05_reloadDStream(bitD);
10060c16b537SWarner Losh     DStatePtr->table = dt + 1;
10070c16b537SWarner Losh }
10080c16b537SWarner Losh 
10090c16b537SWarner Losh MEM_STATIC BYTE FSEv05_peakSymbol(FSEv05_DState_t* DStatePtr)
10100c16b537SWarner Losh {
10110c16b537SWarner Losh     const FSEv05_decode_t DInfo = ((const FSEv05_decode_t*)(DStatePtr->table))[DStatePtr->state];
10120c16b537SWarner Losh     return DInfo.symbol;
10130c16b537SWarner Losh }
10140c16b537SWarner Losh 
10150c16b537SWarner Losh MEM_STATIC BYTE FSEv05_decodeSymbol(FSEv05_DState_t* DStatePtr, BITv05_DStream_t* bitD)
10160c16b537SWarner Losh {
10170c16b537SWarner Losh     const FSEv05_decode_t DInfo = ((const FSEv05_decode_t*)(DStatePtr->table))[DStatePtr->state];
10180c16b537SWarner Losh     const U32  nbBits = DInfo.nbBits;
10190c16b537SWarner Losh     BYTE symbol = DInfo.symbol;
10200c16b537SWarner Losh     size_t lowBits = BITv05_readBits(bitD, nbBits);
10210c16b537SWarner Losh 
10220c16b537SWarner Losh     DStatePtr->state = DInfo.newState + lowBits;
10230c16b537SWarner Losh     return symbol;
10240c16b537SWarner Losh }
10250c16b537SWarner Losh 
10260c16b537SWarner Losh MEM_STATIC BYTE FSEv05_decodeSymbolFast(FSEv05_DState_t* DStatePtr, BITv05_DStream_t* bitD)
10270c16b537SWarner Losh {
10280c16b537SWarner Losh     const FSEv05_decode_t DInfo = ((const FSEv05_decode_t*)(DStatePtr->table))[DStatePtr->state];
10290c16b537SWarner Losh     const U32 nbBits = DInfo.nbBits;
10300c16b537SWarner Losh     BYTE symbol = DInfo.symbol;
10310c16b537SWarner Losh     size_t lowBits = BITv05_readBitsFast(bitD, nbBits);
10320c16b537SWarner Losh 
10330c16b537SWarner Losh     DStatePtr->state = DInfo.newState + lowBits;
10340c16b537SWarner Losh     return symbol;
10350c16b537SWarner Losh }
10360c16b537SWarner Losh 
10370c16b537SWarner Losh MEM_STATIC unsigned FSEv05_endOfDState(const FSEv05_DState_t* DStatePtr)
10380c16b537SWarner Losh {
10390c16b537SWarner Losh     return DStatePtr->state == 0;
10400c16b537SWarner Losh }
10410c16b537SWarner Losh 
10420c16b537SWarner Losh 
10430c16b537SWarner Losh #if defined (__cplusplus)
10440c16b537SWarner Losh }
10450c16b537SWarner Losh #endif
10460c16b537SWarner Losh 
10470c16b537SWarner Losh #endif  /* FSEv05_STATIC_H */
10480c16b537SWarner Losh /* ******************************************************************
10490c16b537SWarner Losh    FSEv05 : Finite State Entropy coder
10500c16b537SWarner Losh    Copyright (C) 2013-2015, Yann Collet.
10510c16b537SWarner Losh 
10520c16b537SWarner Losh    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
10530c16b537SWarner Losh 
10540c16b537SWarner Losh    Redistribution and use in source and binary forms, with or without
10550c16b537SWarner Losh    modification, are permitted provided that the following conditions are
10560c16b537SWarner Losh    met:
10570c16b537SWarner Losh 
10580c16b537SWarner Losh        * Redistributions of source code must retain the above copyright
10590c16b537SWarner Losh    notice, this list of conditions and the following disclaimer.
10600c16b537SWarner Losh        * Redistributions in binary form must reproduce the above
10610c16b537SWarner Losh    copyright notice, this list of conditions and the following disclaimer
10620c16b537SWarner Losh    in the documentation and/or other materials provided with the
10630c16b537SWarner Losh    distribution.
10640c16b537SWarner Losh 
10650c16b537SWarner Losh    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
10660c16b537SWarner Losh    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
10670c16b537SWarner Losh    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
10680c16b537SWarner Losh    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
10690c16b537SWarner Losh    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
10700c16b537SWarner Losh    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
10710c16b537SWarner Losh    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10720c16b537SWarner Losh    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
10730c16b537SWarner Losh    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
10740c16b537SWarner Losh    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
10750c16b537SWarner Losh    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
10760c16b537SWarner Losh 
10770c16b537SWarner Losh     You can contact the author at :
10780c16b537SWarner Losh     - FSEv05 source repository : https://github.com/Cyan4973/FiniteStateEntropy
10790c16b537SWarner Losh     - Public forum : https://groups.google.com/forum/#!forum/lz4c
10800c16b537SWarner Losh ****************************************************************** */
10810c16b537SWarner Losh 
10820c16b537SWarner Losh #ifndef FSEv05_COMMONDEFS_ONLY
10830c16b537SWarner Losh 
10840c16b537SWarner Losh /* **************************************************************
10850c16b537SWarner Losh *  Tuning parameters
10860c16b537SWarner Losh ****************************************************************/
10870c16b537SWarner Losh /*!MEMORY_USAGE :
10880c16b537SWarner Losh *  Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
10890c16b537SWarner Losh *  Increasing memory usage improves compression ratio
10900c16b537SWarner Losh *  Reduced memory usage can improve speed, due to cache effect
10910c16b537SWarner Losh *  Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */
10920c16b537SWarner Losh #define FSEv05_MAX_MEMORY_USAGE 14
10930c16b537SWarner Losh #define FSEv05_DEFAULT_MEMORY_USAGE 13
10940c16b537SWarner Losh 
10950c16b537SWarner Losh /*!FSEv05_MAX_SYMBOL_VALUE :
10960c16b537SWarner Losh *  Maximum symbol value authorized.
10970c16b537SWarner Losh *  Required for proper stack allocation */
10980c16b537SWarner Losh #define FSEv05_MAX_SYMBOL_VALUE 255
10990c16b537SWarner Losh 
11000c16b537SWarner Losh 
11010c16b537SWarner Losh /* **************************************************************
11020c16b537SWarner Losh *  template functions type & suffix
11030c16b537SWarner Losh ****************************************************************/
11040c16b537SWarner Losh #define FSEv05_FUNCTION_TYPE BYTE
11050c16b537SWarner Losh #define FSEv05_FUNCTION_EXTENSION
11060c16b537SWarner Losh #define FSEv05_DECODE_TYPE FSEv05_decode_t
11070c16b537SWarner Losh 
11080c16b537SWarner Losh 
11090c16b537SWarner Losh #endif   /* !FSEv05_COMMONDEFS_ONLY */
11100c16b537SWarner Losh 
11110c16b537SWarner Losh /* **************************************************************
11120c16b537SWarner Losh *  Compiler specifics
11130c16b537SWarner Losh ****************************************************************/
11140c16b537SWarner Losh #ifdef _MSC_VER    /* Visual Studio */
11150c16b537SWarner Losh #  define FORCE_INLINE static __forceinline
11160c16b537SWarner Losh #  include <intrin.h>                    /* For Visual 2005 */
11170c16b537SWarner Losh #  pragma warning(disable : 4127)        /* disable: C4127: conditional expression is constant */
11180c16b537SWarner Losh #  pragma warning(disable : 4214)        /* disable: C4214: non-int bitfields */
11190c16b537SWarner Losh #else
11200c16b537SWarner Losh #  if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L   /* C99 */
11210c16b537SWarner Losh #    ifdef __GNUC__
11220c16b537SWarner Losh #      define FORCE_INLINE static inline __attribute__((always_inline))
11230c16b537SWarner Losh #    else
11240c16b537SWarner Losh #      define FORCE_INLINE static inline
11250c16b537SWarner Losh #    endif
11260c16b537SWarner Losh #  else
11270c16b537SWarner Losh #    define FORCE_INLINE static
11280c16b537SWarner Losh #  endif /* __STDC_VERSION__ */
11290c16b537SWarner Losh #endif
11300c16b537SWarner Losh 
11310c16b537SWarner Losh 
11320c16b537SWarner Losh /* **************************************************************
11330c16b537SWarner Losh *  Includes
11340c16b537SWarner Losh ****************************************************************/
11350c16b537SWarner Losh #include <stdlib.h>     /* malloc, free, qsort */
11360c16b537SWarner Losh #include <string.h>     /* memcpy, memset */
11370c16b537SWarner Losh #include <stdio.h>      /* printf (debug) */
11380c16b537SWarner Losh 
11390c16b537SWarner Losh 
11400c16b537SWarner Losh 
11410c16b537SWarner Losh /* ***************************************************************
11420c16b537SWarner Losh *  Constants
11430c16b537SWarner Losh *****************************************************************/
11440c16b537SWarner Losh #define FSEv05_MAX_TABLELOG  (FSEv05_MAX_MEMORY_USAGE-2)
11450c16b537SWarner Losh #define FSEv05_MAX_TABLESIZE (1U<<FSEv05_MAX_TABLELOG)
11460c16b537SWarner Losh #define FSEv05_MAXTABLESIZE_MASK (FSEv05_MAX_TABLESIZE-1)
11470c16b537SWarner Losh #define FSEv05_DEFAULT_TABLELOG (FSEv05_DEFAULT_MEMORY_USAGE-2)
11480c16b537SWarner Losh #define FSEv05_MIN_TABLELOG 5
11490c16b537SWarner Losh 
11500c16b537SWarner Losh #define FSEv05_TABLELOG_ABSOLUTE_MAX 15
11510c16b537SWarner Losh #if FSEv05_MAX_TABLELOG > FSEv05_TABLELOG_ABSOLUTE_MAX
11520c16b537SWarner Losh #error "FSEv05_MAX_TABLELOG > FSEv05_TABLELOG_ABSOLUTE_MAX is not supported"
11530c16b537SWarner Losh #endif
11540c16b537SWarner Losh 
11550c16b537SWarner Losh 
11560c16b537SWarner Losh /* **************************************************************
11570c16b537SWarner Losh *  Error Management
11580c16b537SWarner Losh ****************************************************************/
11590c16b537SWarner Losh #define FSEv05_STATIC_ASSERT(c) { enum { FSEv05_static_assert = 1/(int)(!!(c)) }; }   /* use only *after* variable declarations */
11600c16b537SWarner Losh 
11610c16b537SWarner Losh 
11620c16b537SWarner Losh /* **************************************************************
11630c16b537SWarner Losh *  Complex types
11640c16b537SWarner Losh ****************************************************************/
11650c16b537SWarner Losh typedef U32 DTable_max_t[FSEv05_DTABLE_SIZE_U32(FSEv05_MAX_TABLELOG)];
11660c16b537SWarner Losh 
11670c16b537SWarner Losh 
11680c16b537SWarner Losh /* **************************************************************
11690c16b537SWarner Losh *  Templates
11700c16b537SWarner Losh ****************************************************************/
11710c16b537SWarner Losh /*
11720c16b537SWarner Losh   designed to be included
11730c16b537SWarner Losh   for type-specific functions (template emulation in C)
11740c16b537SWarner Losh   Objective is to write these functions only once, for improved maintenance
11750c16b537SWarner Losh */
11760c16b537SWarner Losh 
11770c16b537SWarner Losh /* safety checks */
11780c16b537SWarner Losh #ifndef FSEv05_FUNCTION_EXTENSION
11790c16b537SWarner Losh #  error "FSEv05_FUNCTION_EXTENSION must be defined"
11800c16b537SWarner Losh #endif
11810c16b537SWarner Losh #ifndef FSEv05_FUNCTION_TYPE
11820c16b537SWarner Losh #  error "FSEv05_FUNCTION_TYPE must be defined"
11830c16b537SWarner Losh #endif
11840c16b537SWarner Losh 
11850c16b537SWarner Losh /* Function names */
11860c16b537SWarner Losh #define FSEv05_CAT(X,Y) X##Y
11870c16b537SWarner Losh #define FSEv05_FUNCTION_NAME(X,Y) FSEv05_CAT(X,Y)
11880c16b537SWarner Losh #define FSEv05_TYPE_NAME(X,Y) FSEv05_CAT(X,Y)
11890c16b537SWarner Losh 
11900c16b537SWarner Losh 
11910c16b537SWarner Losh /* Function templates */
11920c16b537SWarner Losh static U32 FSEv05_tableStep(U32 tableSize) { return (tableSize>>1) + (tableSize>>3) + 3; }
11930c16b537SWarner Losh 
11940c16b537SWarner Losh 
11950c16b537SWarner Losh 
11960c16b537SWarner Losh FSEv05_DTable* FSEv05_createDTable (unsigned tableLog)
11970c16b537SWarner Losh {
11980c16b537SWarner Losh     if (tableLog > FSEv05_TABLELOG_ABSOLUTE_MAX) tableLog = FSEv05_TABLELOG_ABSOLUTE_MAX;
11990c16b537SWarner Losh     return (FSEv05_DTable*)malloc( FSEv05_DTABLE_SIZE_U32(tableLog) * sizeof (U32) );
12000c16b537SWarner Losh }
12010c16b537SWarner Losh 
12020c16b537SWarner Losh void FSEv05_freeDTable (FSEv05_DTable* dt)
12030c16b537SWarner Losh {
12040c16b537SWarner Losh     free(dt);
12050c16b537SWarner Losh }
12060c16b537SWarner Losh 
12070c16b537SWarner Losh size_t FSEv05_buildDTable(FSEv05_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
12080c16b537SWarner Losh {
12090c16b537SWarner Losh     FSEv05_DTableHeader DTableH;
12100c16b537SWarner Losh     void* const tdPtr = dt+1;   /* because dt is unsigned, 32-bits aligned on 32-bits */
12110c16b537SWarner Losh     FSEv05_DECODE_TYPE* const tableDecode = (FSEv05_DECODE_TYPE*) (tdPtr);
12120c16b537SWarner Losh     const U32 tableSize = 1 << tableLog;
12130c16b537SWarner Losh     const U32 tableMask = tableSize-1;
12140c16b537SWarner Losh     const U32 step = FSEv05_tableStep(tableSize);
12150c16b537SWarner Losh     U16 symbolNext[FSEv05_MAX_SYMBOL_VALUE+1];
12160c16b537SWarner Losh     U32 position = 0;
12170c16b537SWarner Losh     U32 highThreshold = tableSize-1;
12180c16b537SWarner Losh     const S16 largeLimit= (S16)(1 << (tableLog-1));
12190c16b537SWarner Losh     U32 noLarge = 1;
12200c16b537SWarner Losh     U32 s;
12210c16b537SWarner Losh 
12220c16b537SWarner Losh     /* Sanity Checks */
12230c16b537SWarner Losh     if (maxSymbolValue > FSEv05_MAX_SYMBOL_VALUE) return ERROR(maxSymbolValue_tooLarge);
12240c16b537SWarner Losh     if (tableLog > FSEv05_MAX_TABLELOG) return ERROR(tableLog_tooLarge);
12250c16b537SWarner Losh 
12260c16b537SWarner Losh     /* Init, lay down lowprob symbols */
1227*0f743729SConrad Meyer     memset(tableDecode, 0, sizeof(FSEv05_FUNCTION_TYPE) * (maxSymbolValue+1) );   /* useless init, but keep static analyzer happy, and we don't need to performance optimize legacy decoders */
12280c16b537SWarner Losh     DTableH.tableLog = (U16)tableLog;
12290c16b537SWarner Losh     for (s=0; s<=maxSymbolValue; s++) {
12300c16b537SWarner Losh         if (normalizedCounter[s]==-1) {
12310c16b537SWarner Losh             tableDecode[highThreshold--].symbol = (FSEv05_FUNCTION_TYPE)s;
12320c16b537SWarner Losh             symbolNext[s] = 1;
12330c16b537SWarner Losh         } else {
12340c16b537SWarner Losh             if (normalizedCounter[s] >= largeLimit) noLarge=0;
12350c16b537SWarner Losh             symbolNext[s] = normalizedCounter[s];
12360c16b537SWarner Losh     }   }
12370c16b537SWarner Losh 
12380c16b537SWarner Losh     /* Spread symbols */
12390c16b537SWarner Losh     for (s=0; s<=maxSymbolValue; s++) {
12400c16b537SWarner Losh         int i;
12410c16b537SWarner Losh         for (i=0; i<normalizedCounter[s]; i++) {
12420c16b537SWarner Losh             tableDecode[position].symbol = (FSEv05_FUNCTION_TYPE)s;
12430c16b537SWarner Losh             position = (position + step) & tableMask;
12440c16b537SWarner Losh             while (position > highThreshold) position = (position + step) & tableMask;   /* lowprob area */
12450c16b537SWarner Losh     }   }
12460c16b537SWarner Losh 
12470c16b537SWarner Losh     if (position!=0) return ERROR(GENERIC);   /* position must reach all cells once, otherwise normalizedCounter is incorrect */
12480c16b537SWarner Losh 
12490c16b537SWarner Losh     /* Build Decoding table */
12500c16b537SWarner Losh     {
12510c16b537SWarner Losh         U32 i;
12520c16b537SWarner Losh         for (i=0; i<tableSize; i++) {
12530c16b537SWarner Losh             FSEv05_FUNCTION_TYPE symbol = (FSEv05_FUNCTION_TYPE)(tableDecode[i].symbol);
12540c16b537SWarner Losh             U16 nextState = symbolNext[symbol]++;
12550c16b537SWarner Losh             tableDecode[i].nbBits = (BYTE) (tableLog - BITv05_highbit32 ((U32)nextState) );
12560c16b537SWarner Losh             tableDecode[i].newState = (U16) ( (nextState << tableDecode[i].nbBits) - tableSize);
12570c16b537SWarner Losh     }   }
12580c16b537SWarner Losh 
12590c16b537SWarner Losh     DTableH.fastMode = (U16)noLarge;
12600c16b537SWarner Losh     memcpy(dt, &DTableH, sizeof(DTableH));
12610c16b537SWarner Losh     return 0;
12620c16b537SWarner Losh }
12630c16b537SWarner Losh 
12640c16b537SWarner Losh 
12650c16b537SWarner Losh #ifndef FSEv05_COMMONDEFS_ONLY
12660c16b537SWarner Losh /*-****************************************
12670c16b537SWarner Losh *  FSEv05 helper functions
12680c16b537SWarner Losh ******************************************/
12690c16b537SWarner Losh unsigned FSEv05_isError(size_t code) { return ERR_isError(code); }
12700c16b537SWarner Losh 
12710c16b537SWarner Losh const char* FSEv05_getErrorName(size_t code) { return ERR_getErrorName(code); }
12720c16b537SWarner Losh 
12730c16b537SWarner Losh 
12740c16b537SWarner Losh /*-**************************************************************
12750c16b537SWarner Losh *  FSEv05 NCount encoding-decoding
12760c16b537SWarner Losh ****************************************************************/
12770c16b537SWarner Losh static short FSEv05_abs(short a) { return a<0 ? -a : a; }
12780c16b537SWarner Losh 
12790c16b537SWarner Losh 
12800c16b537SWarner Losh size_t FSEv05_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
12810c16b537SWarner Losh                  const void* headerBuffer, size_t hbSize)
12820c16b537SWarner Losh {
12830c16b537SWarner Losh     const BYTE* const istart = (const BYTE*) headerBuffer;
12840c16b537SWarner Losh     const BYTE* const iend = istart + hbSize;
12850c16b537SWarner Losh     const BYTE* ip = istart;
12860c16b537SWarner Losh     int nbBits;
12870c16b537SWarner Losh     int remaining;
12880c16b537SWarner Losh     int threshold;
12890c16b537SWarner Losh     U32 bitStream;
12900c16b537SWarner Losh     int bitCount;
12910c16b537SWarner Losh     unsigned charnum = 0;
12920c16b537SWarner Losh     int previous0 = 0;
12930c16b537SWarner Losh 
12940c16b537SWarner Losh     if (hbSize < 4) return ERROR(srcSize_wrong);
12950c16b537SWarner Losh     bitStream = MEM_readLE32(ip);
12960c16b537SWarner Losh     nbBits = (bitStream & 0xF) + FSEv05_MIN_TABLELOG;   /* extract tableLog */
12970c16b537SWarner Losh     if (nbBits > FSEv05_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge);
12980c16b537SWarner Losh     bitStream >>= 4;
12990c16b537SWarner Losh     bitCount = 4;
13000c16b537SWarner Losh     *tableLogPtr = nbBits;
13010c16b537SWarner Losh     remaining = (1<<nbBits)+1;
13020c16b537SWarner Losh     threshold = 1<<nbBits;
13030c16b537SWarner Losh     nbBits++;
13040c16b537SWarner Losh 
13050c16b537SWarner Losh     while ((remaining>1) && (charnum<=*maxSVPtr)) {
13060c16b537SWarner Losh         if (previous0) {
13070c16b537SWarner Losh             unsigned n0 = charnum;
13080c16b537SWarner Losh             while ((bitStream & 0xFFFF) == 0xFFFF) {
13090c16b537SWarner Losh                 n0+=24;
13100c16b537SWarner Losh                 if (ip < iend-5) {
13110c16b537SWarner Losh                     ip+=2;
13120c16b537SWarner Losh                     bitStream = MEM_readLE32(ip) >> bitCount;
13130c16b537SWarner Losh                 } else {
13140c16b537SWarner Losh                     bitStream >>= 16;
13150c16b537SWarner Losh                     bitCount+=16;
13160c16b537SWarner Losh             }   }
13170c16b537SWarner Losh             while ((bitStream & 3) == 3) {
13180c16b537SWarner Losh                 n0+=3;
13190c16b537SWarner Losh                 bitStream>>=2;
13200c16b537SWarner Losh                 bitCount+=2;
13210c16b537SWarner Losh             }
13220c16b537SWarner Losh             n0 += bitStream & 3;
13230c16b537SWarner Losh             bitCount += 2;
13240c16b537SWarner Losh             if (n0 > *maxSVPtr) return ERROR(maxSymbolValue_tooSmall);
13250c16b537SWarner Losh             while (charnum < n0) normalizedCounter[charnum++] = 0;
13260c16b537SWarner Losh             if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
13270c16b537SWarner Losh                 ip += bitCount>>3;
13280c16b537SWarner Losh                 bitCount &= 7;
13290c16b537SWarner Losh                 bitStream = MEM_readLE32(ip) >> bitCount;
13300c16b537SWarner Losh             }
13310c16b537SWarner Losh             else
13320c16b537SWarner Losh                 bitStream >>= 2;
13330c16b537SWarner Losh         }
13340c16b537SWarner Losh         {
13350c16b537SWarner Losh             const short max = (short)((2*threshold-1)-remaining);
13360c16b537SWarner Losh             short count;
13370c16b537SWarner Losh 
13380c16b537SWarner Losh             if ((bitStream & (threshold-1)) < (U32)max) {
13390c16b537SWarner Losh                 count = (short)(bitStream & (threshold-1));
13400c16b537SWarner Losh                 bitCount   += nbBits-1;
13410c16b537SWarner Losh             } else {
13420c16b537SWarner Losh                 count = (short)(bitStream & (2*threshold-1));
13430c16b537SWarner Losh                 if (count >= threshold) count -= max;
13440c16b537SWarner Losh                 bitCount   += nbBits;
13450c16b537SWarner Losh             }
13460c16b537SWarner Losh 
13470c16b537SWarner Losh             count--;   /* extra accuracy */
13480c16b537SWarner Losh             remaining -= FSEv05_abs(count);
13490c16b537SWarner Losh             normalizedCounter[charnum++] = count;
13500c16b537SWarner Losh             previous0 = !count;
13510c16b537SWarner Losh             while (remaining < threshold) {
13520c16b537SWarner Losh                 nbBits--;
13530c16b537SWarner Losh                 threshold >>= 1;
13540c16b537SWarner Losh             }
13550c16b537SWarner Losh 
13560c16b537SWarner Losh             if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
13570c16b537SWarner Losh                 ip += bitCount>>3;
13580c16b537SWarner Losh                 bitCount &= 7;
13590c16b537SWarner Losh             } else {
13600c16b537SWarner Losh                 bitCount -= (int)(8 * (iend - 4 - ip));
13610c16b537SWarner Losh                 ip = iend - 4;
13620c16b537SWarner Losh             }
13630c16b537SWarner Losh             bitStream = MEM_readLE32(ip) >> (bitCount & 31);
13640c16b537SWarner Losh     }   }
13650c16b537SWarner Losh     if (remaining != 1) return ERROR(GENERIC);
13660c16b537SWarner Losh     *maxSVPtr = charnum-1;
13670c16b537SWarner Losh 
13680c16b537SWarner Losh     ip += (bitCount+7)>>3;
13690c16b537SWarner Losh     if ((size_t)(ip-istart) > hbSize) return ERROR(srcSize_wrong);
13700c16b537SWarner Losh     return ip-istart;
13710c16b537SWarner Losh }
13720c16b537SWarner Losh 
13730c16b537SWarner Losh 
13740c16b537SWarner Losh 
13750c16b537SWarner Losh /*-*******************************************************
13760c16b537SWarner Losh *  Decompression (Byte symbols)
13770c16b537SWarner Losh *********************************************************/
13780c16b537SWarner Losh size_t FSEv05_buildDTable_rle (FSEv05_DTable* dt, BYTE symbolValue)
13790c16b537SWarner Losh {
13800c16b537SWarner Losh     void* ptr = dt;
13810c16b537SWarner Losh     FSEv05_DTableHeader* const DTableH = (FSEv05_DTableHeader*)ptr;
13820c16b537SWarner Losh     void* dPtr = dt + 1;
13830c16b537SWarner Losh     FSEv05_decode_t* const cell = (FSEv05_decode_t*)dPtr;
13840c16b537SWarner Losh 
13850c16b537SWarner Losh     DTableH->tableLog = 0;
13860c16b537SWarner Losh     DTableH->fastMode = 0;
13870c16b537SWarner Losh 
13880c16b537SWarner Losh     cell->newState = 0;
13890c16b537SWarner Losh     cell->symbol = symbolValue;
13900c16b537SWarner Losh     cell->nbBits = 0;
13910c16b537SWarner Losh 
13920c16b537SWarner Losh     return 0;
13930c16b537SWarner Losh }
13940c16b537SWarner Losh 
13950c16b537SWarner Losh 
13960c16b537SWarner Losh size_t FSEv05_buildDTable_raw (FSEv05_DTable* dt, unsigned nbBits)
13970c16b537SWarner Losh {
13980c16b537SWarner Losh     void* ptr = dt;
13990c16b537SWarner Losh     FSEv05_DTableHeader* const DTableH = (FSEv05_DTableHeader*)ptr;
14000c16b537SWarner Losh     void* dPtr = dt + 1;
14010c16b537SWarner Losh     FSEv05_decode_t* const dinfo = (FSEv05_decode_t*)dPtr;
14020c16b537SWarner Losh     const unsigned tableSize = 1 << nbBits;
14030c16b537SWarner Losh     const unsigned tableMask = tableSize - 1;
14040c16b537SWarner Losh     const unsigned maxSymbolValue = tableMask;
14050c16b537SWarner Losh     unsigned s;
14060c16b537SWarner Losh 
14070c16b537SWarner Losh     /* Sanity checks */
14080c16b537SWarner Losh     if (nbBits < 1) return ERROR(GENERIC);         /* min size */
14090c16b537SWarner Losh 
14100c16b537SWarner Losh     /* Build Decoding Table */
14110c16b537SWarner Losh     DTableH->tableLog = (U16)nbBits;
14120c16b537SWarner Losh     DTableH->fastMode = 1;
14130c16b537SWarner Losh     for (s=0; s<=maxSymbolValue; s++) {
14140c16b537SWarner Losh         dinfo[s].newState = 0;
14150c16b537SWarner Losh         dinfo[s].symbol = (BYTE)s;
14160c16b537SWarner Losh         dinfo[s].nbBits = (BYTE)nbBits;
14170c16b537SWarner Losh     }
14180c16b537SWarner Losh 
14190c16b537SWarner Losh     return 0;
14200c16b537SWarner Losh }
14210c16b537SWarner Losh 
14220c16b537SWarner Losh FORCE_INLINE size_t FSEv05_decompress_usingDTable_generic(
14230c16b537SWarner Losh           void* dst, size_t maxDstSize,
14240c16b537SWarner Losh     const void* cSrc, size_t cSrcSize,
14250c16b537SWarner Losh     const FSEv05_DTable* dt, const unsigned fast)
14260c16b537SWarner Losh {
14270c16b537SWarner Losh     BYTE* const ostart = (BYTE*) dst;
14280c16b537SWarner Losh     BYTE* op = ostart;
14290c16b537SWarner Losh     BYTE* const omax = op + maxDstSize;
14300c16b537SWarner Losh     BYTE* const olimit = omax-3;
14310c16b537SWarner Losh 
14320c16b537SWarner Losh     BITv05_DStream_t bitD;
14330c16b537SWarner Losh     FSEv05_DState_t state1;
14340c16b537SWarner Losh     FSEv05_DState_t state2;
14350c16b537SWarner Losh     size_t errorCode;
14360c16b537SWarner Losh 
14370c16b537SWarner Losh     /* Init */
14380c16b537SWarner Losh     errorCode = BITv05_initDStream(&bitD, cSrc, cSrcSize);   /* replaced last arg by maxCompressed Size */
14390c16b537SWarner Losh     if (FSEv05_isError(errorCode)) return errorCode;
14400c16b537SWarner Losh 
14410c16b537SWarner Losh     FSEv05_initDState(&state1, &bitD, dt);
14420c16b537SWarner Losh     FSEv05_initDState(&state2, &bitD, dt);
14430c16b537SWarner Losh 
14440c16b537SWarner Losh #define FSEv05_GETSYMBOL(statePtr) fast ? FSEv05_decodeSymbolFast(statePtr, &bitD) : FSEv05_decodeSymbol(statePtr, &bitD)
14450c16b537SWarner Losh 
14460c16b537SWarner Losh     /* 4 symbols per loop */
14470c16b537SWarner Losh     for ( ; (BITv05_reloadDStream(&bitD)==BITv05_DStream_unfinished) && (op<olimit) ; op+=4) {
14480c16b537SWarner Losh         op[0] = FSEv05_GETSYMBOL(&state1);
14490c16b537SWarner Losh 
14500c16b537SWarner Losh         if (FSEv05_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8)    /* This test must be static */
14510c16b537SWarner Losh             BITv05_reloadDStream(&bitD);
14520c16b537SWarner Losh 
14530c16b537SWarner Losh         op[1] = FSEv05_GETSYMBOL(&state2);
14540c16b537SWarner Losh 
14550c16b537SWarner Losh         if (FSEv05_MAX_TABLELOG*4+7 > sizeof(bitD.bitContainer)*8)    /* This test must be static */
14560c16b537SWarner Losh             { if (BITv05_reloadDStream(&bitD) > BITv05_DStream_unfinished) { op+=2; break; } }
14570c16b537SWarner Losh 
14580c16b537SWarner Losh         op[2] = FSEv05_GETSYMBOL(&state1);
14590c16b537SWarner Losh 
14600c16b537SWarner Losh         if (FSEv05_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8)    /* This test must be static */
14610c16b537SWarner Losh             BITv05_reloadDStream(&bitD);
14620c16b537SWarner Losh 
14630c16b537SWarner Losh         op[3] = FSEv05_GETSYMBOL(&state2);
14640c16b537SWarner Losh     }
14650c16b537SWarner Losh 
14660c16b537SWarner Losh     /* tail */
14670c16b537SWarner Losh     /* note : BITv05_reloadDStream(&bitD) >= FSEv05_DStream_partiallyFilled; Ends at exactly BITv05_DStream_completed */
14680c16b537SWarner Losh     while (1) {
14690c16b537SWarner Losh         if ( (BITv05_reloadDStream(&bitD)>BITv05_DStream_completed) || (op==omax) || (BITv05_endOfDStream(&bitD) && (fast || FSEv05_endOfDState(&state1))) )
14700c16b537SWarner Losh             break;
14710c16b537SWarner Losh 
14720c16b537SWarner Losh         *op++ = FSEv05_GETSYMBOL(&state1);
14730c16b537SWarner Losh 
14740c16b537SWarner Losh         if ( (BITv05_reloadDStream(&bitD)>BITv05_DStream_completed) || (op==omax) || (BITv05_endOfDStream(&bitD) && (fast || FSEv05_endOfDState(&state2))) )
14750c16b537SWarner Losh             break;
14760c16b537SWarner Losh 
14770c16b537SWarner Losh         *op++ = FSEv05_GETSYMBOL(&state2);
14780c16b537SWarner Losh     }
14790c16b537SWarner Losh 
14800c16b537SWarner Losh     /* end ? */
14810c16b537SWarner Losh     if (BITv05_endOfDStream(&bitD) && FSEv05_endOfDState(&state1) && FSEv05_endOfDState(&state2))
14820c16b537SWarner Losh         return op-ostart;
14830c16b537SWarner Losh 
14840c16b537SWarner Losh     if (op==omax) return ERROR(dstSize_tooSmall);   /* dst buffer is full, but cSrc unfinished */
14850c16b537SWarner Losh 
14860c16b537SWarner Losh     return ERROR(corruption_detected);
14870c16b537SWarner Losh }
14880c16b537SWarner Losh 
14890c16b537SWarner Losh 
14900c16b537SWarner Losh size_t FSEv05_decompress_usingDTable(void* dst, size_t originalSize,
14910c16b537SWarner Losh                             const void* cSrc, size_t cSrcSize,
14920c16b537SWarner Losh                             const FSEv05_DTable* dt)
14930c16b537SWarner Losh {
14940c16b537SWarner Losh     const void* ptr = dt;
14950c16b537SWarner Losh     const FSEv05_DTableHeader* DTableH = (const FSEv05_DTableHeader*)ptr;
14960c16b537SWarner Losh     const U32 fastMode = DTableH->fastMode;
14970c16b537SWarner Losh 
14980c16b537SWarner Losh     /* select fast mode (static) */
14990c16b537SWarner Losh     if (fastMode) return FSEv05_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 1);
15000c16b537SWarner Losh     return FSEv05_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 0);
15010c16b537SWarner Losh }
15020c16b537SWarner Losh 
15030c16b537SWarner Losh 
15040c16b537SWarner Losh size_t FSEv05_decompress(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize)
15050c16b537SWarner Losh {
15060c16b537SWarner Losh     const BYTE* const istart = (const BYTE*)cSrc;
15070c16b537SWarner Losh     const BYTE* ip = istart;
15080c16b537SWarner Losh     short counting[FSEv05_MAX_SYMBOL_VALUE+1];
15090c16b537SWarner Losh     DTable_max_t dt;   /* Static analyzer seems unable to understand this table will be properly initialized later */
15100c16b537SWarner Losh     unsigned tableLog;
15110c16b537SWarner Losh     unsigned maxSymbolValue = FSEv05_MAX_SYMBOL_VALUE;
15120c16b537SWarner Losh     size_t errorCode;
15130c16b537SWarner Losh 
15140c16b537SWarner Losh     if (cSrcSize<2) return ERROR(srcSize_wrong);   /* too small input size */
15150c16b537SWarner Losh 
15160c16b537SWarner Losh     /* normal FSEv05 decoding mode */
15170c16b537SWarner Losh     errorCode = FSEv05_readNCount (counting, &maxSymbolValue, &tableLog, istart, cSrcSize);
15180c16b537SWarner Losh     if (FSEv05_isError(errorCode)) return errorCode;
15190c16b537SWarner Losh     if (errorCode >= cSrcSize) return ERROR(srcSize_wrong);   /* too small input size */
15200c16b537SWarner Losh     ip += errorCode;
15210c16b537SWarner Losh     cSrcSize -= errorCode;
15220c16b537SWarner Losh 
15230c16b537SWarner Losh     errorCode = FSEv05_buildDTable (dt, counting, maxSymbolValue, tableLog);
15240c16b537SWarner Losh     if (FSEv05_isError(errorCode)) return errorCode;
15250c16b537SWarner Losh 
15260c16b537SWarner Losh     /* always return, even if it is an error code */
15270c16b537SWarner Losh     return FSEv05_decompress_usingDTable (dst, maxDstSize, ip, cSrcSize, dt);
15280c16b537SWarner Losh }
15290c16b537SWarner Losh 
15300c16b537SWarner Losh 
15310c16b537SWarner Losh 
15320c16b537SWarner Losh #endif   /* FSEv05_COMMONDEFS_ONLY */
15330c16b537SWarner Losh /* ******************************************************************
15340c16b537SWarner Losh    Huff0 : Huffman coder, part of New Generation Entropy library
15350c16b537SWarner Losh    header file
15360c16b537SWarner Losh    Copyright (C) 2013-2016, Yann Collet.
15370c16b537SWarner Losh 
15380c16b537SWarner Losh    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
15390c16b537SWarner Losh 
15400c16b537SWarner Losh    Redistribution and use in source and binary forms, with or without
15410c16b537SWarner Losh    modification, are permitted provided that the following conditions are
15420c16b537SWarner Losh    met:
15430c16b537SWarner Losh 
15440c16b537SWarner Losh        * Redistributions of source code must retain the above copyright
15450c16b537SWarner Losh    notice, this list of conditions and the following disclaimer.
15460c16b537SWarner Losh        * Redistributions in binary form must reproduce the above
15470c16b537SWarner Losh    copyright notice, this list of conditions and the following disclaimer
15480c16b537SWarner Losh    in the documentation and/or other materials provided with the
15490c16b537SWarner Losh    distribution.
15500c16b537SWarner Losh 
15510c16b537SWarner Losh    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15520c16b537SWarner Losh    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
15530c16b537SWarner Losh    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
15540c16b537SWarner Losh    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
15550c16b537SWarner Losh    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
15560c16b537SWarner Losh    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
15570c16b537SWarner Losh    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
15580c16b537SWarner Losh    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
15590c16b537SWarner Losh    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
15600c16b537SWarner Losh    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
15610c16b537SWarner Losh    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15620c16b537SWarner Losh 
15630c16b537SWarner Losh    You can contact the author at :
15640c16b537SWarner Losh    - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
15650c16b537SWarner Losh ****************************************************************** */
15660c16b537SWarner Losh #ifndef HUFF0_H
15670c16b537SWarner Losh #define HUFF0_H
15680c16b537SWarner Losh 
15690c16b537SWarner Losh #if defined (__cplusplus)
15700c16b537SWarner Losh extern "C" {
15710c16b537SWarner Losh #endif
15720c16b537SWarner Losh 
15730c16b537SWarner Losh 
15740c16b537SWarner Losh 
15750c16b537SWarner Losh /* ****************************************
15760c16b537SWarner Losh *  Huff0 simple functions
15770c16b537SWarner Losh ******************************************/
15780c16b537SWarner Losh size_t HUFv05_decompress(void* dst,  size_t dstSize,
15790c16b537SWarner Losh                 const void* cSrc, size_t cSrcSize);
15800c16b537SWarner Losh /*!
15810c16b537SWarner Losh HUFv05_decompress():
15820c16b537SWarner Losh     Decompress Huff0 data from buffer 'cSrc', of size 'cSrcSize',
15830c16b537SWarner Losh     into already allocated destination buffer 'dst', of size 'dstSize'.
15840c16b537SWarner Losh     @dstSize : must be the **exact** size of original (uncompressed) data.
15850c16b537SWarner Losh     Note : in contrast with FSEv05, HUFv05_decompress can regenerate
15860c16b537SWarner Losh            RLE (cSrcSize==1) and uncompressed (cSrcSize==dstSize) data,
15870c16b537SWarner Losh            because it knows size to regenerate.
15880c16b537SWarner Losh     @return : size of regenerated data (== dstSize)
15890c16b537SWarner Losh               or an error code, which can be tested using HUFv05_isError()
15900c16b537SWarner Losh */
15910c16b537SWarner Losh 
15920c16b537SWarner Losh 
15930c16b537SWarner Losh /* ****************************************
15940c16b537SWarner Losh *  Tool functions
15950c16b537SWarner Losh ******************************************/
15960c16b537SWarner Losh /* Error Management */
15970c16b537SWarner Losh unsigned    HUFv05_isError(size_t code);        /* tells if a return value is an error code */
15980c16b537SWarner Losh const char* HUFv05_getErrorName(size_t code);   /* provides error code string (useful for debugging) */
15990c16b537SWarner Losh 
16000c16b537SWarner Losh 
16010c16b537SWarner Losh #if defined (__cplusplus)
16020c16b537SWarner Losh }
16030c16b537SWarner Losh #endif
16040c16b537SWarner Losh 
16050c16b537SWarner Losh #endif   /* HUF0_H */
16060c16b537SWarner Losh /* ******************************************************************
16070c16b537SWarner Losh    Huff0 : Huffman codec, part of New Generation Entropy library
16080c16b537SWarner Losh    header file, for static linking only
16090c16b537SWarner Losh    Copyright (C) 2013-2016, Yann Collet
16100c16b537SWarner Losh 
16110c16b537SWarner Losh    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
16120c16b537SWarner Losh 
16130c16b537SWarner Losh    Redistribution and use in source and binary forms, with or without
16140c16b537SWarner Losh    modification, are permitted provided that the following conditions are
16150c16b537SWarner Losh    met:
16160c16b537SWarner Losh 
16170c16b537SWarner Losh        * Redistributions of source code must retain the above copyright
16180c16b537SWarner Losh    notice, this list of conditions and the following disclaimer.
16190c16b537SWarner Losh        * Redistributions in binary form must reproduce the above
16200c16b537SWarner Losh    copyright notice, this list of conditions and the following disclaimer
16210c16b537SWarner Losh    in the documentation and/or other materials provided with the
16220c16b537SWarner Losh    distribution.
16230c16b537SWarner Losh 
16240c16b537SWarner Losh    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16250c16b537SWarner Losh    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16260c16b537SWarner Losh    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
16270c16b537SWarner Losh    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
16280c16b537SWarner Losh    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
16290c16b537SWarner Losh    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
16300c16b537SWarner Losh    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
16310c16b537SWarner Losh    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
16320c16b537SWarner Losh    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
16330c16b537SWarner Losh    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
16340c16b537SWarner Losh    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16350c16b537SWarner Losh 
16360c16b537SWarner Losh    You can contact the author at :
16370c16b537SWarner Losh    - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
16380c16b537SWarner Losh ****************************************************************** */
16390c16b537SWarner Losh #ifndef HUF0_STATIC_H
16400c16b537SWarner Losh #define HUF0_STATIC_H
16410c16b537SWarner Losh 
16420c16b537SWarner Losh #if defined (__cplusplus)
16430c16b537SWarner Losh extern "C" {
16440c16b537SWarner Losh #endif
16450c16b537SWarner Losh 
16460c16b537SWarner Losh 
16470c16b537SWarner Losh 
16480c16b537SWarner Losh /* ****************************************
16490c16b537SWarner Losh *  Static allocation
16500c16b537SWarner Losh ******************************************/
16510c16b537SWarner Losh /* static allocation of Huff0's DTable */
16520c16b537SWarner Losh #define HUFv05_DTABLE_SIZE(maxTableLog)   (1 + (1<<maxTableLog))
16530c16b537SWarner Losh #define HUFv05_CREATE_STATIC_DTABLEX2(DTable, maxTableLog) \
16540c16b537SWarner Losh         unsigned short DTable[HUFv05_DTABLE_SIZE(maxTableLog)] = { maxTableLog }
16550c16b537SWarner Losh #define HUFv05_CREATE_STATIC_DTABLEX4(DTable, maxTableLog) \
16560c16b537SWarner Losh         unsigned int DTable[HUFv05_DTABLE_SIZE(maxTableLog)] = { maxTableLog }
16570c16b537SWarner Losh #define HUFv05_CREATE_STATIC_DTABLEX6(DTable, maxTableLog) \
16580c16b537SWarner Losh         unsigned int DTable[HUFv05_DTABLE_SIZE(maxTableLog) * 3 / 2] = { maxTableLog }
16590c16b537SWarner Losh 
16600c16b537SWarner Losh 
16610c16b537SWarner Losh /* ****************************************
16620c16b537SWarner Losh *  Advanced decompression functions
16630c16b537SWarner Losh ******************************************/
16640c16b537SWarner Losh size_t HUFv05_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /* single-symbol decoder */
16650c16b537SWarner Losh size_t HUFv05_decompress4X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /* double-symbols decoder */
16660c16b537SWarner Losh 
16670c16b537SWarner Losh 
16680c16b537SWarner Losh /* ****************************************
16690c16b537SWarner Losh *  Huff0 detailed API
16700c16b537SWarner Losh ******************************************/
16710c16b537SWarner Losh /*!
16720c16b537SWarner Losh HUFv05_decompress() does the following:
16730c16b537SWarner Losh 1. select the decompression algorithm (X2, X4, X6) based on pre-computed heuristics
16740c16b537SWarner Losh 2. build Huffman table from save, using HUFv05_readDTableXn()
16750c16b537SWarner Losh 3. decode 1 or 4 segments in parallel using HUFv05_decompressSXn_usingDTable
16760c16b537SWarner Losh */
16770c16b537SWarner Losh size_t HUFv05_readDTableX2 (unsigned short* DTable, const void* src, size_t srcSize);
16780c16b537SWarner Losh size_t HUFv05_readDTableX4 (unsigned* DTable, const void* src, size_t srcSize);
16790c16b537SWarner Losh 
16800c16b537SWarner Losh size_t HUFv05_decompress4X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const unsigned short* DTable);
16810c16b537SWarner Losh size_t HUFv05_decompress4X4_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const unsigned* DTable);
16820c16b537SWarner Losh 
16830c16b537SWarner Losh 
16840c16b537SWarner Losh /* single stream variants */
16850c16b537SWarner Losh 
16860c16b537SWarner Losh size_t HUFv05_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /* single-symbol decoder */
16870c16b537SWarner Losh size_t HUFv05_decompress1X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /* double-symbol decoder */
16880c16b537SWarner Losh 
16890c16b537SWarner Losh size_t HUFv05_decompress1X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const unsigned short* DTable);
16900c16b537SWarner Losh size_t HUFv05_decompress1X4_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const unsigned* DTable);
16910c16b537SWarner Losh 
16920c16b537SWarner Losh 
16930c16b537SWarner Losh 
16940c16b537SWarner Losh #if defined (__cplusplus)
16950c16b537SWarner Losh }
16960c16b537SWarner Losh #endif
16970c16b537SWarner Losh 
16980c16b537SWarner Losh #endif /* HUF0_STATIC_H */
16990c16b537SWarner Losh /* ******************************************************************
17000c16b537SWarner Losh    Huff0 : Huffman coder, part of New Generation Entropy library
17010c16b537SWarner Losh    Copyright (C) 2013-2015, Yann Collet.
17020c16b537SWarner Losh 
17030c16b537SWarner Losh    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
17040c16b537SWarner Losh 
17050c16b537SWarner Losh    Redistribution and use in source and binary forms, with or without
17060c16b537SWarner Losh    modification, are permitted provided that the following conditions are
17070c16b537SWarner Losh    met:
17080c16b537SWarner Losh 
17090c16b537SWarner Losh        * Redistributions of source code must retain the above copyright
17100c16b537SWarner Losh    notice, this list of conditions and the following disclaimer.
17110c16b537SWarner Losh        * Redistributions in binary form must reproduce the above
17120c16b537SWarner Losh    copyright notice, this list of conditions and the following disclaimer
17130c16b537SWarner Losh    in the documentation and/or other materials provided with the
17140c16b537SWarner Losh    distribution.
17150c16b537SWarner Losh 
17160c16b537SWarner Losh    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17170c16b537SWarner Losh    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17180c16b537SWarner Losh    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17190c16b537SWarner Losh    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
17200c16b537SWarner Losh    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
17210c16b537SWarner Losh    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
17220c16b537SWarner Losh    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
17230c16b537SWarner Losh    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
17240c16b537SWarner Losh    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
17250c16b537SWarner Losh    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
17260c16b537SWarner Losh    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17270c16b537SWarner Losh 
17280c16b537SWarner Losh     You can contact the author at :
17290c16b537SWarner Losh     - FSEv05+Huff0 source repository : https://github.com/Cyan4973/FiniteStateEntropy
17300c16b537SWarner Losh     - Public forum : https://groups.google.com/forum/#!forum/lz4c
17310c16b537SWarner Losh ****************************************************************** */
17320c16b537SWarner Losh 
17330c16b537SWarner Losh /* **************************************************************
17340c16b537SWarner Losh *  Compiler specifics
17350c16b537SWarner Losh ****************************************************************/
17360c16b537SWarner Losh #if defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
17370c16b537SWarner Losh /* inline is defined */
17380c16b537SWarner Losh #elif defined(_MSC_VER)
17390c16b537SWarner Losh #  define inline __inline
17400c16b537SWarner Losh #else
17410c16b537SWarner Losh #  define inline /* disable inline */
17420c16b537SWarner Losh #endif
17430c16b537SWarner Losh 
17440c16b537SWarner Losh 
17450c16b537SWarner Losh #ifdef _MSC_VER    /* Visual Studio */
17460c16b537SWarner Losh #  pragma warning(disable : 4127)        /* disable: C4127: conditional expression is constant */
17470c16b537SWarner Losh #endif
17480c16b537SWarner Losh 
17490c16b537SWarner Losh 
17500c16b537SWarner Losh /* **************************************************************
17510c16b537SWarner Losh *  Includes
17520c16b537SWarner Losh ****************************************************************/
17530c16b537SWarner Losh #include <stdlib.h>     /* malloc, free, qsort */
17540c16b537SWarner Losh #include <string.h>     /* memcpy, memset */
17550c16b537SWarner Losh #include <stdio.h>      /* printf (debug) */
17560c16b537SWarner Losh 
17570c16b537SWarner Losh 
17580c16b537SWarner Losh /* **************************************************************
17590c16b537SWarner Losh *  Constants
17600c16b537SWarner Losh ****************************************************************/
17610c16b537SWarner Losh #define HUFv05_ABSOLUTEMAX_TABLELOG  16   /* absolute limit of HUFv05_MAX_TABLELOG. Beyond that value, code does not work */
17620c16b537SWarner Losh #define HUFv05_MAX_TABLELOG  12           /* max configured tableLog (for static allocation); can be modified up to HUFv05_ABSOLUTEMAX_TABLELOG */
17630c16b537SWarner Losh #define HUFv05_DEFAULT_TABLELOG  HUFv05_MAX_TABLELOG   /* tableLog by default, when not specified */
17640c16b537SWarner Losh #define HUFv05_MAX_SYMBOL_VALUE 255
17650c16b537SWarner Losh #if (HUFv05_MAX_TABLELOG > HUFv05_ABSOLUTEMAX_TABLELOG)
17660c16b537SWarner Losh #  error "HUFv05_MAX_TABLELOG is too large !"
17670c16b537SWarner Losh #endif
17680c16b537SWarner Losh 
17690c16b537SWarner Losh 
17700c16b537SWarner Losh /* **************************************************************
17710c16b537SWarner Losh *  Error Management
17720c16b537SWarner Losh ****************************************************************/
17730c16b537SWarner Losh unsigned HUFv05_isError(size_t code) { return ERR_isError(code); }
17740c16b537SWarner Losh const char* HUFv05_getErrorName(size_t code) { return ERR_getErrorName(code); }
17750c16b537SWarner Losh #define HUFv05_STATIC_ASSERT(c) { enum { HUFv05_static_assert = 1/(int)(!!(c)) }; }   /* use only *after* variable declarations */
17760c16b537SWarner Losh 
17770c16b537SWarner Losh 
17780c16b537SWarner Losh /* *******************************************************
17790c16b537SWarner Losh *  Huff0 : Huffman block decompression
17800c16b537SWarner Losh *********************************************************/
17810c16b537SWarner Losh typedef struct { BYTE byte; BYTE nbBits; } HUFv05_DEltX2;   /* single-symbol decoding */
17820c16b537SWarner Losh 
17830c16b537SWarner Losh typedef struct { U16 sequence; BYTE nbBits; BYTE length; } HUFv05_DEltX4;  /* double-symbols decoding */
17840c16b537SWarner Losh 
17850c16b537SWarner Losh typedef struct { BYTE symbol; BYTE weight; } sortedSymbol_t;
17860c16b537SWarner Losh 
17870c16b537SWarner Losh /*! HUFv05_readStats
17880c16b537SWarner Losh     Read compact Huffman tree, saved by HUFv05_writeCTable
17890c16b537SWarner Losh     @huffWeight : destination buffer
17900c16b537SWarner Losh     @return : size read from `src`
17910c16b537SWarner Losh */
17920c16b537SWarner Losh static size_t HUFv05_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats,
17930c16b537SWarner Losh                             U32* nbSymbolsPtr, U32* tableLogPtr,
17940c16b537SWarner Losh                             const void* src, size_t srcSize)
17950c16b537SWarner Losh {
17960c16b537SWarner Losh     U32 weightTotal;
17970c16b537SWarner Losh     U32 tableLog;
17980c16b537SWarner Losh     const BYTE* ip = (const BYTE*) src;
17990c16b537SWarner Losh     size_t iSize;
18000c16b537SWarner Losh     size_t oSize;
18010c16b537SWarner Losh     U32 n;
18020c16b537SWarner Losh 
18030c16b537SWarner Losh     if (!srcSize) return ERROR(srcSize_wrong);
18040c16b537SWarner Losh     iSize = ip[0];
18050c16b537SWarner Losh     //memset(huffWeight, 0, hwSize);   /* is not necessary, even though some analyzer complain ... */
18060c16b537SWarner Losh 
18070c16b537SWarner Losh     if (iSize >= 128)  { /* special header */
18080c16b537SWarner Losh         if (iSize >= (242)) {  /* RLE */
18090c16b537SWarner Losh             static int l[14] = { 1, 2, 3, 4, 7, 8, 15, 16, 31, 32, 63, 64, 127, 128 };
18100c16b537SWarner Losh             oSize = l[iSize-242];
18110c16b537SWarner Losh             memset(huffWeight, 1, hwSize);
18120c16b537SWarner Losh             iSize = 0;
18130c16b537SWarner Losh         }
18140c16b537SWarner Losh         else {   /* Incompressible */
18150c16b537SWarner Losh             oSize = iSize - 127;
18160c16b537SWarner Losh             iSize = ((oSize+1)/2);
18170c16b537SWarner Losh             if (iSize+1 > srcSize) return ERROR(srcSize_wrong);
18180c16b537SWarner Losh             if (oSize >= hwSize) return ERROR(corruption_detected);
18190c16b537SWarner Losh             ip += 1;
18200c16b537SWarner Losh             for (n=0; n<oSize; n+=2) {
18210c16b537SWarner Losh                 huffWeight[n]   = ip[n/2] >> 4;
18220c16b537SWarner Losh                 huffWeight[n+1] = ip[n/2] & 15;
18230c16b537SWarner Losh     }   }   }
18240c16b537SWarner Losh     else  {   /* header compressed with FSEv05 (normal case) */
18250c16b537SWarner Losh         if (iSize+1 > srcSize) return ERROR(srcSize_wrong);
18260c16b537SWarner Losh         oSize = FSEv05_decompress(huffWeight, hwSize-1, ip+1, iSize);   /* max (hwSize-1) values decoded, as last one is implied */
18270c16b537SWarner Losh         if (FSEv05_isError(oSize)) return oSize;
18280c16b537SWarner Losh     }
18290c16b537SWarner Losh 
18300c16b537SWarner Losh     /* collect weight stats */
18310c16b537SWarner Losh     memset(rankStats, 0, (HUFv05_ABSOLUTEMAX_TABLELOG + 1) * sizeof(U32));
18320c16b537SWarner Losh     weightTotal = 0;
18330c16b537SWarner Losh     for (n=0; n<oSize; n++) {
18340c16b537SWarner Losh         if (huffWeight[n] >= HUFv05_ABSOLUTEMAX_TABLELOG) return ERROR(corruption_detected);
18350c16b537SWarner Losh         rankStats[huffWeight[n]]++;
18360c16b537SWarner Losh         weightTotal += (1 << huffWeight[n]) >> 1;
18370c16b537SWarner Losh     }
18380c16b537SWarner Losh     if (weightTotal == 0) return ERROR(corruption_detected);
18390c16b537SWarner Losh 
18400c16b537SWarner Losh     /* get last non-null symbol weight (implied, total must be 2^n) */
18410c16b537SWarner Losh     tableLog = BITv05_highbit32(weightTotal) + 1;
18420c16b537SWarner Losh     if (tableLog > HUFv05_ABSOLUTEMAX_TABLELOG) return ERROR(corruption_detected);
18430c16b537SWarner Losh     {   /* determine last weight */
18440c16b537SWarner Losh         U32 total = 1 << tableLog;
18450c16b537SWarner Losh         U32 rest = total - weightTotal;
18460c16b537SWarner Losh         U32 verif = 1 << BITv05_highbit32(rest);
18470c16b537SWarner Losh         U32 lastWeight = BITv05_highbit32(rest) + 1;
18480c16b537SWarner Losh         if (verif != rest) return ERROR(corruption_detected);    /* last value must be a clean power of 2 */
18490c16b537SWarner Losh         huffWeight[oSize] = (BYTE)lastWeight;
18500c16b537SWarner Losh         rankStats[lastWeight]++;
18510c16b537SWarner Losh     }
18520c16b537SWarner Losh 
18530c16b537SWarner Losh     /* check tree construction validity */
18540c16b537SWarner Losh     if ((rankStats[1] < 2) || (rankStats[1] & 1)) return ERROR(corruption_detected);   /* by construction : at least 2 elts of rank 1, must be even */
18550c16b537SWarner Losh 
18560c16b537SWarner Losh     /* results */
18570c16b537SWarner Losh     *nbSymbolsPtr = (U32)(oSize+1);
18580c16b537SWarner Losh     *tableLogPtr = tableLog;
18590c16b537SWarner Losh     return iSize+1;
18600c16b537SWarner Losh }
18610c16b537SWarner Losh 
18620c16b537SWarner Losh 
18630c16b537SWarner Losh /*-***************************/
18640c16b537SWarner Losh /*  single-symbol decoding   */
18650c16b537SWarner Losh /*-***************************/
18660c16b537SWarner Losh 
18670c16b537SWarner Losh size_t HUFv05_readDTableX2 (U16* DTable, const void* src, size_t srcSize)
18680c16b537SWarner Losh {
18690c16b537SWarner Losh     BYTE huffWeight[HUFv05_MAX_SYMBOL_VALUE + 1];
18700c16b537SWarner Losh     U32 rankVal[HUFv05_ABSOLUTEMAX_TABLELOG + 1];   /* large enough for values from 0 to 16 */
18710c16b537SWarner Losh     U32 tableLog = 0;
18720c16b537SWarner Losh     size_t iSize;
18730c16b537SWarner Losh     U32 nbSymbols = 0;
18740c16b537SWarner Losh     U32 n;
18750c16b537SWarner Losh     U32 nextRankStart;
18760c16b537SWarner Losh     void* const dtPtr = DTable + 1;
18770c16b537SWarner Losh     HUFv05_DEltX2* const dt = (HUFv05_DEltX2*)dtPtr;
18780c16b537SWarner Losh 
18790c16b537SWarner Losh     HUFv05_STATIC_ASSERT(sizeof(HUFv05_DEltX2) == sizeof(U16));   /* if compilation fails here, assertion is false */
18800c16b537SWarner Losh     //memset(huffWeight, 0, sizeof(huffWeight));   /* is not necessary, even though some analyzer complain ... */
18810c16b537SWarner Losh 
18820c16b537SWarner Losh     iSize = HUFv05_readStats(huffWeight, HUFv05_MAX_SYMBOL_VALUE + 1, rankVal, &nbSymbols, &tableLog, src, srcSize);
18830c16b537SWarner Losh     if (HUFv05_isError(iSize)) return iSize;
18840c16b537SWarner Losh 
18850c16b537SWarner Losh     /* check result */
18860c16b537SWarner Losh     if (tableLog > DTable[0]) return ERROR(tableLog_tooLarge);   /* DTable is too small */
18870c16b537SWarner Losh     DTable[0] = (U16)tableLog;   /* maybe should separate sizeof allocated DTable, from used size of DTable, in case of re-use */
18880c16b537SWarner Losh 
18890c16b537SWarner Losh     /* Prepare ranks */
18900c16b537SWarner Losh     nextRankStart = 0;
18910c16b537SWarner Losh     for (n=1; n<=tableLog; n++) {
18920c16b537SWarner Losh         U32 current = nextRankStart;
18930c16b537SWarner Losh         nextRankStart += (rankVal[n] << (n-1));
18940c16b537SWarner Losh         rankVal[n] = current;
18950c16b537SWarner Losh     }
18960c16b537SWarner Losh 
18970c16b537SWarner Losh     /* fill DTable */
18980c16b537SWarner Losh     for (n=0; n<nbSymbols; n++) {
18990c16b537SWarner Losh         const U32 w = huffWeight[n];
19000c16b537SWarner Losh         const U32 length = (1 << w) >> 1;
19010c16b537SWarner Losh         U32 i;
19020c16b537SWarner Losh         HUFv05_DEltX2 D;
19030c16b537SWarner Losh         D.byte = (BYTE)n; D.nbBits = (BYTE)(tableLog + 1 - w);
19040c16b537SWarner Losh         for (i = rankVal[w]; i < rankVal[w] + length; i++)
19050c16b537SWarner Losh             dt[i] = D;
19060c16b537SWarner Losh         rankVal[w] += length;
19070c16b537SWarner Losh     }
19080c16b537SWarner Losh 
19090c16b537SWarner Losh     return iSize;
19100c16b537SWarner Losh }
19110c16b537SWarner Losh 
19120c16b537SWarner Losh static BYTE HUFv05_decodeSymbolX2(BITv05_DStream_t* Dstream, const HUFv05_DEltX2* dt, const U32 dtLog)
19130c16b537SWarner Losh {
19140c16b537SWarner Losh         const size_t val = BITv05_lookBitsFast(Dstream, dtLog); /* note : dtLog >= 1 */
19150c16b537SWarner Losh         const BYTE c = dt[val].byte;
19160c16b537SWarner Losh         BITv05_skipBits(Dstream, dt[val].nbBits);
19170c16b537SWarner Losh         return c;
19180c16b537SWarner Losh }
19190c16b537SWarner Losh 
19200c16b537SWarner Losh #define HUFv05_DECODE_SYMBOLX2_0(ptr, DStreamPtr) \
19210c16b537SWarner Losh     *ptr++ = HUFv05_decodeSymbolX2(DStreamPtr, dt, dtLog)
19220c16b537SWarner Losh 
19230c16b537SWarner Losh #define HUFv05_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \
19240c16b537SWarner Losh     if (MEM_64bits() || (HUFv05_MAX_TABLELOG<=12)) \
19250c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX2_0(ptr, DStreamPtr)
19260c16b537SWarner Losh 
19270c16b537SWarner Losh #define HUFv05_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \
19280c16b537SWarner Losh     if (MEM_64bits()) \
19290c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX2_0(ptr, DStreamPtr)
19300c16b537SWarner Losh 
19310c16b537SWarner Losh static inline size_t HUFv05_decodeStreamX2(BYTE* p, BITv05_DStream_t* const bitDPtr, BYTE* const pEnd, const HUFv05_DEltX2* const dt, const U32 dtLog)
19320c16b537SWarner Losh {
19330c16b537SWarner Losh     BYTE* const pStart = p;
19340c16b537SWarner Losh 
19350c16b537SWarner Losh     /* up to 4 symbols at a time */
19360c16b537SWarner Losh     while ((BITv05_reloadDStream(bitDPtr) == BITv05_DStream_unfinished) && (p <= pEnd-4)) {
19370c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX2_2(p, bitDPtr);
19380c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX2_1(p, bitDPtr);
19390c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX2_2(p, bitDPtr);
19400c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX2_0(p, bitDPtr);
19410c16b537SWarner Losh     }
19420c16b537SWarner Losh 
19430c16b537SWarner Losh     /* closer to the end */
19440c16b537SWarner Losh     while ((BITv05_reloadDStream(bitDPtr) == BITv05_DStream_unfinished) && (p < pEnd))
19450c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX2_0(p, bitDPtr);
19460c16b537SWarner Losh 
19470c16b537SWarner Losh     /* no more data to retrieve from bitstream, hence no need to reload */
19480c16b537SWarner Losh     while (p < pEnd)
19490c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX2_0(p, bitDPtr);
19500c16b537SWarner Losh 
19510c16b537SWarner Losh     return pEnd-pStart;
19520c16b537SWarner Losh }
19530c16b537SWarner Losh 
19540c16b537SWarner Losh size_t HUFv05_decompress1X2_usingDTable(
19550c16b537SWarner Losh           void* dst,  size_t dstSize,
19560c16b537SWarner Losh     const void* cSrc, size_t cSrcSize,
19570c16b537SWarner Losh     const U16* DTable)
19580c16b537SWarner Losh {
19590c16b537SWarner Losh     BYTE* op = (BYTE*)dst;
19600c16b537SWarner Losh     BYTE* const oend = op + dstSize;
19610c16b537SWarner Losh     const U32 dtLog = DTable[0];
19620c16b537SWarner Losh     const void* dtPtr = DTable;
19630c16b537SWarner Losh     const HUFv05_DEltX2* const dt = ((const HUFv05_DEltX2*)dtPtr)+1;
19640c16b537SWarner Losh     BITv05_DStream_t bitD;
19650c16b537SWarner Losh 
19660c16b537SWarner Losh     if (dstSize <= cSrcSize) return ERROR(dstSize_tooSmall);
19670c16b537SWarner Losh     { size_t const errorCode = BITv05_initDStream(&bitD, cSrc, cSrcSize);
19680c16b537SWarner Losh       if (HUFv05_isError(errorCode)) return errorCode; }
19690c16b537SWarner Losh 
19700c16b537SWarner Losh     HUFv05_decodeStreamX2(op, &bitD, oend, dt, dtLog);
19710c16b537SWarner Losh 
19720c16b537SWarner Losh     /* check */
19730c16b537SWarner Losh     if (!BITv05_endOfDStream(&bitD)) return ERROR(corruption_detected);
19740c16b537SWarner Losh 
19750c16b537SWarner Losh     return dstSize;
19760c16b537SWarner Losh }
19770c16b537SWarner Losh 
19780c16b537SWarner Losh size_t HUFv05_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
19790c16b537SWarner Losh {
19800c16b537SWarner Losh     HUFv05_CREATE_STATIC_DTABLEX2(DTable, HUFv05_MAX_TABLELOG);
19810c16b537SWarner Losh     const BYTE* ip = (const BYTE*) cSrc;
19820c16b537SWarner Losh     size_t errorCode;
19830c16b537SWarner Losh 
19840c16b537SWarner Losh     errorCode = HUFv05_readDTableX2 (DTable, cSrc, cSrcSize);
19850c16b537SWarner Losh     if (HUFv05_isError(errorCode)) return errorCode;
19860c16b537SWarner Losh     if (errorCode >= cSrcSize) return ERROR(srcSize_wrong);
19870c16b537SWarner Losh     ip += errorCode;
19880c16b537SWarner Losh     cSrcSize -= errorCode;
19890c16b537SWarner Losh 
19900c16b537SWarner Losh     return HUFv05_decompress1X2_usingDTable (dst, dstSize, ip, cSrcSize, DTable);
19910c16b537SWarner Losh }
19920c16b537SWarner Losh 
19930c16b537SWarner Losh 
19940c16b537SWarner Losh size_t HUFv05_decompress4X2_usingDTable(
19950c16b537SWarner Losh           void* dst,  size_t dstSize,
19960c16b537SWarner Losh     const void* cSrc, size_t cSrcSize,
19970c16b537SWarner Losh     const U16* DTable)
19980c16b537SWarner Losh {
19990c16b537SWarner Losh     const BYTE* const istart = (const BYTE*) cSrc;
20000c16b537SWarner Losh     BYTE* const ostart = (BYTE*) dst;
20010c16b537SWarner Losh     BYTE* const oend = ostart + dstSize;
20020c16b537SWarner Losh     const void* const dtPtr = DTable;
20030c16b537SWarner Losh     const HUFv05_DEltX2* const dt = ((const HUFv05_DEltX2*)dtPtr) +1;
20040c16b537SWarner Losh     const U32 dtLog = DTable[0];
20050c16b537SWarner Losh     size_t errorCode;
20060c16b537SWarner Losh 
20070c16b537SWarner Losh     /* Init */
20080c16b537SWarner Losh     BITv05_DStream_t bitD1;
20090c16b537SWarner Losh     BITv05_DStream_t bitD2;
20100c16b537SWarner Losh     BITv05_DStream_t bitD3;
20110c16b537SWarner Losh     BITv05_DStream_t bitD4;
20120c16b537SWarner Losh     const size_t length1 = MEM_readLE16(istart);
20130c16b537SWarner Losh     const size_t length2 = MEM_readLE16(istart+2);
20140c16b537SWarner Losh     const size_t length3 = MEM_readLE16(istart+4);
20150c16b537SWarner Losh     size_t length4;
20160c16b537SWarner Losh     const BYTE* const istart1 = istart + 6;  /* jumpTable */
20170c16b537SWarner Losh     const BYTE* const istart2 = istart1 + length1;
20180c16b537SWarner Losh     const BYTE* const istart3 = istart2 + length2;
20190c16b537SWarner Losh     const BYTE* const istart4 = istart3 + length3;
20200c16b537SWarner Losh     const size_t segmentSize = (dstSize+3) / 4;
20210c16b537SWarner Losh     BYTE* const opStart2 = ostart + segmentSize;
20220c16b537SWarner Losh     BYTE* const opStart3 = opStart2 + segmentSize;
20230c16b537SWarner Losh     BYTE* const opStart4 = opStart3 + segmentSize;
20240c16b537SWarner Losh     BYTE* op1 = ostart;
20250c16b537SWarner Losh     BYTE* op2 = opStart2;
20260c16b537SWarner Losh     BYTE* op3 = opStart3;
20270c16b537SWarner Losh     BYTE* op4 = opStart4;
20280c16b537SWarner Losh     U32 endSignal;
20290c16b537SWarner Losh 
20300c16b537SWarner Losh     /* Check */
20310c16b537SWarner Losh     if (cSrcSize < 10) return ERROR(corruption_detected);   /* strict minimum : jump table + 1 byte per stream */
20320c16b537SWarner Losh 
20330c16b537SWarner Losh     length4 = cSrcSize - (length1 + length2 + length3 + 6);
20340c16b537SWarner Losh     if (length4 > cSrcSize) return ERROR(corruption_detected);   /* overflow */
20350c16b537SWarner Losh     errorCode = BITv05_initDStream(&bitD1, istart1, length1);
20360c16b537SWarner Losh     if (HUFv05_isError(errorCode)) return errorCode;
20370c16b537SWarner Losh     errorCode = BITv05_initDStream(&bitD2, istart2, length2);
20380c16b537SWarner Losh     if (HUFv05_isError(errorCode)) return errorCode;
20390c16b537SWarner Losh     errorCode = BITv05_initDStream(&bitD3, istart3, length3);
20400c16b537SWarner Losh     if (HUFv05_isError(errorCode)) return errorCode;
20410c16b537SWarner Losh     errorCode = BITv05_initDStream(&bitD4, istart4, length4);
20420c16b537SWarner Losh     if (HUFv05_isError(errorCode)) return errorCode;
20430c16b537SWarner Losh 
20440c16b537SWarner Losh     /* 16-32 symbols per loop (4-8 symbols per stream) */
20450c16b537SWarner Losh     endSignal = BITv05_reloadDStream(&bitD1) | BITv05_reloadDStream(&bitD2) | BITv05_reloadDStream(&bitD3) | BITv05_reloadDStream(&bitD4);
20460c16b537SWarner Losh     for ( ; (endSignal==BITv05_DStream_unfinished) && (op4<(oend-7)) ; ) {
20470c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX2_2(op1, &bitD1);
20480c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX2_2(op2, &bitD2);
20490c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX2_2(op3, &bitD3);
20500c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX2_2(op4, &bitD4);
20510c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX2_1(op1, &bitD1);
20520c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX2_1(op2, &bitD2);
20530c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX2_1(op3, &bitD3);
20540c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX2_1(op4, &bitD4);
20550c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX2_2(op1, &bitD1);
20560c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX2_2(op2, &bitD2);
20570c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX2_2(op3, &bitD3);
20580c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX2_2(op4, &bitD4);
20590c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX2_0(op1, &bitD1);
20600c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX2_0(op2, &bitD2);
20610c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX2_0(op3, &bitD3);
20620c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX2_0(op4, &bitD4);
20630c16b537SWarner Losh         endSignal = BITv05_reloadDStream(&bitD1) | BITv05_reloadDStream(&bitD2) | BITv05_reloadDStream(&bitD3) | BITv05_reloadDStream(&bitD4);
20640c16b537SWarner Losh     }
20650c16b537SWarner Losh 
20660c16b537SWarner Losh     /* check corruption */
20670c16b537SWarner Losh     if (op1 > opStart2) return ERROR(corruption_detected);
20680c16b537SWarner Losh     if (op2 > opStart3) return ERROR(corruption_detected);
20690c16b537SWarner Losh     if (op3 > opStart4) return ERROR(corruption_detected);
20700c16b537SWarner Losh     /* note : op4 supposed already verified within main loop */
20710c16b537SWarner Losh 
20720c16b537SWarner Losh     /* finish bitStreams one by one */
20730c16b537SWarner Losh     HUFv05_decodeStreamX2(op1, &bitD1, opStart2, dt, dtLog);
20740c16b537SWarner Losh     HUFv05_decodeStreamX2(op2, &bitD2, opStart3, dt, dtLog);
20750c16b537SWarner Losh     HUFv05_decodeStreamX2(op3, &bitD3, opStart4, dt, dtLog);
20760c16b537SWarner Losh     HUFv05_decodeStreamX2(op4, &bitD4, oend,     dt, dtLog);
20770c16b537SWarner Losh 
20780c16b537SWarner Losh     /* check */
20790c16b537SWarner Losh     endSignal = BITv05_endOfDStream(&bitD1) & BITv05_endOfDStream(&bitD2) & BITv05_endOfDStream(&bitD3) & BITv05_endOfDStream(&bitD4);
20800c16b537SWarner Losh     if (!endSignal) return ERROR(corruption_detected);
20810c16b537SWarner Losh 
20820c16b537SWarner Losh     /* decoded size */
20830c16b537SWarner Losh     return dstSize;
20840c16b537SWarner Losh }
20850c16b537SWarner Losh 
20860c16b537SWarner Losh 
20870c16b537SWarner Losh size_t HUFv05_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
20880c16b537SWarner Losh {
20890c16b537SWarner Losh     HUFv05_CREATE_STATIC_DTABLEX2(DTable, HUFv05_MAX_TABLELOG);
20900c16b537SWarner Losh     const BYTE* ip = (const BYTE*) cSrc;
20910c16b537SWarner Losh     size_t errorCode;
20920c16b537SWarner Losh 
20930c16b537SWarner Losh     errorCode = HUFv05_readDTableX2 (DTable, cSrc, cSrcSize);
20940c16b537SWarner Losh     if (HUFv05_isError(errorCode)) return errorCode;
20950c16b537SWarner Losh     if (errorCode >= cSrcSize) return ERROR(srcSize_wrong);
20960c16b537SWarner Losh     ip += errorCode;
20970c16b537SWarner Losh     cSrcSize -= errorCode;
20980c16b537SWarner Losh 
20990c16b537SWarner Losh     return HUFv05_decompress4X2_usingDTable (dst, dstSize, ip, cSrcSize, DTable);
21000c16b537SWarner Losh }
21010c16b537SWarner Losh 
21020c16b537SWarner Losh 
21030c16b537SWarner Losh /* *************************/
21040c16b537SWarner Losh /* double-symbols decoding */
21050c16b537SWarner Losh /* *************************/
21060c16b537SWarner Losh 
21070c16b537SWarner Losh static void HUFv05_fillDTableX4Level2(HUFv05_DEltX4* DTable, U32 sizeLog, const U32 consumed,
21080c16b537SWarner Losh                            const U32* rankValOrigin, const int minWeight,
21090c16b537SWarner Losh                            const sortedSymbol_t* sortedSymbols, const U32 sortedListSize,
21100c16b537SWarner Losh                            U32 nbBitsBaseline, U16 baseSeq)
21110c16b537SWarner Losh {
21120c16b537SWarner Losh     HUFv05_DEltX4 DElt;
21130c16b537SWarner Losh     U32 rankVal[HUFv05_ABSOLUTEMAX_TABLELOG + 1];
21140c16b537SWarner Losh     U32 s;
21150c16b537SWarner Losh 
21160c16b537SWarner Losh     /* get pre-calculated rankVal */
21170c16b537SWarner Losh     memcpy(rankVal, rankValOrigin, sizeof(rankVal));
21180c16b537SWarner Losh 
21190c16b537SWarner Losh     /* fill skipped values */
21200c16b537SWarner Losh     if (minWeight>1) {
21210c16b537SWarner Losh         U32 i, skipSize = rankVal[minWeight];
21220c16b537SWarner Losh         MEM_writeLE16(&(DElt.sequence), baseSeq);
21230c16b537SWarner Losh         DElt.nbBits   = (BYTE)(consumed);
21240c16b537SWarner Losh         DElt.length   = 1;
21250c16b537SWarner Losh         for (i = 0; i < skipSize; i++)
21260c16b537SWarner Losh             DTable[i] = DElt;
21270c16b537SWarner Losh     }
21280c16b537SWarner Losh 
21290c16b537SWarner Losh     /* fill DTable */
21300c16b537SWarner Losh     for (s=0; s<sortedListSize; s++) {   /* note : sortedSymbols already skipped */
21310c16b537SWarner Losh         const U32 symbol = sortedSymbols[s].symbol;
21320c16b537SWarner Losh         const U32 weight = sortedSymbols[s].weight;
21330c16b537SWarner Losh         const U32 nbBits = nbBitsBaseline - weight;
21340c16b537SWarner Losh         const U32 length = 1 << (sizeLog-nbBits);
21350c16b537SWarner Losh         const U32 start = rankVal[weight];
21360c16b537SWarner Losh         U32 i = start;
21370c16b537SWarner Losh         const U32 end = start + length;
21380c16b537SWarner Losh 
21390c16b537SWarner Losh         MEM_writeLE16(&(DElt.sequence), (U16)(baseSeq + (symbol << 8)));
21400c16b537SWarner Losh         DElt.nbBits = (BYTE)(nbBits + consumed);
21410c16b537SWarner Losh         DElt.length = 2;
21420c16b537SWarner Losh         do { DTable[i++] = DElt; } while (i<end);   /* since length >= 1 */
21430c16b537SWarner Losh 
21440c16b537SWarner Losh         rankVal[weight] += length;
21450c16b537SWarner Losh     }
21460c16b537SWarner Losh }
21470c16b537SWarner Losh 
21480c16b537SWarner Losh typedef U32 rankVal_t[HUFv05_ABSOLUTEMAX_TABLELOG][HUFv05_ABSOLUTEMAX_TABLELOG + 1];
21490c16b537SWarner Losh 
21500c16b537SWarner Losh static void HUFv05_fillDTableX4(HUFv05_DEltX4* DTable, const U32 targetLog,
21510c16b537SWarner Losh                            const sortedSymbol_t* sortedList, const U32 sortedListSize,
21520c16b537SWarner Losh                            const U32* rankStart, rankVal_t rankValOrigin, const U32 maxWeight,
21530c16b537SWarner Losh                            const U32 nbBitsBaseline)
21540c16b537SWarner Losh {
21550c16b537SWarner Losh     U32 rankVal[HUFv05_ABSOLUTEMAX_TABLELOG + 1];
21560c16b537SWarner Losh     const int scaleLog = nbBitsBaseline - targetLog;   /* note : targetLog >= srcLog, hence scaleLog <= 1 */
21570c16b537SWarner Losh     const U32 minBits  = nbBitsBaseline - maxWeight;
21580c16b537SWarner Losh     U32 s;
21590c16b537SWarner Losh 
21600c16b537SWarner Losh     memcpy(rankVal, rankValOrigin, sizeof(rankVal));
21610c16b537SWarner Losh 
21620c16b537SWarner Losh     /* fill DTable */
21630c16b537SWarner Losh     for (s=0; s<sortedListSize; s++) {
21640c16b537SWarner Losh         const U16 symbol = sortedList[s].symbol;
21650c16b537SWarner Losh         const U32 weight = sortedList[s].weight;
21660c16b537SWarner Losh         const U32 nbBits = nbBitsBaseline - weight;
21670c16b537SWarner Losh         const U32 start = rankVal[weight];
21680c16b537SWarner Losh         const U32 length = 1 << (targetLog-nbBits);
21690c16b537SWarner Losh 
21700c16b537SWarner Losh         if (targetLog-nbBits >= minBits) {   /* enough room for a second symbol */
21710c16b537SWarner Losh             U32 sortedRank;
21720c16b537SWarner Losh             int minWeight = nbBits + scaleLog;
21730c16b537SWarner Losh             if (minWeight < 1) minWeight = 1;
21740c16b537SWarner Losh             sortedRank = rankStart[minWeight];
21750c16b537SWarner Losh             HUFv05_fillDTableX4Level2(DTable+start, targetLog-nbBits, nbBits,
21760c16b537SWarner Losh                            rankValOrigin[nbBits], minWeight,
21770c16b537SWarner Losh                            sortedList+sortedRank, sortedListSize-sortedRank,
21780c16b537SWarner Losh                            nbBitsBaseline, symbol);
21790c16b537SWarner Losh         } else {
21800c16b537SWarner Losh             U32 i;
21810c16b537SWarner Losh             const U32 end = start + length;
21820c16b537SWarner Losh             HUFv05_DEltX4 DElt;
21830c16b537SWarner Losh 
21840c16b537SWarner Losh             MEM_writeLE16(&(DElt.sequence), symbol);
21850c16b537SWarner Losh             DElt.nbBits   = (BYTE)(nbBits);
21860c16b537SWarner Losh             DElt.length   = 1;
21870c16b537SWarner Losh             for (i = start; i < end; i++)
21880c16b537SWarner Losh                 DTable[i] = DElt;
21890c16b537SWarner Losh         }
21900c16b537SWarner Losh         rankVal[weight] += length;
21910c16b537SWarner Losh     }
21920c16b537SWarner Losh }
21930c16b537SWarner Losh 
21940c16b537SWarner Losh size_t HUFv05_readDTableX4 (U32* DTable, const void* src, size_t srcSize)
21950c16b537SWarner Losh {
21960c16b537SWarner Losh     BYTE weightList[HUFv05_MAX_SYMBOL_VALUE + 1];
21970c16b537SWarner Losh     sortedSymbol_t sortedSymbol[HUFv05_MAX_SYMBOL_VALUE + 1];
21980c16b537SWarner Losh     U32 rankStats[HUFv05_ABSOLUTEMAX_TABLELOG + 1] = { 0 };
21990c16b537SWarner Losh     U32 rankStart0[HUFv05_ABSOLUTEMAX_TABLELOG + 2] = { 0 };
22000c16b537SWarner Losh     U32* const rankStart = rankStart0+1;
22010c16b537SWarner Losh     rankVal_t rankVal;
22020c16b537SWarner Losh     U32 tableLog, maxW, sizeOfSort, nbSymbols;
22030c16b537SWarner Losh     const U32 memLog = DTable[0];
22040c16b537SWarner Losh     size_t iSize;
22050c16b537SWarner Losh     void* dtPtr = DTable;
22060c16b537SWarner Losh     HUFv05_DEltX4* const dt = ((HUFv05_DEltX4*)dtPtr) + 1;
22070c16b537SWarner Losh 
22080c16b537SWarner Losh     HUFv05_STATIC_ASSERT(sizeof(HUFv05_DEltX4) == sizeof(U32));   /* if compilation fails here, assertion is false */
22090c16b537SWarner Losh     if (memLog > HUFv05_ABSOLUTEMAX_TABLELOG) return ERROR(tableLog_tooLarge);
22100c16b537SWarner Losh     //memset(weightList, 0, sizeof(weightList));   /* is not necessary, even though some analyzer complain ... */
22110c16b537SWarner Losh 
22120c16b537SWarner Losh     iSize = HUFv05_readStats(weightList, HUFv05_MAX_SYMBOL_VALUE + 1, rankStats, &nbSymbols, &tableLog, src, srcSize);
22130c16b537SWarner Losh     if (HUFv05_isError(iSize)) return iSize;
22140c16b537SWarner Losh 
22150c16b537SWarner Losh     /* check result */
22160c16b537SWarner Losh     if (tableLog > memLog) return ERROR(tableLog_tooLarge);   /* DTable can't fit code depth */
22170c16b537SWarner Losh 
22180c16b537SWarner Losh     /* find maxWeight */
22190c16b537SWarner Losh     for (maxW = tableLog; rankStats[maxW]==0; maxW--) {}  /* necessarily finds a solution before 0 */
22200c16b537SWarner Losh 
22210c16b537SWarner Losh     /* Get start index of each weight */
22220c16b537SWarner Losh     {
22230c16b537SWarner Losh         U32 w, nextRankStart = 0;
22240c16b537SWarner Losh         for (w=1; w<=maxW; w++) {
22250c16b537SWarner Losh             U32 current = nextRankStart;
22260c16b537SWarner Losh             nextRankStart += rankStats[w];
22270c16b537SWarner Losh             rankStart[w] = current;
22280c16b537SWarner Losh         }
22290c16b537SWarner Losh         rankStart[0] = nextRankStart;   /* put all 0w symbols at the end of sorted list*/
22300c16b537SWarner Losh         sizeOfSort = nextRankStart;
22310c16b537SWarner Losh     }
22320c16b537SWarner Losh 
22330c16b537SWarner Losh     /* sort symbols by weight */
22340c16b537SWarner Losh     {
22350c16b537SWarner Losh         U32 s;
22360c16b537SWarner Losh         for (s=0; s<nbSymbols; s++) {
22370c16b537SWarner Losh             U32 w = weightList[s];
22380c16b537SWarner Losh             U32 r = rankStart[w]++;
22390c16b537SWarner Losh             sortedSymbol[r].symbol = (BYTE)s;
22400c16b537SWarner Losh             sortedSymbol[r].weight = (BYTE)w;
22410c16b537SWarner Losh         }
22420c16b537SWarner Losh         rankStart[0] = 0;   /* forget 0w symbols; this is beginning of weight(1) */
22430c16b537SWarner Losh     }
22440c16b537SWarner Losh 
22450c16b537SWarner Losh     /* Build rankVal */
22460c16b537SWarner Losh     {
22470c16b537SWarner Losh         const U32 minBits = tableLog+1 - maxW;
22480c16b537SWarner Losh         U32 nextRankVal = 0;
22490c16b537SWarner Losh         U32 w, consumed;
22500c16b537SWarner Losh         const int rescale = (memLog-tableLog) - 1;   /* tableLog <= memLog */
22510c16b537SWarner Losh         U32* rankVal0 = rankVal[0];
22520c16b537SWarner Losh         for (w=1; w<=maxW; w++) {
22530c16b537SWarner Losh             U32 current = nextRankVal;
22540c16b537SWarner Losh             nextRankVal += rankStats[w] << (w+rescale);
22550c16b537SWarner Losh             rankVal0[w] = current;
22560c16b537SWarner Losh         }
22570c16b537SWarner Losh         for (consumed = minBits; consumed <= memLog - minBits; consumed++) {
22580c16b537SWarner Losh             U32* rankValPtr = rankVal[consumed];
22590c16b537SWarner Losh             for (w = 1; w <= maxW; w++) {
22600c16b537SWarner Losh                 rankValPtr[w] = rankVal0[w] >> consumed;
22610c16b537SWarner Losh     }   }   }
22620c16b537SWarner Losh 
22630c16b537SWarner Losh     HUFv05_fillDTableX4(dt, memLog,
22640c16b537SWarner Losh                    sortedSymbol, sizeOfSort,
22650c16b537SWarner Losh                    rankStart0, rankVal, maxW,
22660c16b537SWarner Losh                    tableLog+1);
22670c16b537SWarner Losh 
22680c16b537SWarner Losh     return iSize;
22690c16b537SWarner Losh }
22700c16b537SWarner Losh 
22710c16b537SWarner Losh 
22720c16b537SWarner Losh static U32 HUFv05_decodeSymbolX4(void* op, BITv05_DStream_t* DStream, const HUFv05_DEltX4* dt, const U32 dtLog)
22730c16b537SWarner Losh {
22740c16b537SWarner Losh     const size_t val = BITv05_lookBitsFast(DStream, dtLog);   /* note : dtLog >= 1 */
22750c16b537SWarner Losh     memcpy(op, dt+val, 2);
22760c16b537SWarner Losh     BITv05_skipBits(DStream, dt[val].nbBits);
22770c16b537SWarner Losh     return dt[val].length;
22780c16b537SWarner Losh }
22790c16b537SWarner Losh 
22800c16b537SWarner Losh static U32 HUFv05_decodeLastSymbolX4(void* op, BITv05_DStream_t* DStream, const HUFv05_DEltX4* dt, const U32 dtLog)
22810c16b537SWarner Losh {
22820c16b537SWarner Losh     const size_t val = BITv05_lookBitsFast(DStream, dtLog);   /* note : dtLog >= 1 */
22830c16b537SWarner Losh     memcpy(op, dt+val, 1);
22840c16b537SWarner Losh     if (dt[val].length==1) BITv05_skipBits(DStream, dt[val].nbBits);
22850c16b537SWarner Losh     else {
22860c16b537SWarner Losh         if (DStream->bitsConsumed < (sizeof(DStream->bitContainer)*8)) {
22870c16b537SWarner Losh             BITv05_skipBits(DStream, dt[val].nbBits);
22880c16b537SWarner Losh             if (DStream->bitsConsumed > (sizeof(DStream->bitContainer)*8))
22890c16b537SWarner 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 */
22900c16b537SWarner Losh     }   }
22910c16b537SWarner Losh     return 1;
22920c16b537SWarner Losh }
22930c16b537SWarner Losh 
22940c16b537SWarner Losh 
22950c16b537SWarner Losh #define HUFv05_DECODE_SYMBOLX4_0(ptr, DStreamPtr) \
22960c16b537SWarner Losh     ptr += HUFv05_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
22970c16b537SWarner Losh 
22980c16b537SWarner Losh #define HUFv05_DECODE_SYMBOLX4_1(ptr, DStreamPtr) \
22990c16b537SWarner Losh     if (MEM_64bits() || (HUFv05_MAX_TABLELOG<=12)) \
23000c16b537SWarner Losh         ptr += HUFv05_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
23010c16b537SWarner Losh 
23020c16b537SWarner Losh #define HUFv05_DECODE_SYMBOLX4_2(ptr, DStreamPtr) \
23030c16b537SWarner Losh     if (MEM_64bits()) \
23040c16b537SWarner Losh         ptr += HUFv05_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
23050c16b537SWarner Losh 
23060c16b537SWarner Losh static inline size_t HUFv05_decodeStreamX4(BYTE* p, BITv05_DStream_t* bitDPtr, BYTE* const pEnd, const HUFv05_DEltX4* const dt, const U32 dtLog)
23070c16b537SWarner Losh {
23080c16b537SWarner Losh     BYTE* const pStart = p;
23090c16b537SWarner Losh 
23100c16b537SWarner Losh     /* up to 8 symbols at a time */
23110c16b537SWarner Losh     while ((BITv05_reloadDStream(bitDPtr) == BITv05_DStream_unfinished) && (p < pEnd-7)) {
23120c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX4_2(p, bitDPtr);
23130c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX4_1(p, bitDPtr);
23140c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX4_2(p, bitDPtr);
23150c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX4_0(p, bitDPtr);
23160c16b537SWarner Losh     }
23170c16b537SWarner Losh 
23180c16b537SWarner Losh     /* closer to the end */
23190c16b537SWarner Losh     while ((BITv05_reloadDStream(bitDPtr) == BITv05_DStream_unfinished) && (p <= pEnd-2))
23200c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX4_0(p, bitDPtr);
23210c16b537SWarner Losh 
23220c16b537SWarner Losh     while (p <= pEnd-2)
23230c16b537SWarner Losh         HUFv05_DECODE_SYMBOLX4_0(p, bitDPtr);   /* no need to reload : reached the end of DStream */
23240c16b537SWarner Losh 
23250c16b537SWarner Losh     if (p < pEnd)
23260c16b537SWarner Losh         p += HUFv05_decodeLastSymbolX4(p, bitDPtr, dt, dtLog);
23270c16b537SWarner Losh 
23280c16b537SWarner Losh     return p-pStart;
23290c16b537SWarner Losh }
23300c16b537SWarner Losh 
23310c16b537SWarner Losh 
23320c16b537SWarner Losh size_t HUFv05_decompress1X4_usingDTable(
23330c16b537SWarner Losh           void* dst,  size_t dstSize,
23340c16b537SWarner Losh     const void* cSrc, size_t cSrcSize,
23350c16b537SWarner Losh     const U32* DTable)
23360c16b537SWarner Losh {
23370c16b537SWarner Losh     const BYTE* const istart = (const BYTE*) cSrc;
23380c16b537SWarner Losh     BYTE* const ostart = (BYTE*) dst;
23390c16b537SWarner Losh     BYTE* const oend = ostart + dstSize;
23400c16b537SWarner Losh 
23410c16b537SWarner Losh     const U32 dtLog = DTable[0];
23420c16b537SWarner Losh     const void* const dtPtr = DTable;
23430c16b537SWarner Losh     const HUFv05_DEltX4* const dt = ((const HUFv05_DEltX4*)dtPtr) +1;
23440c16b537SWarner Losh     size_t errorCode;
23450c16b537SWarner Losh 
23460c16b537SWarner Losh     /* Init */
23470c16b537SWarner Losh     BITv05_DStream_t bitD;
23480c16b537SWarner Losh     errorCode = BITv05_initDStream(&bitD, istart, cSrcSize);
23490c16b537SWarner Losh     if (HUFv05_isError(errorCode)) return errorCode;
23500c16b537SWarner Losh 
23510c16b537SWarner Losh     /* finish bitStreams one by one */
23520c16b537SWarner Losh     HUFv05_decodeStreamX4(ostart, &bitD, oend,     dt, dtLog);
23530c16b537SWarner Losh 
23540c16b537SWarner Losh     /* check */
23550c16b537SWarner Losh     if (!BITv05_endOfDStream(&bitD)) return ERROR(corruption_detected);
23560c16b537SWarner Losh 
23570c16b537SWarner Losh     /* decoded size */
23580c16b537SWarner Losh     return dstSize;
23590c16b537SWarner Losh }
23600c16b537SWarner Losh 
23610c16b537SWarner Losh size_t HUFv05_decompress1X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
23620c16b537SWarner Losh {
23630c16b537SWarner Losh     HUFv05_CREATE_STATIC_DTABLEX4(DTable, HUFv05_MAX_TABLELOG);
23640c16b537SWarner Losh     const BYTE* ip = (const BYTE*) cSrc;
23650c16b537SWarner Losh 
23660c16b537SWarner Losh     size_t hSize = HUFv05_readDTableX4 (DTable, cSrc, cSrcSize);
23670c16b537SWarner Losh     if (HUFv05_isError(hSize)) return hSize;
23680c16b537SWarner Losh     if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
23690c16b537SWarner Losh     ip += hSize;
23700c16b537SWarner Losh     cSrcSize -= hSize;
23710c16b537SWarner Losh 
23720c16b537SWarner Losh     return HUFv05_decompress1X4_usingDTable (dst, dstSize, ip, cSrcSize, DTable);
23730c16b537SWarner Losh }
23740c16b537SWarner Losh 
23750c16b537SWarner Losh size_t HUFv05_decompress4X4_usingDTable(
23760c16b537SWarner Losh           void* dst,  size_t dstSize,
23770c16b537SWarner Losh     const void* cSrc, size_t cSrcSize,
23780c16b537SWarner Losh     const U32* DTable)
23790c16b537SWarner Losh {
23800c16b537SWarner Losh     if (cSrcSize < 10) return ERROR(corruption_detected);   /* strict minimum : jump table + 1 byte per stream */
23810c16b537SWarner Losh 
23820c16b537SWarner Losh     {
23830c16b537SWarner Losh         const BYTE* const istart = (const BYTE*) cSrc;
23840c16b537SWarner Losh         BYTE* const ostart = (BYTE*) dst;
23850c16b537SWarner Losh         BYTE* const oend = ostart + dstSize;
23860c16b537SWarner Losh         const void* const dtPtr = DTable;
23870c16b537SWarner Losh         const HUFv05_DEltX4* const dt = ((const HUFv05_DEltX4*)dtPtr) +1;
23880c16b537SWarner Losh         const U32 dtLog = DTable[0];
23890c16b537SWarner Losh         size_t errorCode;
23900c16b537SWarner Losh 
23910c16b537SWarner Losh         /* Init */
23920c16b537SWarner Losh         BITv05_DStream_t bitD1;
23930c16b537SWarner Losh         BITv05_DStream_t bitD2;
23940c16b537SWarner Losh         BITv05_DStream_t bitD3;
23950c16b537SWarner Losh         BITv05_DStream_t bitD4;
23960c16b537SWarner Losh         const size_t length1 = MEM_readLE16(istart);
23970c16b537SWarner Losh         const size_t length2 = MEM_readLE16(istart+2);
23980c16b537SWarner Losh         const size_t length3 = MEM_readLE16(istart+4);
23990c16b537SWarner Losh         size_t length4;
24000c16b537SWarner Losh         const BYTE* const istart1 = istart + 6;  /* jumpTable */
24010c16b537SWarner Losh         const BYTE* const istart2 = istart1 + length1;
24020c16b537SWarner Losh         const BYTE* const istart3 = istart2 + length2;
24030c16b537SWarner Losh         const BYTE* const istart4 = istart3 + length3;
24040c16b537SWarner Losh         const size_t segmentSize = (dstSize+3) / 4;
24050c16b537SWarner Losh         BYTE* const opStart2 = ostart + segmentSize;
24060c16b537SWarner Losh         BYTE* const opStart3 = opStart2 + segmentSize;
24070c16b537SWarner Losh         BYTE* const opStart4 = opStart3 + segmentSize;
24080c16b537SWarner Losh         BYTE* op1 = ostart;
24090c16b537SWarner Losh         BYTE* op2 = opStart2;
24100c16b537SWarner Losh         BYTE* op3 = opStart3;
24110c16b537SWarner Losh         BYTE* op4 = opStart4;
24120c16b537SWarner Losh         U32 endSignal;
24130c16b537SWarner Losh 
24140c16b537SWarner Losh         length4 = cSrcSize - (length1 + length2 + length3 + 6);
24150c16b537SWarner Losh         if (length4 > cSrcSize) return ERROR(corruption_detected);   /* overflow */
24160c16b537SWarner Losh         errorCode = BITv05_initDStream(&bitD1, istart1, length1);
24170c16b537SWarner Losh         if (HUFv05_isError(errorCode)) return errorCode;
24180c16b537SWarner Losh         errorCode = BITv05_initDStream(&bitD2, istart2, length2);
24190c16b537SWarner Losh         if (HUFv05_isError(errorCode)) return errorCode;
24200c16b537SWarner Losh         errorCode = BITv05_initDStream(&bitD3, istart3, length3);
24210c16b537SWarner Losh         if (HUFv05_isError(errorCode)) return errorCode;
24220c16b537SWarner Losh         errorCode = BITv05_initDStream(&bitD4, istart4, length4);
24230c16b537SWarner Losh         if (HUFv05_isError(errorCode)) return errorCode;
24240c16b537SWarner Losh 
24250c16b537SWarner Losh         /* 16-32 symbols per loop (4-8 symbols per stream) */
24260c16b537SWarner Losh         endSignal = BITv05_reloadDStream(&bitD1) | BITv05_reloadDStream(&bitD2) | BITv05_reloadDStream(&bitD3) | BITv05_reloadDStream(&bitD4);
24270c16b537SWarner Losh         for ( ; (endSignal==BITv05_DStream_unfinished) && (op4<(oend-7)) ; ) {
24280c16b537SWarner Losh             HUFv05_DECODE_SYMBOLX4_2(op1, &bitD1);
24290c16b537SWarner Losh             HUFv05_DECODE_SYMBOLX4_2(op2, &bitD2);
24300c16b537SWarner Losh             HUFv05_DECODE_SYMBOLX4_2(op3, &bitD3);
24310c16b537SWarner Losh             HUFv05_DECODE_SYMBOLX4_2(op4, &bitD4);
24320c16b537SWarner Losh             HUFv05_DECODE_SYMBOLX4_1(op1, &bitD1);
24330c16b537SWarner Losh             HUFv05_DECODE_SYMBOLX4_1(op2, &bitD2);
24340c16b537SWarner Losh             HUFv05_DECODE_SYMBOLX4_1(op3, &bitD3);
24350c16b537SWarner Losh             HUFv05_DECODE_SYMBOLX4_1(op4, &bitD4);
24360c16b537SWarner Losh             HUFv05_DECODE_SYMBOLX4_2(op1, &bitD1);
24370c16b537SWarner Losh             HUFv05_DECODE_SYMBOLX4_2(op2, &bitD2);
24380c16b537SWarner Losh             HUFv05_DECODE_SYMBOLX4_2(op3, &bitD3);
24390c16b537SWarner Losh             HUFv05_DECODE_SYMBOLX4_2(op4, &bitD4);
24400c16b537SWarner Losh             HUFv05_DECODE_SYMBOLX4_0(op1, &bitD1);
24410c16b537SWarner Losh             HUFv05_DECODE_SYMBOLX4_0(op2, &bitD2);
24420c16b537SWarner Losh             HUFv05_DECODE_SYMBOLX4_0(op3, &bitD3);
24430c16b537SWarner Losh             HUFv05_DECODE_SYMBOLX4_0(op4, &bitD4);
24440c16b537SWarner Losh 
24450c16b537SWarner Losh             endSignal = BITv05_reloadDStream(&bitD1) | BITv05_reloadDStream(&bitD2) | BITv05_reloadDStream(&bitD3) | BITv05_reloadDStream(&bitD4);
24460c16b537SWarner Losh         }
24470c16b537SWarner Losh 
24480c16b537SWarner Losh         /* check corruption */
24490c16b537SWarner Losh         if (op1 > opStart2) return ERROR(corruption_detected);
24500c16b537SWarner Losh         if (op2 > opStart3) return ERROR(corruption_detected);
24510c16b537SWarner Losh         if (op3 > opStart4) return ERROR(corruption_detected);
24520c16b537SWarner Losh         /* note : op4 supposed already verified within main loop */
24530c16b537SWarner Losh 
24540c16b537SWarner Losh         /* finish bitStreams one by one */
24550c16b537SWarner Losh         HUFv05_decodeStreamX4(op1, &bitD1, opStart2, dt, dtLog);
24560c16b537SWarner Losh         HUFv05_decodeStreamX4(op2, &bitD2, opStart3, dt, dtLog);
24570c16b537SWarner Losh         HUFv05_decodeStreamX4(op3, &bitD3, opStart4, dt, dtLog);
24580c16b537SWarner Losh         HUFv05_decodeStreamX4(op4, &bitD4, oend,     dt, dtLog);
24590c16b537SWarner Losh 
24600c16b537SWarner Losh         /* check */
24610c16b537SWarner Losh         endSignal = BITv05_endOfDStream(&bitD1) & BITv05_endOfDStream(&bitD2) & BITv05_endOfDStream(&bitD3) & BITv05_endOfDStream(&bitD4);
24620c16b537SWarner Losh         if (!endSignal) return ERROR(corruption_detected);
24630c16b537SWarner Losh 
24640c16b537SWarner Losh         /* decoded size */
24650c16b537SWarner Losh         return dstSize;
24660c16b537SWarner Losh     }
24670c16b537SWarner Losh }
24680c16b537SWarner Losh 
24690c16b537SWarner Losh 
24700c16b537SWarner Losh size_t HUFv05_decompress4X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
24710c16b537SWarner Losh {
24720c16b537SWarner Losh     HUFv05_CREATE_STATIC_DTABLEX4(DTable, HUFv05_MAX_TABLELOG);
24730c16b537SWarner Losh     const BYTE* ip = (const BYTE*) cSrc;
24740c16b537SWarner Losh 
24750c16b537SWarner Losh     size_t hSize = HUFv05_readDTableX4 (DTable, cSrc, cSrcSize);
24760c16b537SWarner Losh     if (HUFv05_isError(hSize)) return hSize;
24770c16b537SWarner Losh     if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
24780c16b537SWarner Losh     ip += hSize;
24790c16b537SWarner Losh     cSrcSize -= hSize;
24800c16b537SWarner Losh 
24810c16b537SWarner Losh     return HUFv05_decompress4X4_usingDTable (dst, dstSize, ip, cSrcSize, DTable);
24820c16b537SWarner Losh }
24830c16b537SWarner Losh 
24840c16b537SWarner Losh 
24850c16b537SWarner Losh /* ********************************/
24860c16b537SWarner Losh /* Generic decompression selector */
24870c16b537SWarner Losh /* ********************************/
24880c16b537SWarner Losh 
24890c16b537SWarner Losh typedef struct { U32 tableTime; U32 decode256Time; } algo_time_t;
24900c16b537SWarner Losh static const algo_time_t algoTime[16 /* Quantization */][3 /* single, double, quad */] =
24910c16b537SWarner Losh {
24920c16b537SWarner Losh     /* single, double, quad */
24930c16b537SWarner Losh     {{0,0}, {1,1}, {2,2}},  /* Q==0 : impossible */
24940c16b537SWarner Losh     {{0,0}, {1,1}, {2,2}},  /* Q==1 : impossible */
24950c16b537SWarner Losh     {{  38,130}, {1313, 74}, {2151, 38}},   /* Q == 2 : 12-18% */
24960c16b537SWarner Losh     {{ 448,128}, {1353, 74}, {2238, 41}},   /* Q == 3 : 18-25% */
24970c16b537SWarner Losh     {{ 556,128}, {1353, 74}, {2238, 47}},   /* Q == 4 : 25-32% */
24980c16b537SWarner Losh     {{ 714,128}, {1418, 74}, {2436, 53}},   /* Q == 5 : 32-38% */
24990c16b537SWarner Losh     {{ 883,128}, {1437, 74}, {2464, 61}},   /* Q == 6 : 38-44% */
25000c16b537SWarner Losh     {{ 897,128}, {1515, 75}, {2622, 68}},   /* Q == 7 : 44-50% */
25010c16b537SWarner Losh     {{ 926,128}, {1613, 75}, {2730, 75}},   /* Q == 8 : 50-56% */
25020c16b537SWarner Losh     {{ 947,128}, {1729, 77}, {3359, 77}},   /* Q == 9 : 56-62% */
25030c16b537SWarner Losh     {{1107,128}, {2083, 81}, {4006, 84}},   /* Q ==10 : 62-69% */
25040c16b537SWarner Losh     {{1177,128}, {2379, 87}, {4785, 88}},   /* Q ==11 : 69-75% */
25050c16b537SWarner Losh     {{1242,128}, {2415, 93}, {5155, 84}},   /* Q ==12 : 75-81% */
25060c16b537SWarner Losh     {{1349,128}, {2644,106}, {5260,106}},   /* Q ==13 : 81-87% */
25070c16b537SWarner Losh     {{1455,128}, {2422,124}, {4174,124}},   /* Q ==14 : 87-93% */
25080c16b537SWarner Losh     {{ 722,128}, {1891,145}, {1936,146}},   /* Q ==15 : 93-99% */
25090c16b537SWarner Losh };
25100c16b537SWarner Losh 
25110c16b537SWarner Losh typedef size_t (*decompressionAlgo)(void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);
25120c16b537SWarner Losh 
25130c16b537SWarner Losh size_t HUFv05_decompress (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
25140c16b537SWarner Losh {
25150c16b537SWarner Losh     static const decompressionAlgo decompress[3] = { HUFv05_decompress4X2, HUFv05_decompress4X4, NULL };
25160c16b537SWarner Losh     /* estimate decompression time */
25170c16b537SWarner Losh     U32 Q;
25180c16b537SWarner Losh     const U32 D256 = (U32)(dstSize >> 8);
25190c16b537SWarner Losh     U32 Dtime[3];
25200c16b537SWarner Losh     U32 algoNb = 0;
25210c16b537SWarner Losh     int n;
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, or not compressed, but not compressed already dealt with */
25260c16b537SWarner Losh     if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; }   /* RLE */
25270c16b537SWarner Losh 
25280c16b537SWarner Losh     /* decoder timing evaluation */
25290c16b537SWarner Losh     Q = (U32)(cSrcSize * 16 / dstSize);   /* Q < 16 since dstSize > cSrcSize */
25300c16b537SWarner Losh     for (n=0; n<3; n++)
25310c16b537SWarner Losh         Dtime[n] = algoTime[Q][n].tableTime + (algoTime[Q][n].decode256Time * D256);
25320c16b537SWarner Losh 
25330c16b537SWarner Losh     Dtime[1] += Dtime[1] >> 4; Dtime[2] += Dtime[2] >> 3; /* advantage to algorithms using less memory, for cache eviction */
25340c16b537SWarner Losh 
25350c16b537SWarner Losh     if (Dtime[1] < Dtime[0]) algoNb = 1;
25360c16b537SWarner Losh 
25370c16b537SWarner Losh     return decompress[algoNb](dst, dstSize, cSrc, cSrcSize);
25380c16b537SWarner Losh 
25390c16b537SWarner Losh     //return HUFv05_decompress4X2(dst, dstSize, cSrc, cSrcSize);   /* multi-streams single-symbol decoding */
25400c16b537SWarner Losh     //return HUFv05_decompress4X4(dst, dstSize, cSrc, cSrcSize);   /* multi-streams double-symbols decoding */
25410c16b537SWarner Losh     //return HUFv05_decompress4X6(dst, dstSize, cSrc, cSrcSize);   /* multi-streams quad-symbols decoding */
25420c16b537SWarner Losh }
25430c16b537SWarner Losh /*
25440c16b537SWarner Losh     zstd - standard compression library
25450c16b537SWarner Losh     Copyright (C) 2014-2016, Yann Collet.
25460c16b537SWarner Losh 
25470c16b537SWarner Losh     BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
25480c16b537SWarner Losh 
25490c16b537SWarner Losh     Redistribution and use in source and binary forms, with or without
25500c16b537SWarner Losh     modification, are permitted provided that the following conditions are
25510c16b537SWarner Losh     met:
25520c16b537SWarner Losh     * Redistributions of source code must retain the above copyright
25530c16b537SWarner Losh     notice, this list of conditions and the following disclaimer.
25540c16b537SWarner Losh     * Redistributions in binary form must reproduce the above
25550c16b537SWarner Losh     copyright notice, this list of conditions and the following disclaimer
25560c16b537SWarner Losh     in the documentation and/or other materials provided with the
25570c16b537SWarner Losh     distribution.
25580c16b537SWarner Losh     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25590c16b537SWarner Losh     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25600c16b537SWarner Losh     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25610c16b537SWarner Losh     A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25620c16b537SWarner Losh     OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25630c16b537SWarner Losh     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25640c16b537SWarner Losh     LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25650c16b537SWarner Losh     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25660c16b537SWarner Losh     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25670c16b537SWarner Losh     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25680c16b537SWarner Losh     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25690c16b537SWarner Losh 
25700c16b537SWarner Losh     You can contact the author at :
25710c16b537SWarner Losh     - zstd source repository : https://github.com/Cyan4973/zstd
25720c16b537SWarner Losh */
25730c16b537SWarner Losh 
25740c16b537SWarner Losh /* ***************************************************************
25750c16b537SWarner Losh *  Tuning parameters
25760c16b537SWarner Losh *****************************************************************/
25770c16b537SWarner Losh /*!
25780c16b537SWarner Losh  * HEAPMODE :
25790c16b537SWarner Losh  * Select how default decompression function ZSTDv05_decompress() will allocate memory,
25800c16b537SWarner Losh  * in memory stack (0), or in memory heap (1, requires malloc())
25810c16b537SWarner Losh  */
25820c16b537SWarner Losh #ifndef ZSTDv05_HEAPMODE
25830c16b537SWarner Losh #  define ZSTDv05_HEAPMODE 1
25840c16b537SWarner Losh #endif
25850c16b537SWarner Losh 
25860c16b537SWarner Losh 
25870c16b537SWarner Losh /*-*******************************************************
25880c16b537SWarner Losh *  Dependencies
25890c16b537SWarner Losh *********************************************************/
25900c16b537SWarner Losh #include <stdlib.h>      /* calloc */
25910c16b537SWarner Losh #include <string.h>      /* memcpy, memmove */
25920c16b537SWarner Losh #include <stdio.h>       /* debug only : printf */
25930c16b537SWarner Losh 
25940c16b537SWarner Losh 
25950c16b537SWarner Losh /*-*******************************************************
25960c16b537SWarner Losh *  Compiler specifics
25970c16b537SWarner Losh *********************************************************/
25980c16b537SWarner Losh #ifdef _MSC_VER    /* Visual Studio */
25990c16b537SWarner Losh #  include <intrin.h>                    /* For Visual 2005 */
26000c16b537SWarner Losh #  pragma warning(disable : 4127)        /* disable: C4127: conditional expression is constant */
26010c16b537SWarner Losh #  pragma warning(disable : 4324)        /* disable: C4324: padded structure */
26020c16b537SWarner Losh #endif
26030c16b537SWarner Losh 
26040c16b537SWarner Losh 
26050c16b537SWarner Losh /*-*************************************
26060c16b537SWarner Losh *  Local types
26070c16b537SWarner Losh ***************************************/
26080c16b537SWarner Losh typedef struct
26090c16b537SWarner Losh {
26100c16b537SWarner Losh     blockType_t blockType;
26110c16b537SWarner Losh     U32 origSize;
26120c16b537SWarner Losh } blockProperties_t;
26130c16b537SWarner Losh 
26140c16b537SWarner Losh 
26150c16b537SWarner Losh /* *******************************************************
26160c16b537SWarner Losh *  Memory operations
26170c16b537SWarner Losh **********************************************************/
26180c16b537SWarner Losh static void ZSTDv05_copy4(void* dst, const void* src) { memcpy(dst, src, 4); }
26190c16b537SWarner Losh 
26200c16b537SWarner Losh 
26210c16b537SWarner Losh /* *************************************
26220c16b537SWarner Losh *  Error Management
26230c16b537SWarner Losh ***************************************/
26240c16b537SWarner Losh /*! ZSTDv05_isError() :
26250c16b537SWarner Losh *   tells if a return value is an error code */
26260c16b537SWarner Losh unsigned ZSTDv05_isError(size_t code) { return ERR_isError(code); }
26270c16b537SWarner Losh 
26280c16b537SWarner Losh 
26290c16b537SWarner Losh /*! ZSTDv05_getErrorName() :
26300c16b537SWarner Losh *   provides error code string (useful for debugging) */
26310c16b537SWarner Losh const char* ZSTDv05_getErrorName(size_t code) { return ERR_getErrorName(code); }
26320c16b537SWarner Losh 
26330c16b537SWarner Losh 
26340c16b537SWarner Losh /* *************************************************************
26350c16b537SWarner Losh *   Context management
26360c16b537SWarner Losh ***************************************************************/
26370c16b537SWarner Losh typedef enum { ZSTDv05ds_getFrameHeaderSize, ZSTDv05ds_decodeFrameHeader,
26380c16b537SWarner Losh                ZSTDv05ds_decodeBlockHeader, ZSTDv05ds_decompressBlock } ZSTDv05_dStage;
26390c16b537SWarner Losh 
26400c16b537SWarner Losh struct ZSTDv05_DCtx_s
26410c16b537SWarner Losh {
26420c16b537SWarner Losh     FSEv05_DTable LLTable[FSEv05_DTABLE_SIZE_U32(LLFSEv05Log)];
26430c16b537SWarner Losh     FSEv05_DTable OffTable[FSEv05_DTABLE_SIZE_U32(OffFSEv05Log)];
26440c16b537SWarner Losh     FSEv05_DTable MLTable[FSEv05_DTABLE_SIZE_U32(MLFSEv05Log)];
26450c16b537SWarner Losh     unsigned   hufTableX4[HUFv05_DTABLE_SIZE(HufLog)];
26460c16b537SWarner Losh     const void* previousDstEnd;
26470c16b537SWarner Losh     const void* base;
26480c16b537SWarner Losh     const void* vBase;
26490c16b537SWarner Losh     const void* dictEnd;
26500c16b537SWarner Losh     size_t expected;
26510c16b537SWarner Losh     size_t headerSize;
26520c16b537SWarner Losh     ZSTDv05_parameters params;
26530c16b537SWarner Losh     blockType_t bType;   /* used in ZSTDv05_decompressContinue(), to transfer blockType between header decoding and block decoding stages */
26540c16b537SWarner Losh     ZSTDv05_dStage stage;
26550c16b537SWarner Losh     U32 flagStaticTables;
26560c16b537SWarner Losh     const BYTE* litPtr;
26570c16b537SWarner Losh     size_t litSize;
26580c16b537SWarner Losh     BYTE litBuffer[BLOCKSIZE + WILDCOPY_OVERLENGTH];
26590c16b537SWarner Losh     BYTE headerBuffer[ZSTDv05_frameHeaderSize_max];
26600c16b537SWarner Losh };  /* typedef'd to ZSTDv05_DCtx within "zstd_static.h" */
26610c16b537SWarner Losh 
2662*0f743729SConrad Meyer size_t ZSTDv05_sizeofDCtx (void); /* Hidden declaration */
26630c16b537SWarner Losh size_t ZSTDv05_sizeofDCtx (void) { return sizeof(ZSTDv05_DCtx); }
26640c16b537SWarner Losh 
26650c16b537SWarner Losh size_t ZSTDv05_decompressBegin(ZSTDv05_DCtx* dctx)
26660c16b537SWarner Losh {
26670c16b537SWarner Losh     dctx->expected = ZSTDv05_frameHeaderSize_min;
26680c16b537SWarner Losh     dctx->stage = ZSTDv05ds_getFrameHeaderSize;
26690c16b537SWarner Losh     dctx->previousDstEnd = NULL;
26700c16b537SWarner Losh     dctx->base = NULL;
26710c16b537SWarner Losh     dctx->vBase = NULL;
26720c16b537SWarner Losh     dctx->dictEnd = NULL;
26730c16b537SWarner Losh     dctx->hufTableX4[0] = HufLog;
26740c16b537SWarner Losh     dctx->flagStaticTables = 0;
26750c16b537SWarner Losh     return 0;
26760c16b537SWarner Losh }
26770c16b537SWarner Losh 
26780c16b537SWarner Losh ZSTDv05_DCtx* ZSTDv05_createDCtx(void)
26790c16b537SWarner Losh {
26800c16b537SWarner Losh     ZSTDv05_DCtx* dctx = (ZSTDv05_DCtx*)malloc(sizeof(ZSTDv05_DCtx));
26810c16b537SWarner Losh     if (dctx==NULL) return NULL;
26820c16b537SWarner Losh     ZSTDv05_decompressBegin(dctx);
26830c16b537SWarner Losh     return dctx;
26840c16b537SWarner Losh }
26850c16b537SWarner Losh 
26860c16b537SWarner Losh size_t ZSTDv05_freeDCtx(ZSTDv05_DCtx* dctx)
26870c16b537SWarner Losh {
26880c16b537SWarner Losh     free(dctx);
26890c16b537SWarner Losh     return 0;   /* reserved as a potential error code in the future */
26900c16b537SWarner Losh }
26910c16b537SWarner Losh 
26920c16b537SWarner Losh void ZSTDv05_copyDCtx(ZSTDv05_DCtx* dstDCtx, const ZSTDv05_DCtx* srcDCtx)
26930c16b537SWarner Losh {
26940c16b537SWarner Losh     memcpy(dstDCtx, srcDCtx,
26950c16b537SWarner Losh            sizeof(ZSTDv05_DCtx) - (BLOCKSIZE+WILDCOPY_OVERLENGTH + ZSTDv05_frameHeaderSize_max));  /* no need to copy workspace */
26960c16b537SWarner Losh }
26970c16b537SWarner Losh 
26980c16b537SWarner Losh 
26990c16b537SWarner Losh /* *************************************************************
27000c16b537SWarner Losh *   Decompression section
27010c16b537SWarner Losh ***************************************************************/
27020c16b537SWarner Losh 
27030c16b537SWarner Losh /* Frame format description
27040c16b537SWarner Losh    Frame Header -  [ Block Header - Block ] - Frame End
27050c16b537SWarner Losh    1) Frame Header
27060c16b537SWarner Losh       - 4 bytes - Magic Number : ZSTDv05_MAGICNUMBER (defined within zstd_internal.h)
27070c16b537SWarner Losh       - 1 byte  - Window Descriptor
27080c16b537SWarner Losh    2) Block Header
27090c16b537SWarner Losh       - 3 bytes, starting with a 2-bits descriptor
27100c16b537SWarner Losh                  Uncompressed, Compressed, Frame End, unused
27110c16b537SWarner Losh    3) Block
27120c16b537SWarner Losh       See Block Format Description
27130c16b537SWarner Losh    4) Frame End
27140c16b537SWarner Losh       - 3 bytes, compatible with Block Header
27150c16b537SWarner Losh */
27160c16b537SWarner Losh 
27170c16b537SWarner Losh /* Block format description
27180c16b537SWarner Losh 
27190c16b537SWarner Losh    Block = Literal Section - Sequences Section
27200c16b537SWarner Losh    Prerequisite : size of (compressed) block, maximum size of regenerated data
27210c16b537SWarner Losh 
27220c16b537SWarner Losh    1) Literal Section
27230c16b537SWarner Losh 
27240c16b537SWarner Losh    1.1) Header : 1-5 bytes
27250c16b537SWarner Losh         flags: 2 bits
27260c16b537SWarner Losh             00 compressed by Huff0
27270c16b537SWarner Losh             01 unused
27280c16b537SWarner Losh             10 is Raw (uncompressed)
27290c16b537SWarner Losh             11 is Rle
27300c16b537SWarner Losh             Note : using 01 => Huff0 with precomputed table ?
27310c16b537SWarner Losh             Note : delta map ? => compressed ?
27320c16b537SWarner Losh 
27330c16b537SWarner Losh    1.1.1) Huff0-compressed literal block : 3-5 bytes
27340c16b537SWarner Losh             srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream
27350c16b537SWarner Losh             srcSize < 1 KB => 3 bytes (2-2-10-10)
27360c16b537SWarner Losh             srcSize < 16KB => 4 bytes (2-2-14-14)
27370c16b537SWarner Losh             else           => 5 bytes (2-2-18-18)
27380c16b537SWarner Losh             big endian convention
27390c16b537SWarner Losh 
27400c16b537SWarner Losh    1.1.2) Raw (uncompressed) literal block header : 1-3 bytes
27410c16b537SWarner Losh         size :  5 bits: (IS_RAW<<6) + (0<<4) + size
27420c16b537SWarner Losh                12 bits: (IS_RAW<<6) + (2<<4) + (size>>8)
27430c16b537SWarner Losh                         size&255
27440c16b537SWarner Losh                20 bits: (IS_RAW<<6) + (3<<4) + (size>>16)
27450c16b537SWarner Losh                         size>>8&255
27460c16b537SWarner Losh                         size&255
27470c16b537SWarner Losh 
27480c16b537SWarner Losh    1.1.3) Rle (repeated single byte) literal block header : 1-3 bytes
27490c16b537SWarner Losh         size :  5 bits: (IS_RLE<<6) + (0<<4) + size
27500c16b537SWarner Losh                12 bits: (IS_RLE<<6) + (2<<4) + (size>>8)
27510c16b537SWarner Losh                         size&255
27520c16b537SWarner Losh                20 bits: (IS_RLE<<6) + (3<<4) + (size>>16)
27530c16b537SWarner Losh                         size>>8&255
27540c16b537SWarner Losh                         size&255
27550c16b537SWarner Losh 
27560c16b537SWarner Losh    1.1.4) Huff0-compressed literal block, using precomputed CTables : 3-5 bytes
27570c16b537SWarner Losh             srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream
27580c16b537SWarner Losh             srcSize < 1 KB => 3 bytes (2-2-10-10)
27590c16b537SWarner Losh             srcSize < 16KB => 4 bytes (2-2-14-14)
27600c16b537SWarner Losh             else           => 5 bytes (2-2-18-18)
27610c16b537SWarner Losh             big endian convention
27620c16b537SWarner Losh 
27630c16b537SWarner Losh         1- CTable available (stored into workspace ?)
27640c16b537SWarner Losh         2- Small input (fast heuristic ? Full comparison ? depend on clevel ?)
27650c16b537SWarner Losh 
27660c16b537SWarner Losh 
27670c16b537SWarner Losh    1.2) Literal block content
27680c16b537SWarner Losh 
27690c16b537SWarner Losh    1.2.1) Huff0 block, using sizes from header
27700c16b537SWarner Losh         See Huff0 format
27710c16b537SWarner Losh 
27720c16b537SWarner Losh    1.2.2) Huff0 block, using prepared table
27730c16b537SWarner Losh 
27740c16b537SWarner Losh    1.2.3) Raw content
27750c16b537SWarner Losh 
27760c16b537SWarner Losh    1.2.4) single byte
27770c16b537SWarner Losh 
27780c16b537SWarner Losh 
27790c16b537SWarner Losh    2) Sequences section
27800c16b537SWarner Losh       TO DO
27810c16b537SWarner Losh */
27820c16b537SWarner Losh 
27830c16b537SWarner Losh 
27840c16b537SWarner Losh /** ZSTDv05_decodeFrameHeader_Part1() :
27850c16b537SWarner Losh *   decode the 1st part of the Frame Header, which tells Frame Header size.
27860c16b537SWarner Losh *   srcSize must be == ZSTDv05_frameHeaderSize_min.
27870c16b537SWarner Losh *   @return : the full size of the Frame Header */
27880c16b537SWarner Losh static size_t ZSTDv05_decodeFrameHeader_Part1(ZSTDv05_DCtx* zc, const void* src, size_t srcSize)
27890c16b537SWarner Losh {
27900c16b537SWarner Losh     U32 magicNumber;
27910c16b537SWarner Losh     if (srcSize != ZSTDv05_frameHeaderSize_min)
27920c16b537SWarner Losh         return ERROR(srcSize_wrong);
27930c16b537SWarner Losh     magicNumber = MEM_readLE32(src);
27940c16b537SWarner Losh     if (magicNumber != ZSTDv05_MAGICNUMBER) return ERROR(prefix_unknown);
27950c16b537SWarner Losh     zc->headerSize = ZSTDv05_frameHeaderSize_min;
27960c16b537SWarner Losh     return zc->headerSize;
27970c16b537SWarner Losh }
27980c16b537SWarner Losh 
27990c16b537SWarner Losh 
28000c16b537SWarner Losh size_t ZSTDv05_getFrameParams(ZSTDv05_parameters* params, const void* src, size_t srcSize)
28010c16b537SWarner Losh {
28020c16b537SWarner Losh     U32 magicNumber;
28030c16b537SWarner Losh     if (srcSize < ZSTDv05_frameHeaderSize_min) return ZSTDv05_frameHeaderSize_max;
28040c16b537SWarner Losh     magicNumber = MEM_readLE32(src);
28050c16b537SWarner Losh     if (magicNumber != ZSTDv05_MAGICNUMBER) return ERROR(prefix_unknown);
28060c16b537SWarner Losh     memset(params, 0, sizeof(*params));
28070c16b537SWarner Losh     params->windowLog = (((const BYTE*)src)[4] & 15) + ZSTDv05_WINDOWLOG_ABSOLUTEMIN;
28080c16b537SWarner Losh     if ((((const BYTE*)src)[4] >> 4) != 0) return ERROR(frameParameter_unsupported);   /* reserved bits */
28090c16b537SWarner Losh     return 0;
28100c16b537SWarner Losh }
28110c16b537SWarner Losh 
28120c16b537SWarner Losh /** ZSTDv05_decodeFrameHeader_Part2() :
28130c16b537SWarner Losh *   decode the full Frame Header.
28140c16b537SWarner Losh *   srcSize must be the size provided by ZSTDv05_decodeFrameHeader_Part1().
28150c16b537SWarner Losh *   @return : 0, or an error code, which can be tested using ZSTDv05_isError() */
28160c16b537SWarner Losh static size_t ZSTDv05_decodeFrameHeader_Part2(ZSTDv05_DCtx* zc, const void* src, size_t srcSize)
28170c16b537SWarner Losh {
28180c16b537SWarner Losh     size_t result;
28190c16b537SWarner Losh     if (srcSize != zc->headerSize)
28200c16b537SWarner Losh         return ERROR(srcSize_wrong);
28210c16b537SWarner Losh     result = ZSTDv05_getFrameParams(&(zc->params), src, srcSize);
28220c16b537SWarner Losh     if ((MEM_32bits()) && (zc->params.windowLog > 25)) return ERROR(frameParameter_unsupported);
28230c16b537SWarner Losh     return result;
28240c16b537SWarner Losh }
28250c16b537SWarner Losh 
28260c16b537SWarner Losh 
2827*0f743729SConrad Meyer static size_t ZSTDv05_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr)
28280c16b537SWarner Losh {
28290c16b537SWarner Losh     const BYTE* const in = (const BYTE* const)src;
28300c16b537SWarner Losh     BYTE headerFlags;
28310c16b537SWarner Losh     U32 cSize;
28320c16b537SWarner Losh 
28330c16b537SWarner Losh     if (srcSize < 3)
28340c16b537SWarner Losh         return ERROR(srcSize_wrong);
28350c16b537SWarner Losh 
28360c16b537SWarner Losh     headerFlags = *in;
28370c16b537SWarner Losh     cSize = in[2] + (in[1]<<8) + ((in[0] & 7)<<16);
28380c16b537SWarner Losh 
28390c16b537SWarner Losh     bpPtr->blockType = (blockType_t)(headerFlags >> 6);
28400c16b537SWarner Losh     bpPtr->origSize = (bpPtr->blockType == bt_rle) ? cSize : 0;
28410c16b537SWarner Losh 
28420c16b537SWarner Losh     if (bpPtr->blockType == bt_end) return 0;
28430c16b537SWarner Losh     if (bpPtr->blockType == bt_rle) return 1;
28440c16b537SWarner Losh     return cSize;
28450c16b537SWarner Losh }
28460c16b537SWarner Losh 
28470c16b537SWarner Losh 
28480c16b537SWarner Losh static size_t ZSTDv05_copyRawBlock(void* dst, size_t maxDstSize, const void* src, size_t srcSize)
28490c16b537SWarner Losh {
2850*0f743729SConrad Meyer     if (dst==NULL) return ERROR(dstSize_tooSmall);
28510c16b537SWarner Losh     if (srcSize > maxDstSize) return ERROR(dstSize_tooSmall);
28520c16b537SWarner Losh     memcpy(dst, src, srcSize);
28530c16b537SWarner Losh     return srcSize;
28540c16b537SWarner Losh }
28550c16b537SWarner Losh 
28560c16b537SWarner Losh 
28570c16b537SWarner Losh /*! ZSTDv05_decodeLiteralsBlock() :
28580c16b537SWarner Losh     @return : nb of bytes read from src (< srcSize ) */
2859*0f743729SConrad Meyer static size_t ZSTDv05_decodeLiteralsBlock(ZSTDv05_DCtx* dctx,
28600c16b537SWarner Losh                                     const void* src, size_t srcSize)   /* note : srcSize < BLOCKSIZE */
28610c16b537SWarner Losh {
28620c16b537SWarner Losh     const BYTE* const istart = (const BYTE*) src;
28630c16b537SWarner Losh 
28640c16b537SWarner Losh     /* any compressed block with literals segment must be at least this size */
28650c16b537SWarner Losh     if (srcSize < MIN_CBLOCK_SIZE) return ERROR(corruption_detected);
28660c16b537SWarner Losh 
28670c16b537SWarner Losh     switch(istart[0]>> 6)
28680c16b537SWarner Losh     {
28690c16b537SWarner Losh     case IS_HUFv05:
28700c16b537SWarner Losh         {
28710c16b537SWarner Losh             size_t litSize, litCSize, singleStream=0;
28720c16b537SWarner Losh             U32 lhSize = ((istart[0]) >> 4) & 3;
28730c16b537SWarner Losh             if (srcSize < 5) return ERROR(corruption_detected);   /* srcSize >= MIN_CBLOCK_SIZE == 3; here we need up to 5 for case 3 */
28740c16b537SWarner Losh             switch(lhSize)
28750c16b537SWarner Losh             {
28760c16b537SWarner Losh             case 0: case 1: default:   /* note : default is impossible, since lhSize into [0..3] */
28770c16b537SWarner Losh                 /* 2 - 2 - 10 - 10 */
28780c16b537SWarner Losh                 lhSize=3;
28790c16b537SWarner Losh                 singleStream = istart[0] & 16;
28800c16b537SWarner Losh                 litSize  = ((istart[0] & 15) << 6) + (istart[1] >> 2);
28810c16b537SWarner Losh                 litCSize = ((istart[1] &  3) << 8) + istart[2];
28820c16b537SWarner Losh                 break;
28830c16b537SWarner Losh             case 2:
28840c16b537SWarner Losh                 /* 2 - 2 - 14 - 14 */
28850c16b537SWarner Losh                 lhSize=4;
28860c16b537SWarner Losh                 litSize  = ((istart[0] & 15) << 10) + (istart[1] << 2) + (istart[2] >> 6);
28870c16b537SWarner Losh                 litCSize = ((istart[2] & 63) <<  8) + istart[3];
28880c16b537SWarner Losh                 break;
28890c16b537SWarner Losh             case 3:
28900c16b537SWarner Losh                 /* 2 - 2 - 18 - 18 */
28910c16b537SWarner Losh                 lhSize=5;
28920c16b537SWarner Losh                 litSize  = ((istart[0] & 15) << 14) + (istart[1] << 6) + (istart[2] >> 2);
28930c16b537SWarner Losh                 litCSize = ((istart[2] &  3) << 16) + (istart[3] << 8) + istart[4];
28940c16b537SWarner Losh                 break;
28950c16b537SWarner Losh             }
28960c16b537SWarner Losh             if (litSize > BLOCKSIZE) return ERROR(corruption_detected);
28970c16b537SWarner Losh             if (litCSize + lhSize > srcSize) return ERROR(corruption_detected);
28980c16b537SWarner Losh 
28990c16b537SWarner Losh             if (HUFv05_isError(singleStream ?
29000c16b537SWarner Losh                             HUFv05_decompress1X2(dctx->litBuffer, litSize, istart+lhSize, litCSize) :
29010c16b537SWarner Losh                             HUFv05_decompress   (dctx->litBuffer, litSize, istart+lhSize, litCSize) ))
29020c16b537SWarner Losh                 return ERROR(corruption_detected);
29030c16b537SWarner Losh 
29040c16b537SWarner Losh             dctx->litPtr = dctx->litBuffer;
29050c16b537SWarner Losh             dctx->litSize = litSize;
29060c16b537SWarner Losh             memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH);
29070c16b537SWarner Losh             return litCSize + lhSize;
29080c16b537SWarner Losh         }
29090c16b537SWarner Losh     case IS_PCH:
29100c16b537SWarner Losh         {
29110c16b537SWarner Losh             size_t errorCode;
29120c16b537SWarner Losh             size_t litSize, litCSize;
29130c16b537SWarner Losh             U32 lhSize = ((istart[0]) >> 4) & 3;
29140c16b537SWarner Losh             if (lhSize != 1)  /* only case supported for now : small litSize, single stream */
29150c16b537SWarner Losh                 return ERROR(corruption_detected);
29160c16b537SWarner Losh             if (!dctx->flagStaticTables)
29170c16b537SWarner Losh                 return ERROR(dictionary_corrupted);
29180c16b537SWarner Losh 
29190c16b537SWarner Losh             /* 2 - 2 - 10 - 10 */
29200c16b537SWarner Losh             lhSize=3;
29210c16b537SWarner Losh             litSize  = ((istart[0] & 15) << 6) + (istart[1] >> 2);
29220c16b537SWarner Losh             litCSize = ((istart[1] &  3) << 8) + istart[2];
29230c16b537SWarner Losh             if (litCSize + lhSize > srcSize) return ERROR(corruption_detected);
29240c16b537SWarner Losh 
29250c16b537SWarner Losh             errorCode = HUFv05_decompress1X4_usingDTable(dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->hufTableX4);
29260c16b537SWarner Losh             if (HUFv05_isError(errorCode)) return ERROR(corruption_detected);
29270c16b537SWarner Losh 
29280c16b537SWarner Losh             dctx->litPtr = dctx->litBuffer;
29290c16b537SWarner Losh             dctx->litSize = litSize;
29300c16b537SWarner Losh             memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH);
29310c16b537SWarner Losh             return litCSize + lhSize;
29320c16b537SWarner Losh         }
29330c16b537SWarner Losh     case IS_RAW:
29340c16b537SWarner Losh         {
29350c16b537SWarner Losh             size_t litSize;
29360c16b537SWarner Losh             U32 lhSize = ((istart[0]) >> 4) & 3;
29370c16b537SWarner Losh             switch(lhSize)
29380c16b537SWarner Losh             {
29390c16b537SWarner Losh             case 0: case 1: default:   /* note : default is impossible, since lhSize into [0..3] */
29400c16b537SWarner Losh                 lhSize=1;
29410c16b537SWarner Losh                 litSize = istart[0] & 31;
29420c16b537SWarner Losh                 break;
29430c16b537SWarner Losh             case 2:
29440c16b537SWarner Losh                 litSize = ((istart[0] & 15) << 8) + istart[1];
29450c16b537SWarner Losh                 break;
29460c16b537SWarner Losh             case 3:
29470c16b537SWarner Losh                 litSize = ((istart[0] & 15) << 16) + (istart[1] << 8) + istart[2];
29480c16b537SWarner Losh                 break;
29490c16b537SWarner Losh             }
29500c16b537SWarner Losh 
29510c16b537SWarner Losh             if (lhSize+litSize+WILDCOPY_OVERLENGTH > srcSize) {  /* risk reading beyond src buffer with wildcopy */
29520c16b537SWarner Losh                 if (litSize+lhSize > srcSize) return ERROR(corruption_detected);
29530c16b537SWarner Losh                 memcpy(dctx->litBuffer, istart+lhSize, litSize);
29540c16b537SWarner Losh                 dctx->litPtr = dctx->litBuffer;
29550c16b537SWarner Losh                 dctx->litSize = litSize;
29560c16b537SWarner Losh                 memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH);
29570c16b537SWarner Losh                 return lhSize+litSize;
29580c16b537SWarner Losh             }
29590c16b537SWarner Losh             /* direct reference into compressed stream */
29600c16b537SWarner Losh             dctx->litPtr = istart+lhSize;
29610c16b537SWarner Losh             dctx->litSize = litSize;
29620c16b537SWarner Losh             return lhSize+litSize;
29630c16b537SWarner Losh         }
29640c16b537SWarner Losh     case IS_RLE:
29650c16b537SWarner Losh         {
29660c16b537SWarner Losh             size_t litSize;
29670c16b537SWarner Losh             U32 lhSize = ((istart[0]) >> 4) & 3;
29680c16b537SWarner Losh             switch(lhSize)
29690c16b537SWarner Losh             {
29700c16b537SWarner Losh             case 0: case 1: default:   /* note : default is impossible, since lhSize into [0..3] */
29710c16b537SWarner Losh                 lhSize = 1;
29720c16b537SWarner Losh                 litSize = istart[0] & 31;
29730c16b537SWarner Losh                 break;
29740c16b537SWarner Losh             case 2:
29750c16b537SWarner Losh                 litSize = ((istart[0] & 15) << 8) + istart[1];
29760c16b537SWarner Losh                 break;
29770c16b537SWarner Losh             case 3:
29780c16b537SWarner Losh                 litSize = ((istart[0] & 15) << 16) + (istart[1] << 8) + istart[2];
29790c16b537SWarner Losh                 if (srcSize<4) return ERROR(corruption_detected);   /* srcSize >= MIN_CBLOCK_SIZE == 3; here we need lhSize+1 = 4 */
29800c16b537SWarner Losh                 break;
29810c16b537SWarner Losh             }
29820c16b537SWarner Losh             if (litSize > BLOCKSIZE) return ERROR(corruption_detected);
29830c16b537SWarner Losh             memset(dctx->litBuffer, istart[lhSize], litSize + WILDCOPY_OVERLENGTH);
29840c16b537SWarner Losh             dctx->litPtr = dctx->litBuffer;
29850c16b537SWarner Losh             dctx->litSize = litSize;
29860c16b537SWarner Losh             return lhSize+1;
29870c16b537SWarner Losh         }
29880c16b537SWarner Losh     default:
29890c16b537SWarner Losh         return ERROR(corruption_detected);   /* impossible */
29900c16b537SWarner Losh     }
29910c16b537SWarner Losh }
29920c16b537SWarner Losh 
29930c16b537SWarner Losh 
2994*0f743729SConrad Meyer static size_t ZSTDv05_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* dumpsLengthPtr,
29950c16b537SWarner Losh                          FSEv05_DTable* DTableLL, FSEv05_DTable* DTableML, FSEv05_DTable* DTableOffb,
29960c16b537SWarner Losh                          const void* src, size_t srcSize, U32 flagStaticTable)
29970c16b537SWarner Losh {
29980c16b537SWarner Losh     const BYTE* const istart = (const BYTE* const)src;
29990c16b537SWarner Losh     const BYTE* ip = istart;
30000c16b537SWarner Losh     const BYTE* const iend = istart + srcSize;
30010c16b537SWarner Losh     U32 LLtype, Offtype, MLtype;
30020c16b537SWarner Losh     U32 LLlog, Offlog, MLlog;
30030c16b537SWarner Losh     size_t dumpsLength;
30040c16b537SWarner Losh 
30050c16b537SWarner Losh     /* check */
30060c16b537SWarner Losh     if (srcSize < MIN_SEQUENCES_SIZE)
30070c16b537SWarner Losh         return ERROR(srcSize_wrong);
30080c16b537SWarner Losh 
30090c16b537SWarner Losh     /* SeqHead */
30100c16b537SWarner Losh     *nbSeq = *ip++;
30110c16b537SWarner Losh     if (*nbSeq==0) return 1;
30120c16b537SWarner Losh     if (*nbSeq >= 128) {
30130c16b537SWarner Losh         if (ip >= iend) return ERROR(srcSize_wrong);
30140c16b537SWarner Losh         *nbSeq = ((nbSeq[0]-128)<<8) + *ip++;
30150c16b537SWarner Losh     }
30160c16b537SWarner Losh 
30170c16b537SWarner Losh     if (ip >= iend) return ERROR(srcSize_wrong);
30180c16b537SWarner Losh     LLtype  = *ip >> 6;
30190c16b537SWarner Losh     Offtype = (*ip >> 4) & 3;
30200c16b537SWarner Losh     MLtype  = (*ip >> 2) & 3;
30210c16b537SWarner Losh     if (*ip & 2) {
30220c16b537SWarner Losh         if (ip+3 > iend) return ERROR(srcSize_wrong);
30230c16b537SWarner Losh         dumpsLength  = ip[2];
30240c16b537SWarner Losh         dumpsLength += ip[1] << 8;
30250c16b537SWarner Losh         ip += 3;
30260c16b537SWarner Losh     } else {
30270c16b537SWarner Losh         if (ip+2 > iend) return ERROR(srcSize_wrong);
30280c16b537SWarner Losh         dumpsLength  = ip[1];
30290c16b537SWarner Losh         dumpsLength += (ip[0] & 1) << 8;
30300c16b537SWarner Losh         ip += 2;
30310c16b537SWarner Losh     }
30320c16b537SWarner Losh     *dumpsPtr = ip;
30330c16b537SWarner Losh     ip += dumpsLength;
30340c16b537SWarner Losh     *dumpsLengthPtr = dumpsLength;
30350c16b537SWarner Losh 
30360c16b537SWarner Losh     /* check */
30370c16b537SWarner Losh     if (ip > iend-3) return ERROR(srcSize_wrong); /* min : all 3 are "raw", hence no header, but at least xxLog bits per type */
30380c16b537SWarner Losh 
30390c16b537SWarner Losh     /* sequences */
30400c16b537SWarner Losh     {
30410c16b537SWarner Losh         S16 norm[MaxML+1];    /* assumption : MaxML >= MaxLL >= MaxOff */
30420c16b537SWarner Losh         size_t headerSize;
30430c16b537SWarner Losh 
30440c16b537SWarner Losh         /* Build DTables */
30450c16b537SWarner Losh         switch(LLtype)
30460c16b537SWarner Losh         {
30470c16b537SWarner Losh         case FSEv05_ENCODING_RLE :
30480c16b537SWarner Losh             LLlog = 0;
30490c16b537SWarner Losh             FSEv05_buildDTable_rle(DTableLL, *ip++);
30500c16b537SWarner Losh             break;
30510c16b537SWarner Losh         case FSEv05_ENCODING_RAW :
30520c16b537SWarner Losh             LLlog = LLbits;
30530c16b537SWarner Losh             FSEv05_buildDTable_raw(DTableLL, LLbits);
30540c16b537SWarner Losh             break;
30550c16b537SWarner Losh         case FSEv05_ENCODING_STATIC:
30560c16b537SWarner Losh             if (!flagStaticTable) return ERROR(corruption_detected);
30570c16b537SWarner Losh             break;
30580c16b537SWarner Losh         case FSEv05_ENCODING_DYNAMIC :
30590c16b537SWarner Losh         default :   /* impossible */
30600c16b537SWarner Losh             {   U32 max = MaxLL;
30610c16b537SWarner Losh                 headerSize = FSEv05_readNCount(norm, &max, &LLlog, ip, iend-ip);
30620c16b537SWarner Losh                 if (FSEv05_isError(headerSize)) return ERROR(GENERIC);
30630c16b537SWarner Losh                 if (LLlog > LLFSEv05Log) return ERROR(corruption_detected);
30640c16b537SWarner Losh                 ip += headerSize;
30650c16b537SWarner Losh                 FSEv05_buildDTable(DTableLL, norm, max, LLlog);
30660c16b537SWarner Losh         }   }
30670c16b537SWarner Losh 
30680c16b537SWarner Losh         switch(Offtype)
30690c16b537SWarner Losh         {
30700c16b537SWarner Losh         case FSEv05_ENCODING_RLE :
30710c16b537SWarner Losh             Offlog = 0;
30720c16b537SWarner Losh             if (ip > iend-2) return ERROR(srcSize_wrong);   /* min : "raw", hence no header, but at least xxLog bits */
30730c16b537SWarner Losh             FSEv05_buildDTable_rle(DTableOffb, *ip++ & MaxOff); /* if *ip > MaxOff, data is corrupted */
30740c16b537SWarner Losh             break;
30750c16b537SWarner Losh         case FSEv05_ENCODING_RAW :
30760c16b537SWarner Losh             Offlog = Offbits;
30770c16b537SWarner Losh             FSEv05_buildDTable_raw(DTableOffb, Offbits);
30780c16b537SWarner Losh             break;
30790c16b537SWarner Losh         case FSEv05_ENCODING_STATIC:
30800c16b537SWarner Losh             if (!flagStaticTable) return ERROR(corruption_detected);
30810c16b537SWarner Losh             break;
30820c16b537SWarner Losh         case FSEv05_ENCODING_DYNAMIC :
30830c16b537SWarner Losh         default :   /* impossible */
30840c16b537SWarner Losh             {   U32 max = MaxOff;
30850c16b537SWarner Losh                 headerSize = FSEv05_readNCount(norm, &max, &Offlog, ip, iend-ip);
30860c16b537SWarner Losh                 if (FSEv05_isError(headerSize)) return ERROR(GENERIC);
30870c16b537SWarner Losh                 if (Offlog > OffFSEv05Log) return ERROR(corruption_detected);
30880c16b537SWarner Losh                 ip += headerSize;
30890c16b537SWarner Losh                 FSEv05_buildDTable(DTableOffb, norm, max, Offlog);
30900c16b537SWarner Losh         }   }
30910c16b537SWarner Losh 
30920c16b537SWarner Losh         switch(MLtype)
30930c16b537SWarner Losh         {
30940c16b537SWarner Losh         case FSEv05_ENCODING_RLE :
30950c16b537SWarner Losh             MLlog = 0;
30960c16b537SWarner Losh             if (ip > iend-2) return ERROR(srcSize_wrong); /* min : "raw", hence no header, but at least xxLog bits */
30970c16b537SWarner Losh             FSEv05_buildDTable_rle(DTableML, *ip++);
30980c16b537SWarner Losh             break;
30990c16b537SWarner Losh         case FSEv05_ENCODING_RAW :
31000c16b537SWarner Losh             MLlog = MLbits;
31010c16b537SWarner Losh             FSEv05_buildDTable_raw(DTableML, MLbits);
31020c16b537SWarner Losh             break;
31030c16b537SWarner Losh         case FSEv05_ENCODING_STATIC:
31040c16b537SWarner Losh             if (!flagStaticTable) return ERROR(corruption_detected);
31050c16b537SWarner Losh             break;
31060c16b537SWarner Losh         case FSEv05_ENCODING_DYNAMIC :
31070c16b537SWarner Losh         default :   /* impossible */
31080c16b537SWarner Losh             {   U32 max = MaxML;
31090c16b537SWarner Losh                 headerSize = FSEv05_readNCount(norm, &max, &MLlog, ip, iend-ip);
31100c16b537SWarner Losh                 if (FSEv05_isError(headerSize)) return ERROR(GENERIC);
31110c16b537SWarner Losh                 if (MLlog > MLFSEv05Log) return ERROR(corruption_detected);
31120c16b537SWarner Losh                 ip += headerSize;
31130c16b537SWarner Losh                 FSEv05_buildDTable(DTableML, norm, max, MLlog);
31140c16b537SWarner Losh     }   }   }
31150c16b537SWarner Losh 
31160c16b537SWarner Losh     return ip-istart;
31170c16b537SWarner Losh }
31180c16b537SWarner Losh 
31190c16b537SWarner Losh 
31200c16b537SWarner Losh typedef struct {
31210c16b537SWarner Losh     size_t litLength;
31220c16b537SWarner Losh     size_t matchLength;
31230c16b537SWarner Losh     size_t offset;
31240c16b537SWarner Losh } seq_t;
31250c16b537SWarner Losh 
31260c16b537SWarner Losh typedef struct {
31270c16b537SWarner Losh     BITv05_DStream_t DStream;
31280c16b537SWarner Losh     FSEv05_DState_t stateLL;
31290c16b537SWarner Losh     FSEv05_DState_t stateOffb;
31300c16b537SWarner Losh     FSEv05_DState_t stateML;
31310c16b537SWarner Losh     size_t prevOffset;
31320c16b537SWarner Losh     const BYTE* dumps;
31330c16b537SWarner Losh     const BYTE* dumpsEnd;
31340c16b537SWarner Losh } seqState_t;
31350c16b537SWarner Losh 
31360c16b537SWarner Losh 
31370c16b537SWarner Losh 
31380c16b537SWarner Losh static void ZSTDv05_decodeSequence(seq_t* seq, seqState_t* seqState)
31390c16b537SWarner Losh {
31400c16b537SWarner Losh     size_t litLength;
31410c16b537SWarner Losh     size_t prevOffset;
31420c16b537SWarner Losh     size_t offset;
31430c16b537SWarner Losh     size_t matchLength;
31440c16b537SWarner Losh     const BYTE* dumps = seqState->dumps;
31450c16b537SWarner Losh     const BYTE* const de = seqState->dumpsEnd;
31460c16b537SWarner Losh 
31470c16b537SWarner Losh     /* Literal length */
31480c16b537SWarner Losh     litLength = FSEv05_peakSymbol(&(seqState->stateLL));
31490c16b537SWarner Losh     prevOffset = litLength ? seq->offset : seqState->prevOffset;
31500c16b537SWarner Losh     if (litLength == MaxLL) {
31510c16b537SWarner Losh         U32 add = *dumps++;
31520c16b537SWarner Losh         if (add < 255) litLength += add;
31530c16b537SWarner Losh         else {
31540c16b537SWarner Losh             litLength = MEM_readLE32(dumps) & 0xFFFFFF;  /* no risk : dumps is always followed by seq tables > 1 byte */
31550c16b537SWarner Losh             if (litLength&1) litLength>>=1, dumps += 3;
31560c16b537SWarner Losh             else litLength = (U16)(litLength)>>1, dumps += 2;
31570c16b537SWarner Losh         }
31580c16b537SWarner Losh         if (dumps > de) { litLength = MaxLL+255; }  /* late correction, to avoid using uninitialized memory */
31590c16b537SWarner Losh         if (dumps >= de) { dumps = de-1; }  /* late correction, to avoid read overflow (data is now corrupted anyway) */
31600c16b537SWarner Losh     }
31610c16b537SWarner Losh 
31620c16b537SWarner Losh     /* Offset */
31630c16b537SWarner Losh     {
31640c16b537SWarner Losh         static const U32 offsetPrefix[MaxOff+1] = {
31650c16b537SWarner Losh                 1 /*fake*/, 1, 2, 4, 8, 16, 32, 64, 128, 256,
31660c16b537SWarner Losh                 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144,
31670c16b537SWarner Losh                 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, /*fake*/ 1, 1, 1, 1, 1 };
31680c16b537SWarner Losh         U32 offsetCode = FSEv05_peakSymbol(&(seqState->stateOffb));   /* <= maxOff, by table construction */
31690c16b537SWarner Losh         U32 nbBits = offsetCode - 1;
31700c16b537SWarner Losh         if (offsetCode==0) nbBits = 0;   /* cmove */
31710c16b537SWarner Losh         offset = offsetPrefix[offsetCode] + BITv05_readBits(&(seqState->DStream), nbBits);
31720c16b537SWarner Losh         if (MEM_32bits()) BITv05_reloadDStream(&(seqState->DStream));
31730c16b537SWarner Losh         if (offsetCode==0) offset = prevOffset;   /* repcode, cmove */
31740c16b537SWarner Losh         if (offsetCode | !litLength) seqState->prevOffset = seq->offset;   /* cmove */
31750c16b537SWarner Losh         FSEv05_decodeSymbol(&(seqState->stateOffb), &(seqState->DStream));    /* update */
31760c16b537SWarner Losh     }
31770c16b537SWarner Losh 
31780c16b537SWarner Losh     /* Literal length update */
31790c16b537SWarner Losh     FSEv05_decodeSymbol(&(seqState->stateLL), &(seqState->DStream));   /* update */
31800c16b537SWarner Losh     if (MEM_32bits()) BITv05_reloadDStream(&(seqState->DStream));
31810c16b537SWarner Losh 
31820c16b537SWarner Losh     /* MatchLength */
31830c16b537SWarner Losh     matchLength = FSEv05_decodeSymbol(&(seqState->stateML), &(seqState->DStream));
31840c16b537SWarner Losh     if (matchLength == MaxML) {
31850c16b537SWarner Losh         U32 add = *dumps++;
31860c16b537SWarner Losh         if (add < 255) matchLength += add;
31870c16b537SWarner Losh         else {
31880c16b537SWarner Losh             matchLength = MEM_readLE32(dumps) & 0xFFFFFF;  /* no pb : dumps is always followed by seq tables > 1 byte */
31890c16b537SWarner Losh             if (matchLength&1) matchLength>>=1, dumps += 3;
31900c16b537SWarner Losh             else matchLength = (U16)(matchLength)>>1, dumps += 2;
31910c16b537SWarner Losh         }
31920c16b537SWarner Losh         if (dumps > de) { matchLength = MaxML+255; }  /* late correction, to avoid using uninitialized memory */
31930c16b537SWarner Losh         if (dumps >= de) { dumps = de-1; }  /* late correction, to avoid read overflow (data is now corrupted anyway) */
31940c16b537SWarner Losh     }
31950c16b537SWarner Losh     matchLength += MINMATCH;
31960c16b537SWarner Losh 
31970c16b537SWarner Losh     /* save result */
31980c16b537SWarner Losh     seq->litLength = litLength;
31990c16b537SWarner Losh     seq->offset = offset;
32000c16b537SWarner Losh     seq->matchLength = matchLength;
32010c16b537SWarner Losh     seqState->dumps = dumps;
32020c16b537SWarner Losh 
32030c16b537SWarner Losh #if 0   /* debug */
32040c16b537SWarner Losh     {
32050c16b537SWarner Losh         static U64 totalDecoded = 0;
32060c16b537SWarner Losh         printf("pos %6u : %3u literals & match %3u bytes at distance %6u \n",
32070c16b537SWarner Losh            (U32)(totalDecoded), (U32)litLength, (U32)matchLength, (U32)offset);
32080c16b537SWarner Losh         totalDecoded += litLength + matchLength;
32090c16b537SWarner Losh     }
32100c16b537SWarner Losh #endif
32110c16b537SWarner Losh }
32120c16b537SWarner Losh 
32130c16b537SWarner Losh 
32140c16b537SWarner Losh static size_t ZSTDv05_execSequence(BYTE* op,
32150c16b537SWarner Losh                                 BYTE* const oend, seq_t sequence,
32160c16b537SWarner Losh                                 const BYTE** litPtr, const BYTE* const litLimit,
32170c16b537SWarner Losh                                 const BYTE* const base, const BYTE* const vBase, const BYTE* const dictEnd)
32180c16b537SWarner Losh {
32190c16b537SWarner Losh     static const int dec32table[] = { 0, 1, 2, 1, 4, 4, 4, 4 };   /* added */
32200c16b537SWarner Losh     static const int dec64table[] = { 8, 8, 8, 7, 8, 9,10,11 };   /* substracted */
32210c16b537SWarner Losh     BYTE* const oLitEnd = op + sequence.litLength;
32220c16b537SWarner Losh     const size_t sequenceLength = sequence.litLength + sequence.matchLength;
32230c16b537SWarner Losh     BYTE* const oMatchEnd = op + sequenceLength;   /* risk : address space overflow (32-bits) */
32240c16b537SWarner Losh     BYTE* const oend_8 = oend-8;
32250c16b537SWarner Losh     const BYTE* const litEnd = *litPtr + sequence.litLength;
32260c16b537SWarner Losh     const BYTE* match = oLitEnd - sequence.offset;
32270c16b537SWarner Losh 
32280c16b537SWarner Losh     /* check */
32290c16b537SWarner Losh     if (oLitEnd > oend_8) return ERROR(dstSize_tooSmall);   /* last match must start at a minimum distance of 8 from oend */
32300c16b537SWarner Losh     if (oMatchEnd > oend) return ERROR(dstSize_tooSmall);   /* overwrite beyond dst buffer */
32310c16b537SWarner Losh     if (litEnd > litLimit) return ERROR(corruption_detected);   /* risk read beyond lit buffer */
32320c16b537SWarner Losh 
32330c16b537SWarner Losh     /* copy Literals */
32340c16b537SWarner Losh     ZSTDv05_wildcopy(op, *litPtr, sequence.litLength);   /* note : oLitEnd <= oend-8 : no risk of overwrite beyond oend */
32350c16b537SWarner Losh     op = oLitEnd;
32360c16b537SWarner Losh     *litPtr = litEnd;   /* update for next sequence */
32370c16b537SWarner Losh 
32380c16b537SWarner Losh     /* copy Match */
32390c16b537SWarner Losh     if (sequence.offset > (size_t)(oLitEnd - base)) {
32400c16b537SWarner Losh         /* offset beyond prefix */
32410c16b537SWarner Losh         if (sequence.offset > (size_t)(oLitEnd - vBase))
32420c16b537SWarner Losh             return ERROR(corruption_detected);
32430c16b537SWarner Losh         match = dictEnd - (base-match);
32440c16b537SWarner Losh         if (match + sequence.matchLength <= dictEnd) {
32450c16b537SWarner Losh             memmove(oLitEnd, match, sequence.matchLength);
32460c16b537SWarner Losh             return sequenceLength;
32470c16b537SWarner Losh         }
32480c16b537SWarner Losh         /* span extDict & currentPrefixSegment */
32490c16b537SWarner Losh         {
32500c16b537SWarner Losh             size_t length1 = dictEnd - match;
32510c16b537SWarner Losh             memmove(oLitEnd, match, length1);
32520c16b537SWarner Losh             op = oLitEnd + length1;
32530c16b537SWarner Losh             sequence.matchLength -= length1;
32540c16b537SWarner Losh             match = base;
32550c16b537SWarner Losh             if (op > oend_8 || sequence.matchLength < MINMATCH) {
32560c16b537SWarner Losh               while (op < oMatchEnd) *op++ = *match++;
32570c16b537SWarner Losh               return sequenceLength;
32580c16b537SWarner Losh             }
32590c16b537SWarner Losh     }   }
32600c16b537SWarner Losh     /* Requirement: op <= oend_8 */
32610c16b537SWarner Losh 
32620c16b537SWarner Losh     /* match within prefix */
32630c16b537SWarner Losh     if (sequence.offset < 8) {
32640c16b537SWarner Losh         /* close range match, overlap */
32650c16b537SWarner Losh         const int sub2 = dec64table[sequence.offset];
32660c16b537SWarner Losh         op[0] = match[0];
32670c16b537SWarner Losh         op[1] = match[1];
32680c16b537SWarner Losh         op[2] = match[2];
32690c16b537SWarner Losh         op[3] = match[3];
32700c16b537SWarner Losh         match += dec32table[sequence.offset];
32710c16b537SWarner Losh         ZSTDv05_copy4(op+4, match);
32720c16b537SWarner Losh         match -= sub2;
32730c16b537SWarner Losh     } else {
32740c16b537SWarner Losh         ZSTDv05_copy8(op, match);
32750c16b537SWarner Losh     }
32760c16b537SWarner Losh     op += 8; match += 8;
32770c16b537SWarner Losh 
32780c16b537SWarner Losh     if (oMatchEnd > oend-(16-MINMATCH)) {
32790c16b537SWarner Losh         if (op < oend_8) {
32800c16b537SWarner Losh             ZSTDv05_wildcopy(op, match, oend_8 - op);
32810c16b537SWarner Losh             match += oend_8 - op;
32820c16b537SWarner Losh             op = oend_8;
32830c16b537SWarner Losh         }
32840c16b537SWarner Losh         while (op < oMatchEnd)
32850c16b537SWarner Losh             *op++ = *match++;
32860c16b537SWarner Losh     } else {
32870c16b537SWarner Losh         ZSTDv05_wildcopy(op, match, (ptrdiff_t)sequence.matchLength-8);   /* works even if matchLength < 8 */
32880c16b537SWarner Losh     }
32890c16b537SWarner Losh     return sequenceLength;
32900c16b537SWarner Losh }
32910c16b537SWarner Losh 
32920c16b537SWarner Losh 
32930c16b537SWarner Losh static size_t ZSTDv05_decompressSequences(
32940c16b537SWarner Losh                                ZSTDv05_DCtx* dctx,
32950c16b537SWarner Losh                                void* dst, size_t maxDstSize,
32960c16b537SWarner Losh                          const void* seqStart, size_t seqSize)
32970c16b537SWarner Losh {
32980c16b537SWarner Losh     const BYTE* ip = (const BYTE*)seqStart;
32990c16b537SWarner Losh     const BYTE* const iend = ip + seqSize;
33000c16b537SWarner Losh     BYTE* const ostart = (BYTE* const)dst;
33010c16b537SWarner Losh     BYTE* op = ostart;
33020c16b537SWarner Losh     BYTE* const oend = ostart + maxDstSize;
3303*0f743729SConrad Meyer     size_t errorCode, dumpsLength=0;
33040c16b537SWarner Losh     const BYTE* litPtr = dctx->litPtr;
33050c16b537SWarner Losh     const BYTE* const litEnd = litPtr + dctx->litSize;
3306*0f743729SConrad Meyer     int nbSeq=0;
3307*0f743729SConrad Meyer     const BYTE* dumps = NULL;
33080c16b537SWarner Losh     U32* DTableLL = dctx->LLTable;
33090c16b537SWarner Losh     U32* DTableML = dctx->MLTable;
33100c16b537SWarner Losh     U32* DTableOffb = dctx->OffTable;
33110c16b537SWarner Losh     const BYTE* const base = (const BYTE*) (dctx->base);
33120c16b537SWarner Losh     const BYTE* const vBase = (const BYTE*) (dctx->vBase);
33130c16b537SWarner Losh     const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd);
33140c16b537SWarner Losh 
33150c16b537SWarner Losh     /* Build Decoding Tables */
33160c16b537SWarner Losh     errorCode = ZSTDv05_decodeSeqHeaders(&nbSeq, &dumps, &dumpsLength,
33170c16b537SWarner Losh                                       DTableLL, DTableML, DTableOffb,
33180c16b537SWarner Losh                                       ip, seqSize, dctx->flagStaticTables);
33190c16b537SWarner Losh     if (ZSTDv05_isError(errorCode)) return errorCode;
33200c16b537SWarner Losh     ip += errorCode;
33210c16b537SWarner Losh 
33220c16b537SWarner Losh     /* Regen sequences */
33230c16b537SWarner Losh     if (nbSeq) {
33240c16b537SWarner Losh         seq_t sequence;
33250c16b537SWarner Losh         seqState_t seqState;
33260c16b537SWarner Losh 
33270c16b537SWarner Losh         memset(&sequence, 0, sizeof(sequence));
33280c16b537SWarner Losh         sequence.offset = REPCODE_STARTVALUE;
33290c16b537SWarner Losh         seqState.dumps = dumps;
33300c16b537SWarner Losh         seqState.dumpsEnd = dumps + dumpsLength;
33310c16b537SWarner Losh         seqState.prevOffset = REPCODE_STARTVALUE;
33320c16b537SWarner Losh         errorCode = BITv05_initDStream(&(seqState.DStream), ip, iend-ip);
33330c16b537SWarner Losh         if (ERR_isError(errorCode)) return ERROR(corruption_detected);
33340c16b537SWarner Losh         FSEv05_initDState(&(seqState.stateLL), &(seqState.DStream), DTableLL);
33350c16b537SWarner Losh         FSEv05_initDState(&(seqState.stateOffb), &(seqState.DStream), DTableOffb);
33360c16b537SWarner Losh         FSEv05_initDState(&(seqState.stateML), &(seqState.DStream), DTableML);
33370c16b537SWarner Losh 
33380c16b537SWarner Losh         for ( ; (BITv05_reloadDStream(&(seqState.DStream)) <= BITv05_DStream_completed) && nbSeq ; ) {
33390c16b537SWarner Losh             size_t oneSeqSize;
33400c16b537SWarner Losh             nbSeq--;
33410c16b537SWarner Losh             ZSTDv05_decodeSequence(&sequence, &seqState);
33420c16b537SWarner Losh             oneSeqSize = ZSTDv05_execSequence(op, oend, sequence, &litPtr, litEnd, base, vBase, dictEnd);
33430c16b537SWarner Losh             if (ZSTDv05_isError(oneSeqSize)) return oneSeqSize;
33440c16b537SWarner Losh             op += oneSeqSize;
33450c16b537SWarner Losh         }
33460c16b537SWarner Losh 
33470c16b537SWarner Losh         /* check if reached exact end */
33480c16b537SWarner Losh         if (nbSeq) return ERROR(corruption_detected);
33490c16b537SWarner Losh     }
33500c16b537SWarner Losh 
33510c16b537SWarner Losh     /* last literal segment */
33520c16b537SWarner Losh     {
33530c16b537SWarner Losh         size_t lastLLSize = litEnd - litPtr;
33540c16b537SWarner Losh         if (litPtr > litEnd) return ERROR(corruption_detected);   /* too many literals already used */
33550c16b537SWarner Losh         if (op+lastLLSize > oend) return ERROR(dstSize_tooSmall);
33560c16b537SWarner Losh         memcpy(op, litPtr, lastLLSize);
33570c16b537SWarner Losh         op += lastLLSize;
33580c16b537SWarner Losh     }
33590c16b537SWarner Losh 
33600c16b537SWarner Losh     return op-ostart;
33610c16b537SWarner Losh }
33620c16b537SWarner Losh 
33630c16b537SWarner Losh 
33640c16b537SWarner Losh static void ZSTDv05_checkContinuity(ZSTDv05_DCtx* dctx, const void* dst)
33650c16b537SWarner Losh {
33660c16b537SWarner Losh     if (dst != dctx->previousDstEnd) {   /* not contiguous */
33670c16b537SWarner Losh         dctx->dictEnd = dctx->previousDstEnd;
33680c16b537SWarner Losh         dctx->vBase = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->base));
33690c16b537SWarner Losh         dctx->base = dst;
33700c16b537SWarner Losh         dctx->previousDstEnd = dst;
33710c16b537SWarner Losh     }
33720c16b537SWarner Losh }
33730c16b537SWarner Losh 
33740c16b537SWarner Losh 
33750c16b537SWarner Losh static size_t ZSTDv05_decompressBlock_internal(ZSTDv05_DCtx* dctx,
33760c16b537SWarner Losh                             void* dst, size_t dstCapacity,
33770c16b537SWarner Losh                       const void* src, size_t srcSize)
33780c16b537SWarner Losh {   /* blockType == blockCompressed */
33790c16b537SWarner Losh     const BYTE* ip = (const BYTE*)src;
33800c16b537SWarner Losh     size_t litCSize;
33810c16b537SWarner Losh 
33820c16b537SWarner Losh     if (srcSize >= BLOCKSIZE) return ERROR(srcSize_wrong);
33830c16b537SWarner Losh 
33840c16b537SWarner Losh     /* Decode literals sub-block */
33850c16b537SWarner Losh     litCSize = ZSTDv05_decodeLiteralsBlock(dctx, src, srcSize);
33860c16b537SWarner Losh     if (ZSTDv05_isError(litCSize)) return litCSize;
33870c16b537SWarner Losh     ip += litCSize;
33880c16b537SWarner Losh     srcSize -= litCSize;
33890c16b537SWarner Losh 
33900c16b537SWarner Losh     return ZSTDv05_decompressSequences(dctx, dst, dstCapacity, ip, srcSize);
33910c16b537SWarner Losh }
33920c16b537SWarner Losh 
33930c16b537SWarner Losh 
33940c16b537SWarner Losh size_t ZSTDv05_decompressBlock(ZSTDv05_DCtx* dctx,
33950c16b537SWarner Losh                             void* dst, size_t dstCapacity,
33960c16b537SWarner Losh                       const void* src, size_t srcSize)
33970c16b537SWarner Losh {
33980c16b537SWarner Losh     ZSTDv05_checkContinuity(dctx, dst);
33990c16b537SWarner Losh     return ZSTDv05_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize);
34000c16b537SWarner Losh }
34010c16b537SWarner Losh 
34020c16b537SWarner Losh 
34030c16b537SWarner Losh /*! ZSTDv05_decompress_continueDCtx
34040c16b537SWarner Losh *   dctx must have been properly initialized */
34050c16b537SWarner Losh static size_t ZSTDv05_decompress_continueDCtx(ZSTDv05_DCtx* dctx,
34060c16b537SWarner Losh                                  void* dst, size_t maxDstSize,
34070c16b537SWarner Losh                                  const void* src, size_t srcSize)
34080c16b537SWarner Losh {
34090c16b537SWarner Losh     const BYTE* ip = (const BYTE*)src;
34100c16b537SWarner Losh     const BYTE* iend = ip + srcSize;
34110c16b537SWarner Losh     BYTE* const ostart = (BYTE* const)dst;
34120c16b537SWarner Losh     BYTE* op = ostart;
34130c16b537SWarner Losh     BYTE* const oend = ostart + maxDstSize;
34140c16b537SWarner Losh     size_t remainingSize = srcSize;
34150c16b537SWarner Losh     blockProperties_t blockProperties;
3416*0f743729SConrad Meyer     memset(&blockProperties, 0, sizeof(blockProperties));
34170c16b537SWarner Losh 
34180c16b537SWarner Losh     /* Frame Header */
3419*0f743729SConrad Meyer     {   size_t frameHeaderSize;
34200c16b537SWarner Losh         if (srcSize < ZSTDv05_frameHeaderSize_min+ZSTDv05_blockHeaderSize) return ERROR(srcSize_wrong);
34210c16b537SWarner Losh         frameHeaderSize = ZSTDv05_decodeFrameHeader_Part1(dctx, src, ZSTDv05_frameHeaderSize_min);
34220c16b537SWarner Losh         if (ZSTDv05_isError(frameHeaderSize)) return frameHeaderSize;
34230c16b537SWarner Losh         if (srcSize < frameHeaderSize+ZSTDv05_blockHeaderSize) return ERROR(srcSize_wrong);
34240c16b537SWarner Losh         ip += frameHeaderSize; remainingSize -= frameHeaderSize;
34250c16b537SWarner Losh         frameHeaderSize = ZSTDv05_decodeFrameHeader_Part2(dctx, src, frameHeaderSize);
34260c16b537SWarner Losh         if (ZSTDv05_isError(frameHeaderSize)) return frameHeaderSize;
34270c16b537SWarner Losh     }
34280c16b537SWarner Losh 
34290c16b537SWarner Losh     /* Loop on each block */
34300c16b537SWarner Losh     while (1)
34310c16b537SWarner Losh     {
34320c16b537SWarner Losh         size_t decodedSize=0;
34330c16b537SWarner Losh         size_t cBlockSize = ZSTDv05_getcBlockSize(ip, iend-ip, &blockProperties);
34340c16b537SWarner Losh         if (ZSTDv05_isError(cBlockSize)) return cBlockSize;
34350c16b537SWarner Losh 
34360c16b537SWarner Losh         ip += ZSTDv05_blockHeaderSize;
34370c16b537SWarner Losh         remainingSize -= ZSTDv05_blockHeaderSize;
34380c16b537SWarner Losh         if (cBlockSize > remainingSize) return ERROR(srcSize_wrong);
34390c16b537SWarner Losh 
34400c16b537SWarner Losh         switch(blockProperties.blockType)
34410c16b537SWarner Losh         {
34420c16b537SWarner Losh         case bt_compressed:
34430c16b537SWarner Losh             decodedSize = ZSTDv05_decompressBlock_internal(dctx, op, oend-op, ip, cBlockSize);
34440c16b537SWarner Losh             break;
34450c16b537SWarner Losh         case bt_raw :
34460c16b537SWarner Losh             decodedSize = ZSTDv05_copyRawBlock(op, oend-op, ip, cBlockSize);
34470c16b537SWarner Losh             break;
34480c16b537SWarner Losh         case bt_rle :
34490c16b537SWarner Losh             return ERROR(GENERIC);   /* not yet supported */
34500c16b537SWarner Losh             break;
34510c16b537SWarner Losh         case bt_end :
34520c16b537SWarner Losh             /* end of frame */
34530c16b537SWarner Losh             if (remainingSize) return ERROR(srcSize_wrong);
34540c16b537SWarner Losh             break;
34550c16b537SWarner Losh         default:
34560c16b537SWarner Losh             return ERROR(GENERIC);   /* impossible */
34570c16b537SWarner Losh         }
34580c16b537SWarner Losh         if (cBlockSize == 0) break;   /* bt_end */
34590c16b537SWarner Losh 
34600c16b537SWarner Losh         if (ZSTDv05_isError(decodedSize)) return decodedSize;
34610c16b537SWarner Losh         op += decodedSize;
34620c16b537SWarner Losh         ip += cBlockSize;
34630c16b537SWarner Losh         remainingSize -= cBlockSize;
34640c16b537SWarner Losh     }
34650c16b537SWarner Losh 
34660c16b537SWarner Losh     return op-ostart;
34670c16b537SWarner Losh }
34680c16b537SWarner Losh 
34690c16b537SWarner Losh 
34700c16b537SWarner Losh size_t ZSTDv05_decompress_usingPreparedDCtx(ZSTDv05_DCtx* dctx, const ZSTDv05_DCtx* refDCtx,
34710c16b537SWarner Losh                                          void* dst, size_t maxDstSize,
34720c16b537SWarner Losh                                    const void* src, size_t srcSize)
34730c16b537SWarner Losh {
34740c16b537SWarner Losh     ZSTDv05_copyDCtx(dctx, refDCtx);
34750c16b537SWarner Losh     ZSTDv05_checkContinuity(dctx, dst);
34760c16b537SWarner Losh     return ZSTDv05_decompress_continueDCtx(dctx, dst, maxDstSize, src, srcSize);
34770c16b537SWarner Losh }
34780c16b537SWarner Losh 
34790c16b537SWarner Losh 
34800c16b537SWarner Losh size_t ZSTDv05_decompress_usingDict(ZSTDv05_DCtx* dctx,
34810c16b537SWarner Losh                                  void* dst, size_t maxDstSize,
34820c16b537SWarner Losh                                  const void* src, size_t srcSize,
34830c16b537SWarner Losh                                  const void* dict, size_t dictSize)
34840c16b537SWarner Losh {
34850c16b537SWarner Losh     ZSTDv05_decompressBegin_usingDict(dctx, dict, dictSize);
34860c16b537SWarner Losh     ZSTDv05_checkContinuity(dctx, dst);
34870c16b537SWarner Losh     return ZSTDv05_decompress_continueDCtx(dctx, dst, maxDstSize, src, srcSize);
34880c16b537SWarner Losh }
34890c16b537SWarner Losh 
34900c16b537SWarner Losh 
34910c16b537SWarner Losh size_t ZSTDv05_decompressDCtx(ZSTDv05_DCtx* dctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
34920c16b537SWarner Losh {
34930c16b537SWarner Losh     return ZSTDv05_decompress_usingDict(dctx, dst, maxDstSize, src, srcSize, NULL, 0);
34940c16b537SWarner Losh }
34950c16b537SWarner Losh 
34960c16b537SWarner Losh size_t ZSTDv05_decompress(void* dst, size_t maxDstSize, const void* src, size_t srcSize)
34970c16b537SWarner Losh {
34980c16b537SWarner Losh #if defined(ZSTDv05_HEAPMODE) && (ZSTDv05_HEAPMODE==1)
34990c16b537SWarner Losh     size_t regenSize;
35000c16b537SWarner Losh     ZSTDv05_DCtx* dctx = ZSTDv05_createDCtx();
35010c16b537SWarner Losh     if (dctx==NULL) return ERROR(memory_allocation);
35020c16b537SWarner Losh     regenSize = ZSTDv05_decompressDCtx(dctx, dst, maxDstSize, src, srcSize);
35030c16b537SWarner Losh     ZSTDv05_freeDCtx(dctx);
35040c16b537SWarner Losh     return regenSize;
35050c16b537SWarner Losh #else
35060c16b537SWarner Losh     ZSTDv05_DCtx dctx;
35070c16b537SWarner Losh     return ZSTDv05_decompressDCtx(&dctx, dst, maxDstSize, src, srcSize);
35080c16b537SWarner Losh #endif
35090c16b537SWarner Losh }
35100c16b537SWarner Losh 
35110c16b537SWarner Losh size_t ZSTDv05_findFrameCompressedSize(const void *src, size_t srcSize)
35120c16b537SWarner Losh {
35130c16b537SWarner Losh     const BYTE* ip = (const BYTE*)src;
35140c16b537SWarner Losh     size_t remainingSize = srcSize;
35150c16b537SWarner Losh     blockProperties_t blockProperties;
35160c16b537SWarner Losh 
35170c16b537SWarner Losh     /* Frame Header */
35180c16b537SWarner Losh     if (srcSize < ZSTDv05_frameHeaderSize_min) return ERROR(srcSize_wrong);
35190c16b537SWarner Losh     if (MEM_readLE32(src) != ZSTDv05_MAGICNUMBER) return ERROR(prefix_unknown);
35200c16b537SWarner Losh     ip += ZSTDv05_frameHeaderSize_min; remainingSize -= ZSTDv05_frameHeaderSize_min;
35210c16b537SWarner Losh 
35220c16b537SWarner Losh     /* Loop on each block */
35230c16b537SWarner Losh     while (1)
35240c16b537SWarner Losh     {
35250c16b537SWarner Losh         size_t cBlockSize = ZSTDv05_getcBlockSize(ip, remainingSize, &blockProperties);
35260c16b537SWarner Losh         if (ZSTDv05_isError(cBlockSize)) return cBlockSize;
35270c16b537SWarner Losh 
35280c16b537SWarner Losh         ip += ZSTDv05_blockHeaderSize;
35290c16b537SWarner Losh         remainingSize -= ZSTDv05_blockHeaderSize;
35300c16b537SWarner Losh         if (cBlockSize > remainingSize) return ERROR(srcSize_wrong);
35310c16b537SWarner Losh 
35320c16b537SWarner Losh         if (cBlockSize == 0) break;   /* bt_end */
35330c16b537SWarner Losh 
35340c16b537SWarner Losh         ip += cBlockSize;
35350c16b537SWarner Losh         remainingSize -= cBlockSize;
35360c16b537SWarner Losh     }
35370c16b537SWarner Losh 
35380c16b537SWarner Losh     return ip - (const BYTE*)src;
35390c16b537SWarner Losh }
35400c16b537SWarner Losh 
35410c16b537SWarner Losh /* ******************************
35420c16b537SWarner Losh *  Streaming Decompression API
35430c16b537SWarner Losh ********************************/
35440c16b537SWarner Losh size_t ZSTDv05_nextSrcSizeToDecompress(ZSTDv05_DCtx* dctx)
35450c16b537SWarner Losh {
35460c16b537SWarner Losh     return dctx->expected;
35470c16b537SWarner Losh }
35480c16b537SWarner Losh 
35490c16b537SWarner Losh size_t ZSTDv05_decompressContinue(ZSTDv05_DCtx* dctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
35500c16b537SWarner Losh {
35510c16b537SWarner Losh     /* Sanity check */
35520c16b537SWarner Losh     if (srcSize != dctx->expected) return ERROR(srcSize_wrong);
35530c16b537SWarner Losh     ZSTDv05_checkContinuity(dctx, dst);
35540c16b537SWarner Losh 
35550c16b537SWarner Losh     /* Decompress : frame header; part 1 */
35560c16b537SWarner Losh     switch (dctx->stage)
35570c16b537SWarner Losh     {
35580c16b537SWarner Losh     case ZSTDv05ds_getFrameHeaderSize :
35590c16b537SWarner Losh         /* get frame header size */
35600c16b537SWarner Losh         if (srcSize != ZSTDv05_frameHeaderSize_min) return ERROR(srcSize_wrong);   /* impossible */
35610c16b537SWarner Losh         dctx->headerSize = ZSTDv05_decodeFrameHeader_Part1(dctx, src, ZSTDv05_frameHeaderSize_min);
35620c16b537SWarner Losh         if (ZSTDv05_isError(dctx->headerSize)) return dctx->headerSize;
35630c16b537SWarner Losh         memcpy(dctx->headerBuffer, src, ZSTDv05_frameHeaderSize_min);
35640c16b537SWarner Losh         if (dctx->headerSize > ZSTDv05_frameHeaderSize_min) return ERROR(GENERIC); /* should never happen */
35650c16b537SWarner Losh         dctx->expected = 0;   /* not necessary to copy more */
35660c16b537SWarner Losh         /* fallthrough */
35670c16b537SWarner Losh     case ZSTDv05ds_decodeFrameHeader:
35680c16b537SWarner Losh         /* get frame header */
35690c16b537SWarner Losh         {   size_t const result = ZSTDv05_decodeFrameHeader_Part2(dctx, dctx->headerBuffer, dctx->headerSize);
35700c16b537SWarner Losh             if (ZSTDv05_isError(result)) return result;
35710c16b537SWarner Losh             dctx->expected = ZSTDv05_blockHeaderSize;
35720c16b537SWarner Losh             dctx->stage = ZSTDv05ds_decodeBlockHeader;
35730c16b537SWarner Losh             return 0;
35740c16b537SWarner Losh         }
35750c16b537SWarner Losh     case ZSTDv05ds_decodeBlockHeader:
35760c16b537SWarner Losh         {
35770c16b537SWarner Losh             /* Decode block header */
35780c16b537SWarner Losh             blockProperties_t bp;
35790c16b537SWarner Losh             size_t blockSize = ZSTDv05_getcBlockSize(src, ZSTDv05_blockHeaderSize, &bp);
35800c16b537SWarner Losh             if (ZSTDv05_isError(blockSize)) return blockSize;
35810c16b537SWarner Losh             if (bp.blockType == bt_end) {
35820c16b537SWarner Losh                 dctx->expected = 0;
35830c16b537SWarner Losh                 dctx->stage = ZSTDv05ds_getFrameHeaderSize;
35840c16b537SWarner Losh             }
35850c16b537SWarner Losh             else {
35860c16b537SWarner Losh                 dctx->expected = blockSize;
35870c16b537SWarner Losh                 dctx->bType = bp.blockType;
35880c16b537SWarner Losh                 dctx->stage = ZSTDv05ds_decompressBlock;
35890c16b537SWarner Losh             }
35900c16b537SWarner Losh             return 0;
35910c16b537SWarner Losh         }
35920c16b537SWarner Losh     case ZSTDv05ds_decompressBlock:
35930c16b537SWarner Losh         {
35940c16b537SWarner Losh             /* Decompress : block content */
35950c16b537SWarner Losh             size_t rSize;
35960c16b537SWarner Losh             switch(dctx->bType)
35970c16b537SWarner Losh             {
35980c16b537SWarner Losh             case bt_compressed:
35990c16b537SWarner Losh                 rSize = ZSTDv05_decompressBlock_internal(dctx, dst, maxDstSize, src, srcSize);
36000c16b537SWarner Losh                 break;
36010c16b537SWarner Losh             case bt_raw :
36020c16b537SWarner Losh                 rSize = ZSTDv05_copyRawBlock(dst, maxDstSize, src, srcSize);
36030c16b537SWarner Losh                 break;
36040c16b537SWarner Losh             case bt_rle :
36050c16b537SWarner Losh                 return ERROR(GENERIC);   /* not yet handled */
36060c16b537SWarner Losh                 break;
36070c16b537SWarner Losh             case bt_end :   /* should never happen (filtered at phase 1) */
36080c16b537SWarner Losh                 rSize = 0;
36090c16b537SWarner Losh                 break;
36100c16b537SWarner Losh             default:
36110c16b537SWarner Losh                 return ERROR(GENERIC);   /* impossible */
36120c16b537SWarner Losh             }
36130c16b537SWarner Losh             dctx->stage = ZSTDv05ds_decodeBlockHeader;
36140c16b537SWarner Losh             dctx->expected = ZSTDv05_blockHeaderSize;
36150c16b537SWarner Losh             dctx->previousDstEnd = (char*)dst + rSize;
36160c16b537SWarner Losh             return rSize;
36170c16b537SWarner Losh         }
36180c16b537SWarner Losh     default:
36190c16b537SWarner Losh         return ERROR(GENERIC);   /* impossible */
36200c16b537SWarner Losh     }
36210c16b537SWarner Losh }
36220c16b537SWarner Losh 
36230c16b537SWarner Losh 
36240c16b537SWarner Losh static void ZSTDv05_refDictContent(ZSTDv05_DCtx* dctx, const void* dict, size_t dictSize)
36250c16b537SWarner Losh {
36260c16b537SWarner Losh     dctx->dictEnd = dctx->previousDstEnd;
36270c16b537SWarner Losh     dctx->vBase = (const char*)dict - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->base));
36280c16b537SWarner Losh     dctx->base = dict;
36290c16b537SWarner Losh     dctx->previousDstEnd = (const char*)dict + dictSize;
36300c16b537SWarner Losh }
36310c16b537SWarner Losh 
36320c16b537SWarner Losh static size_t ZSTDv05_loadEntropy(ZSTDv05_DCtx* dctx, const void* dict, size_t dictSize)
36330c16b537SWarner Losh {
36340c16b537SWarner Losh     size_t hSize, offcodeHeaderSize, matchlengthHeaderSize, errorCode, litlengthHeaderSize;
36350c16b537SWarner Losh     short offcodeNCount[MaxOff+1];
36360c16b537SWarner Losh     U32 offcodeMaxValue=MaxOff, offcodeLog;
36370c16b537SWarner Losh     short matchlengthNCount[MaxML+1];
36380c16b537SWarner Losh     unsigned matchlengthMaxValue = MaxML, matchlengthLog;
36390c16b537SWarner Losh     short litlengthNCount[MaxLL+1];
36400c16b537SWarner Losh     unsigned litlengthMaxValue = MaxLL, litlengthLog;
36410c16b537SWarner Losh 
36420c16b537SWarner Losh     hSize = HUFv05_readDTableX4(dctx->hufTableX4, dict, dictSize);
36430c16b537SWarner Losh     if (HUFv05_isError(hSize)) return ERROR(dictionary_corrupted);
36440c16b537SWarner Losh     dict = (const char*)dict + hSize;
36450c16b537SWarner Losh     dictSize -= hSize;
36460c16b537SWarner Losh 
36470c16b537SWarner Losh     offcodeHeaderSize = FSEv05_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dict, dictSize);
36480c16b537SWarner Losh     if (FSEv05_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
36490c16b537SWarner Losh     if (offcodeLog > OffFSEv05Log) return ERROR(dictionary_corrupted);
36500c16b537SWarner Losh     errorCode = FSEv05_buildDTable(dctx->OffTable, offcodeNCount, offcodeMaxValue, offcodeLog);
36510c16b537SWarner Losh     if (FSEv05_isError(errorCode)) return ERROR(dictionary_corrupted);
36520c16b537SWarner Losh     dict = (const char*)dict + offcodeHeaderSize;
36530c16b537SWarner Losh     dictSize -= offcodeHeaderSize;
36540c16b537SWarner Losh 
36550c16b537SWarner Losh     matchlengthHeaderSize = FSEv05_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dict, dictSize);
36560c16b537SWarner Losh     if (FSEv05_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
36570c16b537SWarner Losh     if (matchlengthLog > MLFSEv05Log) return ERROR(dictionary_corrupted);
36580c16b537SWarner Losh     errorCode = FSEv05_buildDTable(dctx->MLTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog);
36590c16b537SWarner Losh     if (FSEv05_isError(errorCode)) return ERROR(dictionary_corrupted);
36600c16b537SWarner Losh     dict = (const char*)dict + matchlengthHeaderSize;
36610c16b537SWarner Losh     dictSize -= matchlengthHeaderSize;
36620c16b537SWarner Losh 
36630c16b537SWarner Losh     litlengthHeaderSize = FSEv05_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dict, dictSize);
36640c16b537SWarner Losh     if (litlengthLog > LLFSEv05Log) return ERROR(dictionary_corrupted);
36650c16b537SWarner Losh     if (FSEv05_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
36660c16b537SWarner Losh     errorCode = FSEv05_buildDTable(dctx->LLTable, litlengthNCount, litlengthMaxValue, litlengthLog);
36670c16b537SWarner Losh     if (FSEv05_isError(errorCode)) return ERROR(dictionary_corrupted);
36680c16b537SWarner Losh 
36690c16b537SWarner Losh     dctx->flagStaticTables = 1;
36700c16b537SWarner Losh     return hSize + offcodeHeaderSize + matchlengthHeaderSize + litlengthHeaderSize;
36710c16b537SWarner Losh }
36720c16b537SWarner Losh 
36730c16b537SWarner Losh static size_t ZSTDv05_decompress_insertDictionary(ZSTDv05_DCtx* dctx, const void* dict, size_t dictSize)
36740c16b537SWarner Losh {
36750c16b537SWarner Losh     size_t eSize;
36760c16b537SWarner Losh     U32 magic = MEM_readLE32(dict);
36770c16b537SWarner Losh     if (magic != ZSTDv05_DICT_MAGIC) {
36780c16b537SWarner Losh         /* pure content mode */
36790c16b537SWarner Losh         ZSTDv05_refDictContent(dctx, dict, dictSize);
36800c16b537SWarner Losh         return 0;
36810c16b537SWarner Losh     }
36820c16b537SWarner Losh     /* load entropy tables */
36830c16b537SWarner Losh     dict = (const char*)dict + 4;
36840c16b537SWarner Losh     dictSize -= 4;
36850c16b537SWarner Losh     eSize = ZSTDv05_loadEntropy(dctx, dict, dictSize);
36860c16b537SWarner Losh     if (ZSTDv05_isError(eSize)) return ERROR(dictionary_corrupted);
36870c16b537SWarner Losh 
36880c16b537SWarner Losh     /* reference dictionary content */
36890c16b537SWarner Losh     dict = (const char*)dict + eSize;
36900c16b537SWarner Losh     dictSize -= eSize;
36910c16b537SWarner Losh     ZSTDv05_refDictContent(dctx, dict, dictSize);
36920c16b537SWarner Losh 
36930c16b537SWarner Losh     return 0;
36940c16b537SWarner Losh }
36950c16b537SWarner Losh 
36960c16b537SWarner Losh 
36970c16b537SWarner Losh size_t ZSTDv05_decompressBegin_usingDict(ZSTDv05_DCtx* dctx, const void* dict, size_t dictSize)
36980c16b537SWarner Losh {
36990c16b537SWarner Losh     size_t errorCode;
37000c16b537SWarner Losh     errorCode = ZSTDv05_decompressBegin(dctx);
37010c16b537SWarner Losh     if (ZSTDv05_isError(errorCode)) return errorCode;
37020c16b537SWarner Losh 
37030c16b537SWarner Losh     if (dict && dictSize) {
37040c16b537SWarner Losh         errorCode = ZSTDv05_decompress_insertDictionary(dctx, dict, dictSize);
37050c16b537SWarner Losh         if (ZSTDv05_isError(errorCode)) return ERROR(dictionary_corrupted);
37060c16b537SWarner Losh     }
37070c16b537SWarner Losh 
37080c16b537SWarner Losh     return 0;
37090c16b537SWarner Losh }
37100c16b537SWarner Losh 
37110c16b537SWarner Losh /*
37120c16b537SWarner Losh     Buffered version of Zstd compression library
37130c16b537SWarner Losh     Copyright (C) 2015-2016, Yann Collet.
37140c16b537SWarner Losh 
37150c16b537SWarner Losh     BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
37160c16b537SWarner Losh 
37170c16b537SWarner Losh     Redistribution and use in source and binary forms, with or without
37180c16b537SWarner Losh     modification, are permitted provided that the following conditions are
37190c16b537SWarner Losh     met:
37200c16b537SWarner Losh     * Redistributions of source code must retain the above copyright
37210c16b537SWarner Losh     notice, this list of conditions and the following disclaimer.
37220c16b537SWarner Losh     * Redistributions in binary form must reproduce the above
37230c16b537SWarner Losh     copyright notice, this list of conditions and the following disclaimer
37240c16b537SWarner Losh     in the documentation and/or other materials provided with the
37250c16b537SWarner Losh     distribution.
37260c16b537SWarner Losh     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
37270c16b537SWarner Losh     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37280c16b537SWarner Losh     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
37290c16b537SWarner Losh     A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
37300c16b537SWarner Losh     OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
37310c16b537SWarner Losh     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
37320c16b537SWarner Losh     LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
37330c16b537SWarner Losh     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37340c16b537SWarner Losh     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37350c16b537SWarner Losh     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37360c16b537SWarner Losh     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37370c16b537SWarner Losh 
37380c16b537SWarner Losh     You can contact the author at :
37390c16b537SWarner Losh     - zstd source repository : https://github.com/Cyan4973/zstd
37400c16b537SWarner Losh     - ztsd public forum : https://groups.google.com/forum/#!forum/lz4c
37410c16b537SWarner Losh */
37420c16b537SWarner Losh 
37430c16b537SWarner Losh /* The objects defined into this file should be considered experimental.
37440c16b537SWarner Losh  * They are not labelled stable, as their prototype may change in the future.
37450c16b537SWarner Losh  * You can use them for tests, provide feedback, or if you can endure risk of future changes.
37460c16b537SWarner Losh  */
37470c16b537SWarner Losh 
37480c16b537SWarner Losh 
37490c16b537SWarner Losh 
37500c16b537SWarner Losh /* *************************************
37510c16b537SWarner Losh *  Constants
37520c16b537SWarner Losh ***************************************/
37530c16b537SWarner Losh static size_t ZBUFFv05_blockHeaderSize = 3;
37540c16b537SWarner Losh 
37550c16b537SWarner Losh 
37560c16b537SWarner Losh 
37570c16b537SWarner Losh /* *** Compression *** */
37580c16b537SWarner Losh 
37590c16b537SWarner Losh static size_t ZBUFFv05_limitCopy(void* dst, size_t maxDstSize, const void* src, size_t srcSize)
37600c16b537SWarner Losh {
37610c16b537SWarner Losh     size_t length = MIN(maxDstSize, srcSize);
37620c16b537SWarner Losh     memcpy(dst, src, length);
37630c16b537SWarner Losh     return length;
37640c16b537SWarner Losh }
37650c16b537SWarner Losh 
37660c16b537SWarner Losh 
37670c16b537SWarner Losh 
37680c16b537SWarner Losh 
37690c16b537SWarner Losh /** ************************************************
37700c16b537SWarner Losh *  Streaming decompression
37710c16b537SWarner Losh *
37720c16b537SWarner Losh *  A ZBUFFv05_DCtx object is required to track streaming operation.
37730c16b537SWarner Losh *  Use ZBUFFv05_createDCtx() and ZBUFFv05_freeDCtx() to create/release resources.
37740c16b537SWarner Losh *  Use ZBUFFv05_decompressInit() to start a new decompression operation.
37750c16b537SWarner Losh *  ZBUFFv05_DCtx objects can be reused multiple times.
37760c16b537SWarner Losh *
37770c16b537SWarner Losh *  Use ZBUFFv05_decompressContinue() repetitively to consume your input.
37780c16b537SWarner Losh *  *srcSizePtr and *maxDstSizePtr can be any size.
37790c16b537SWarner Losh *  The function will report how many bytes were read or written by modifying *srcSizePtr and *maxDstSizePtr.
37800c16b537SWarner Losh *  Note that it may not consume the entire input, in which case it's up to the caller to call again the function with remaining input.
37810c16b537SWarner Losh *  The content of dst will be overwritten (up to *maxDstSizePtr) at each function call, so save its content if it matters or change dst .
37820c16b537SWarner Losh *  return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to improve latency)
37830c16b537SWarner Losh *            or 0 when a frame is completely decoded
37840c16b537SWarner Losh *            or an error code, which can be tested using ZBUFFv05_isError().
37850c16b537SWarner Losh *
37860c16b537SWarner Losh *  Hint : recommended buffer sizes (not compulsory)
37870c16b537SWarner Losh *  output : 128 KB block size is the internal unit, it ensures it's always possible to write a full block when it's decoded.
37880c16b537SWarner Losh *  input : just follow indications from ZBUFFv05_decompressContinue() to minimize latency. It should always be <= 128 KB + 3 .
37890c16b537SWarner Losh * **************************************************/
37900c16b537SWarner Losh 
37910c16b537SWarner Losh typedef enum { ZBUFFv05ds_init, ZBUFFv05ds_readHeader, ZBUFFv05ds_loadHeader, ZBUFFv05ds_decodeHeader,
37920c16b537SWarner Losh                ZBUFFv05ds_read, ZBUFFv05ds_load, ZBUFFv05ds_flush } ZBUFFv05_dStage;
37930c16b537SWarner Losh 
37940c16b537SWarner Losh /* *** Resource management *** */
37950c16b537SWarner Losh 
37960c16b537SWarner Losh #define ZSTDv05_frameHeaderSize_max 5   /* too magical, should come from reference */
37970c16b537SWarner Losh struct ZBUFFv05_DCtx_s {
37980c16b537SWarner Losh     ZSTDv05_DCtx* zc;
37990c16b537SWarner Losh     ZSTDv05_parameters params;
38000c16b537SWarner Losh     char* inBuff;
38010c16b537SWarner Losh     size_t inBuffSize;
38020c16b537SWarner Losh     size_t inPos;
38030c16b537SWarner Losh     char* outBuff;
38040c16b537SWarner Losh     size_t outBuffSize;
38050c16b537SWarner Losh     size_t outStart;
38060c16b537SWarner Losh     size_t outEnd;
38070c16b537SWarner Losh     size_t hPos;
38080c16b537SWarner Losh     ZBUFFv05_dStage stage;
38090c16b537SWarner Losh     unsigned char headerBuffer[ZSTDv05_frameHeaderSize_max];
38100c16b537SWarner Losh };   /* typedef'd to ZBUFFv05_DCtx within "zstd_buffered.h" */
38110c16b537SWarner Losh 
38120c16b537SWarner Losh 
38130c16b537SWarner Losh ZBUFFv05_DCtx* ZBUFFv05_createDCtx(void)
38140c16b537SWarner Losh {
38150c16b537SWarner Losh     ZBUFFv05_DCtx* zbc = (ZBUFFv05_DCtx*)malloc(sizeof(ZBUFFv05_DCtx));
38160c16b537SWarner Losh     if (zbc==NULL) return NULL;
38170c16b537SWarner Losh     memset(zbc, 0, sizeof(*zbc));
38180c16b537SWarner Losh     zbc->zc = ZSTDv05_createDCtx();
38190c16b537SWarner Losh     zbc->stage = ZBUFFv05ds_init;
38200c16b537SWarner Losh     return zbc;
38210c16b537SWarner Losh }
38220c16b537SWarner Losh 
38230c16b537SWarner Losh size_t ZBUFFv05_freeDCtx(ZBUFFv05_DCtx* zbc)
38240c16b537SWarner Losh {
38250c16b537SWarner Losh     if (zbc==NULL) return 0;   /* support free on null */
38260c16b537SWarner Losh     ZSTDv05_freeDCtx(zbc->zc);
38270c16b537SWarner Losh     free(zbc->inBuff);
38280c16b537SWarner Losh     free(zbc->outBuff);
38290c16b537SWarner Losh     free(zbc);
38300c16b537SWarner Losh     return 0;
38310c16b537SWarner Losh }
38320c16b537SWarner Losh 
38330c16b537SWarner Losh 
38340c16b537SWarner Losh /* *** Initialization *** */
38350c16b537SWarner Losh 
38360c16b537SWarner Losh size_t ZBUFFv05_decompressInitDictionary(ZBUFFv05_DCtx* zbc, const void* dict, size_t dictSize)
38370c16b537SWarner Losh {
38380c16b537SWarner Losh     zbc->stage = ZBUFFv05ds_readHeader;
38390c16b537SWarner Losh     zbc->hPos = zbc->inPos = zbc->outStart = zbc->outEnd = 0;
38400c16b537SWarner Losh     return ZSTDv05_decompressBegin_usingDict(zbc->zc, dict, dictSize);
38410c16b537SWarner Losh }
38420c16b537SWarner Losh 
38430c16b537SWarner Losh size_t ZBUFFv05_decompressInit(ZBUFFv05_DCtx* zbc)
38440c16b537SWarner Losh {
38450c16b537SWarner Losh     return ZBUFFv05_decompressInitDictionary(zbc, NULL, 0);
38460c16b537SWarner Losh }
38470c16b537SWarner Losh 
38480c16b537SWarner Losh 
38490c16b537SWarner Losh /* *** Decompression *** */
38500c16b537SWarner Losh 
38510c16b537SWarner Losh size_t ZBUFFv05_decompressContinue(ZBUFFv05_DCtx* zbc, void* dst, size_t* maxDstSizePtr, const void* src, size_t* srcSizePtr)
38520c16b537SWarner Losh {
38530c16b537SWarner Losh     const char* const istart = (const char*)src;
38540c16b537SWarner Losh     const char* ip = istart;
38550c16b537SWarner Losh     const char* const iend = istart + *srcSizePtr;
38560c16b537SWarner Losh     char* const ostart = (char*)dst;
38570c16b537SWarner Losh     char* op = ostart;
38580c16b537SWarner Losh     char* const oend = ostart + *maxDstSizePtr;
38590c16b537SWarner Losh     U32 notDone = 1;
38600c16b537SWarner Losh 
38610c16b537SWarner Losh     while (notDone) {
38620c16b537SWarner Losh         switch(zbc->stage)
38630c16b537SWarner Losh         {
38640c16b537SWarner Losh         case ZBUFFv05ds_init :
38650c16b537SWarner Losh             return ERROR(init_missing);
38660c16b537SWarner Losh 
38670c16b537SWarner Losh         case ZBUFFv05ds_readHeader :
38680c16b537SWarner Losh             /* read header from src */
38690c16b537SWarner Losh             {
38700c16b537SWarner Losh                 size_t headerSize = ZSTDv05_getFrameParams(&(zbc->params), src, *srcSizePtr);
38710c16b537SWarner Losh                 if (ZSTDv05_isError(headerSize)) return headerSize;
38720c16b537SWarner Losh                 if (headerSize) {
38730c16b537SWarner Losh                     /* not enough input to decode header : tell how many bytes would be necessary */
38740c16b537SWarner Losh                     memcpy(zbc->headerBuffer+zbc->hPos, src, *srcSizePtr);
38750c16b537SWarner Losh                     zbc->hPos += *srcSizePtr;
38760c16b537SWarner Losh                     *maxDstSizePtr = 0;
38770c16b537SWarner Losh                     zbc->stage = ZBUFFv05ds_loadHeader;
38780c16b537SWarner Losh                     return headerSize - zbc->hPos;
38790c16b537SWarner Losh                 }
38800c16b537SWarner Losh                 zbc->stage = ZBUFFv05ds_decodeHeader;
38810c16b537SWarner Losh                 break;
38820c16b537SWarner Losh             }
38830c16b537SWarner Losh 	    /* fall-through */
38840c16b537SWarner Losh         case ZBUFFv05ds_loadHeader:
38850c16b537SWarner Losh             /* complete header from src */
38860c16b537SWarner Losh             {
38870c16b537SWarner Losh                 size_t headerSize = ZBUFFv05_limitCopy(
38880c16b537SWarner Losh                     zbc->headerBuffer + zbc->hPos, ZSTDv05_frameHeaderSize_max - zbc->hPos,
38890c16b537SWarner Losh                     src, *srcSizePtr);
38900c16b537SWarner Losh                 zbc->hPos += headerSize;
38910c16b537SWarner Losh                 ip += headerSize;
38920c16b537SWarner Losh                 headerSize = ZSTDv05_getFrameParams(&(zbc->params), zbc->headerBuffer, zbc->hPos);
38930c16b537SWarner Losh                 if (ZSTDv05_isError(headerSize)) return headerSize;
38940c16b537SWarner Losh                 if (headerSize) {
38950c16b537SWarner Losh                     /* not enough input to decode header : tell how many bytes would be necessary */
38960c16b537SWarner Losh                     *maxDstSizePtr = 0;
38970c16b537SWarner Losh                     return headerSize - zbc->hPos;
38980c16b537SWarner Losh                 }
38990c16b537SWarner Losh                 // zbc->stage = ZBUFFv05ds_decodeHeader; break;   /* useless : stage follows */
39000c16b537SWarner Losh             }
39010c16b537SWarner Losh 	    /* fall-through */
39020c16b537SWarner Losh         case ZBUFFv05ds_decodeHeader:
39030c16b537SWarner Losh                 /* apply header to create / resize buffers */
39040c16b537SWarner Losh                 {
39050c16b537SWarner Losh                     size_t neededOutSize = (size_t)1 << zbc->params.windowLog;
39060c16b537SWarner Losh                     size_t neededInSize = BLOCKSIZE;   /* a block is never > BLOCKSIZE */
39070c16b537SWarner Losh                     if (zbc->inBuffSize < neededInSize) {
39080c16b537SWarner Losh                         free(zbc->inBuff);
39090c16b537SWarner Losh                         zbc->inBuffSize = neededInSize;
39100c16b537SWarner Losh                         zbc->inBuff = (char*)malloc(neededInSize);
39110c16b537SWarner Losh                         if (zbc->inBuff == NULL) return ERROR(memory_allocation);
39120c16b537SWarner Losh                     }
39130c16b537SWarner Losh                     if (zbc->outBuffSize < neededOutSize) {
39140c16b537SWarner Losh                         free(zbc->outBuff);
39150c16b537SWarner Losh                         zbc->outBuffSize = neededOutSize;
39160c16b537SWarner Losh                         zbc->outBuff = (char*)malloc(neededOutSize);
39170c16b537SWarner Losh                         if (zbc->outBuff == NULL) return ERROR(memory_allocation);
39180c16b537SWarner Losh                 }   }
39190c16b537SWarner Losh                 if (zbc->hPos) {
39200c16b537SWarner Losh                     /* some data already loaded into headerBuffer : transfer into inBuff */
39210c16b537SWarner Losh                     memcpy(zbc->inBuff, zbc->headerBuffer, zbc->hPos);
39220c16b537SWarner Losh                     zbc->inPos = zbc->hPos;
39230c16b537SWarner Losh                     zbc->hPos = 0;
39240c16b537SWarner Losh                     zbc->stage = ZBUFFv05ds_load;
39250c16b537SWarner Losh                     break;
39260c16b537SWarner Losh                 }
39270c16b537SWarner Losh                 zbc->stage = ZBUFFv05ds_read;
39280c16b537SWarner Losh 		/* fall-through */
39290c16b537SWarner Losh         case ZBUFFv05ds_read:
39300c16b537SWarner Losh             {
39310c16b537SWarner Losh                 size_t neededInSize = ZSTDv05_nextSrcSizeToDecompress(zbc->zc);
39320c16b537SWarner Losh                 if (neededInSize==0) {  /* end of frame */
39330c16b537SWarner Losh                     zbc->stage = ZBUFFv05ds_init;
39340c16b537SWarner Losh                     notDone = 0;
39350c16b537SWarner Losh                     break;
39360c16b537SWarner Losh                 }
39370c16b537SWarner Losh                 if ((size_t)(iend-ip) >= neededInSize) {
39380c16b537SWarner Losh                     /* directly decode from src */
39390c16b537SWarner Losh                     size_t decodedSize = ZSTDv05_decompressContinue(zbc->zc,
39400c16b537SWarner Losh                         zbc->outBuff + zbc->outStart, zbc->outBuffSize - zbc->outStart,
39410c16b537SWarner Losh                         ip, neededInSize);
39420c16b537SWarner Losh                     if (ZSTDv05_isError(decodedSize)) return decodedSize;
39430c16b537SWarner Losh                     ip += neededInSize;
39440c16b537SWarner Losh                     if (!decodedSize) break;   /* this was just a header */
39450c16b537SWarner Losh                     zbc->outEnd = zbc->outStart +  decodedSize;
39460c16b537SWarner Losh                     zbc->stage = ZBUFFv05ds_flush;
39470c16b537SWarner Losh                     break;
39480c16b537SWarner Losh                 }
39490c16b537SWarner Losh                 if (ip==iend) { notDone = 0; break; }   /* no more input */
39500c16b537SWarner Losh                 zbc->stage = ZBUFFv05ds_load;
39510c16b537SWarner Losh             }
39520c16b537SWarner Losh 	    /* fall-through */
39530c16b537SWarner Losh         case ZBUFFv05ds_load:
39540c16b537SWarner Losh             {
39550c16b537SWarner Losh                 size_t neededInSize = ZSTDv05_nextSrcSizeToDecompress(zbc->zc);
39560c16b537SWarner Losh                 size_t toLoad = neededInSize - zbc->inPos;   /* should always be <= remaining space within inBuff */
39570c16b537SWarner Losh                 size_t loadedSize;
39580c16b537SWarner Losh                 if (toLoad > zbc->inBuffSize - zbc->inPos) return ERROR(corruption_detected);   /* should never happen */
39590c16b537SWarner Losh                 loadedSize = ZBUFFv05_limitCopy(zbc->inBuff + zbc->inPos, toLoad, ip, iend-ip);
39600c16b537SWarner Losh                 ip += loadedSize;
39610c16b537SWarner Losh                 zbc->inPos += loadedSize;
39620c16b537SWarner Losh                 if (loadedSize < toLoad) { notDone = 0; break; }   /* not enough input, wait for more */
39630c16b537SWarner Losh                 {
39640c16b537SWarner Losh                     size_t decodedSize = ZSTDv05_decompressContinue(zbc->zc,
39650c16b537SWarner Losh                         zbc->outBuff + zbc->outStart, zbc->outBuffSize - zbc->outStart,
39660c16b537SWarner Losh                         zbc->inBuff, neededInSize);
39670c16b537SWarner Losh                     if (ZSTDv05_isError(decodedSize)) return decodedSize;
39680c16b537SWarner Losh                     zbc->inPos = 0;   /* input is consumed */
39690c16b537SWarner Losh                     if (!decodedSize) { zbc->stage = ZBUFFv05ds_read; break; }   /* this was just a header */
39700c16b537SWarner Losh                     zbc->outEnd = zbc->outStart +  decodedSize;
39710c16b537SWarner Losh                     zbc->stage = ZBUFFv05ds_flush;
39720c16b537SWarner Losh                     // break; /* ZBUFFv05ds_flush follows */
39730c16b537SWarner Losh                 }
39740c16b537SWarner Losh 	    }
39750c16b537SWarner Losh 	    /* fall-through */
39760c16b537SWarner Losh         case ZBUFFv05ds_flush:
39770c16b537SWarner Losh             {
39780c16b537SWarner Losh                 size_t toFlushSize = zbc->outEnd - zbc->outStart;
39790c16b537SWarner Losh                 size_t flushedSize = ZBUFFv05_limitCopy(op, oend-op, zbc->outBuff + zbc->outStart, toFlushSize);
39800c16b537SWarner Losh                 op += flushedSize;
39810c16b537SWarner Losh                 zbc->outStart += flushedSize;
39820c16b537SWarner Losh                 if (flushedSize == toFlushSize) {
39830c16b537SWarner Losh                     zbc->stage = ZBUFFv05ds_read;
39840c16b537SWarner Losh                     if (zbc->outStart + BLOCKSIZE > zbc->outBuffSize)
39850c16b537SWarner Losh                         zbc->outStart = zbc->outEnd = 0;
39860c16b537SWarner Losh                     break;
39870c16b537SWarner Losh                 }
39880c16b537SWarner Losh                 /* cannot flush everything */
39890c16b537SWarner Losh                 notDone = 0;
39900c16b537SWarner Losh                 break;
39910c16b537SWarner Losh             }
39920c16b537SWarner Losh         default: return ERROR(GENERIC);   /* impossible */
39930c16b537SWarner Losh     }   }
39940c16b537SWarner Losh 
39950c16b537SWarner Losh     *srcSizePtr = ip-istart;
39960c16b537SWarner Losh     *maxDstSizePtr = op-ostart;
39970c16b537SWarner Losh 
39980c16b537SWarner Losh     {   size_t nextSrcSizeHint = ZSTDv05_nextSrcSizeToDecompress(zbc->zc);
39990c16b537SWarner Losh         if (nextSrcSizeHint > ZBUFFv05_blockHeaderSize) nextSrcSizeHint+= ZBUFFv05_blockHeaderSize;   /* get next block header too */
40000c16b537SWarner Losh         nextSrcSizeHint -= zbc->inPos;   /* already loaded*/
40010c16b537SWarner Losh         return nextSrcSizeHint;
40020c16b537SWarner Losh     }
40030c16b537SWarner Losh }
40040c16b537SWarner Losh 
40050c16b537SWarner Losh 
40060c16b537SWarner Losh 
40070c16b537SWarner Losh /* *************************************
40080c16b537SWarner Losh *  Tool functions
40090c16b537SWarner Losh ***************************************/
40100c16b537SWarner Losh unsigned ZBUFFv05_isError(size_t errorCode) { return ERR_isError(errorCode); }
40110c16b537SWarner Losh const char* ZBUFFv05_getErrorName(size_t errorCode) { return ERR_getErrorName(errorCode); }
40120c16b537SWarner Losh 
40130c16b537SWarner Losh size_t ZBUFFv05_recommendedDInSize(void)  { return BLOCKSIZE + ZBUFFv05_blockHeaderSize /* block header size*/ ; }
40140c16b537SWarner Losh size_t ZBUFFv05_recommendedDOutSize(void) { return BLOCKSIZE; }
4015