xref: /freebsd/sys/contrib/zstd/lib/legacy/zstd_v04.c (revision 0c16b53773565120a8f80a31a0af2ef56ccd368e)
1*0c16b537SWarner Losh /*
2*0c16b537SWarner Losh  * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
3*0c16b537SWarner Losh  * All rights reserved.
4*0c16b537SWarner Losh  *
5*0c16b537SWarner Losh  * This source code is licensed under both the BSD-style license (found in the
6*0c16b537SWarner Losh  * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7*0c16b537SWarner Losh  * in the COPYING file in the root directory of this source tree).
8*0c16b537SWarner Losh  * You may select, at your option, one of the above-listed licenses.
9*0c16b537SWarner Losh  */
10*0c16b537SWarner Losh 
11*0c16b537SWarner Losh 
12*0c16b537SWarner Losh /*- Dependencies -*/
13*0c16b537SWarner Losh #include "zstd_v04.h"
14*0c16b537SWarner Losh #include "error_private.h"
15*0c16b537SWarner Losh 
16*0c16b537SWarner Losh 
17*0c16b537SWarner Losh /* ******************************************************************
18*0c16b537SWarner Losh    mem.h
19*0c16b537SWarner Losh    low-level memory access routines
20*0c16b537SWarner Losh    Copyright (C) 2013-2015, Yann Collet.
21*0c16b537SWarner Losh 
22*0c16b537SWarner Losh    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
23*0c16b537SWarner Losh 
24*0c16b537SWarner Losh    Redistribution and use in source and binary forms, with or without
25*0c16b537SWarner Losh    modification, are permitted provided that the following conditions are
26*0c16b537SWarner Losh    met:
27*0c16b537SWarner Losh 
28*0c16b537SWarner Losh        * Redistributions of source code must retain the above copyright
29*0c16b537SWarner Losh    notice, this list of conditions and the following disclaimer.
30*0c16b537SWarner Losh        * Redistributions in binary form must reproduce the above
31*0c16b537SWarner Losh    copyright notice, this list of conditions and the following disclaimer
32*0c16b537SWarner Losh    in the documentation and/or other materials provided with the
33*0c16b537SWarner Losh    distribution.
34*0c16b537SWarner Losh 
35*0c16b537SWarner Losh    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36*0c16b537SWarner Losh    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37*0c16b537SWarner Losh    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38*0c16b537SWarner Losh    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39*0c16b537SWarner Losh    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40*0c16b537SWarner Losh    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41*0c16b537SWarner Losh    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42*0c16b537SWarner Losh    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43*0c16b537SWarner Losh    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44*0c16b537SWarner Losh    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45*0c16b537SWarner Losh    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46*0c16b537SWarner Losh 
47*0c16b537SWarner Losh     You can contact the author at :
48*0c16b537SWarner Losh     - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
49*0c16b537SWarner Losh     - Public forum : https://groups.google.com/forum/#!forum/lz4c
50*0c16b537SWarner Losh ****************************************************************** */
51*0c16b537SWarner Losh #ifndef MEM_H_MODULE
52*0c16b537SWarner Losh #define MEM_H_MODULE
53*0c16b537SWarner Losh 
54*0c16b537SWarner Losh #if defined (__cplusplus)
55*0c16b537SWarner Losh extern "C" {
56*0c16b537SWarner Losh #endif
57*0c16b537SWarner Losh 
58*0c16b537SWarner Losh /******************************************
59*0c16b537SWarner Losh *  Includes
60*0c16b537SWarner Losh ******************************************/
61*0c16b537SWarner Losh #include <stddef.h>    /* size_t, ptrdiff_t */
62*0c16b537SWarner Losh #include <string.h>    /* memcpy */
63*0c16b537SWarner Losh 
64*0c16b537SWarner Losh 
65*0c16b537SWarner Losh /******************************************
66*0c16b537SWarner Losh *  Compiler-specific
67*0c16b537SWarner Losh ******************************************/
68*0c16b537SWarner Losh #if defined(_MSC_VER)   /* Visual Studio */
69*0c16b537SWarner Losh #   include <stdlib.h>  /* _byteswap_ulong */
70*0c16b537SWarner Losh #   include <intrin.h>  /* _byteswap_* */
71*0c16b537SWarner Losh #endif
72*0c16b537SWarner Losh #if defined(__GNUC__)
73*0c16b537SWarner Losh #  define MEM_STATIC static __attribute__((unused))
74*0c16b537SWarner Losh #elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
75*0c16b537SWarner Losh #  define MEM_STATIC static inline
76*0c16b537SWarner Losh #elif defined(_MSC_VER)
77*0c16b537SWarner Losh #  define MEM_STATIC static __inline
78*0c16b537SWarner Losh #else
79*0c16b537SWarner Losh #  define MEM_STATIC static  /* this version may generate warnings for unused static functions; disable the relevant warning */
80*0c16b537SWarner Losh #endif
81*0c16b537SWarner Losh 
82*0c16b537SWarner Losh 
83*0c16b537SWarner Losh /****************************************************************
84*0c16b537SWarner Losh *  Basic Types
85*0c16b537SWarner Losh *****************************************************************/
86*0c16b537SWarner Losh #if defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
87*0c16b537SWarner Losh # include <stdint.h>
88*0c16b537SWarner Losh   typedef  uint8_t BYTE;
89*0c16b537SWarner Losh   typedef uint16_t U16;
90*0c16b537SWarner Losh   typedef  int16_t S16;
91*0c16b537SWarner Losh   typedef uint32_t U32;
92*0c16b537SWarner Losh   typedef  int32_t S32;
93*0c16b537SWarner Losh   typedef uint64_t U64;
94*0c16b537SWarner Losh   typedef  int64_t S64;
95*0c16b537SWarner Losh #else
96*0c16b537SWarner Losh   typedef unsigned char       BYTE;
97*0c16b537SWarner Losh   typedef unsigned short      U16;
98*0c16b537SWarner Losh   typedef   signed short      S16;
99*0c16b537SWarner Losh   typedef unsigned int        U32;
100*0c16b537SWarner Losh   typedef   signed int        S32;
101*0c16b537SWarner Losh   typedef unsigned long long  U64;
102*0c16b537SWarner Losh   typedef   signed long long  S64;
103*0c16b537SWarner Losh #endif
104*0c16b537SWarner Losh 
105*0c16b537SWarner Losh 
106*0c16b537SWarner Losh /****************************************************************
107*0c16b537SWarner Losh *  Memory I/O
108*0c16b537SWarner Losh *****************************************************************/
109*0c16b537SWarner Losh /* MEM_FORCE_MEMORY_ACCESS
110*0c16b537SWarner Losh  * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.
111*0c16b537SWarner Losh  * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.
112*0c16b537SWarner Losh  * The below switch allow to select different access method for improved performance.
113*0c16b537SWarner Losh  * Method 0 (default) : use `memcpy()`. Safe and portable.
114*0c16b537SWarner Losh  * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable).
115*0c16b537SWarner Losh  *            This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.
116*0c16b537SWarner Losh  * Method 2 : direct access. This method is portable but violate C standard.
117*0c16b537SWarner Losh  *            It can generate buggy code on targets generating assembly depending on alignment.
118*0c16b537SWarner Losh  *            But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)
119*0c16b537SWarner Losh  * See http://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details.
120*0c16b537SWarner Losh  * Prefer these methods in priority order (0 > 1 > 2)
121*0c16b537SWarner Losh  */
122*0c16b537SWarner Losh #ifndef MEM_FORCE_MEMORY_ACCESS   /* can be defined externally, on command line for example */
123*0c16b537SWarner 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__) )
124*0c16b537SWarner Losh #    define MEM_FORCE_MEMORY_ACCESS 2
125*0c16b537SWarner Losh #  elif (defined(__INTEL_COMPILER) && !defined(WIN32)) || \
126*0c16b537SWarner Losh   (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) ))
127*0c16b537SWarner Losh #    define MEM_FORCE_MEMORY_ACCESS 1
128*0c16b537SWarner Losh #  endif
129*0c16b537SWarner Losh #endif
130*0c16b537SWarner Losh 
131*0c16b537SWarner Losh MEM_STATIC unsigned MEM_32bits(void) { return sizeof(void*)==4; }
132*0c16b537SWarner Losh MEM_STATIC unsigned MEM_64bits(void) { return sizeof(void*)==8; }
133*0c16b537SWarner Losh 
134*0c16b537SWarner Losh MEM_STATIC unsigned MEM_isLittleEndian(void)
135*0c16b537SWarner Losh {
136*0c16b537SWarner Losh     const union { U32 u; BYTE c[4]; } one = { 1 };   /* don't use static : performance detrimental  */
137*0c16b537SWarner Losh     return one.c[0];
138*0c16b537SWarner Losh }
139*0c16b537SWarner Losh 
140*0c16b537SWarner Losh #if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2)
141*0c16b537SWarner Losh 
142*0c16b537SWarner Losh /* violates C standard on structure alignment.
143*0c16b537SWarner Losh Only use if no other choice to achieve best performance on target platform */
144*0c16b537SWarner Losh MEM_STATIC U16 MEM_read16(const void* memPtr) { return *(const U16*) memPtr; }
145*0c16b537SWarner Losh MEM_STATIC U32 MEM_read32(const void* memPtr) { return *(const U32*) memPtr; }
146*0c16b537SWarner Losh MEM_STATIC U64 MEM_read64(const void* memPtr) { return *(const U64*) memPtr; }
147*0c16b537SWarner Losh 
148*0c16b537SWarner Losh MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; }
149*0c16b537SWarner Losh 
150*0c16b537SWarner Losh #elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1)
151*0c16b537SWarner Losh 
152*0c16b537SWarner Losh /* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
153*0c16b537SWarner Losh /* currently only defined for gcc and icc */
154*0c16b537SWarner Losh typedef union { U16 u16; U32 u32; U64 u64; } __attribute__((packed)) unalign;
155*0c16b537SWarner Losh 
156*0c16b537SWarner Losh MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign*)ptr)->u16; }
157*0c16b537SWarner Losh MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign*)ptr)->u32; }
158*0c16b537SWarner Losh MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign*)ptr)->u64; }
159*0c16b537SWarner Losh 
160*0c16b537SWarner Losh MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; }
161*0c16b537SWarner Losh 
162*0c16b537SWarner Losh #else
163*0c16b537SWarner Losh 
164*0c16b537SWarner Losh /* default method, safe and standard.
165*0c16b537SWarner Losh    can sometimes prove slower */
166*0c16b537SWarner Losh 
167*0c16b537SWarner Losh MEM_STATIC U16 MEM_read16(const void* memPtr)
168*0c16b537SWarner Losh {
169*0c16b537SWarner Losh     U16 val; memcpy(&val, memPtr, sizeof(val)); return val;
170*0c16b537SWarner Losh }
171*0c16b537SWarner Losh 
172*0c16b537SWarner Losh MEM_STATIC U32 MEM_read32(const void* memPtr)
173*0c16b537SWarner Losh {
174*0c16b537SWarner Losh     U32 val; memcpy(&val, memPtr, sizeof(val)); return val;
175*0c16b537SWarner Losh }
176*0c16b537SWarner Losh 
177*0c16b537SWarner Losh MEM_STATIC U64 MEM_read64(const void* memPtr)
178*0c16b537SWarner Losh {
179*0c16b537SWarner Losh     U64 val; memcpy(&val, memPtr, sizeof(val)); return val;
180*0c16b537SWarner Losh }
181*0c16b537SWarner Losh 
182*0c16b537SWarner Losh MEM_STATIC void MEM_write16(void* memPtr, U16 value)
183*0c16b537SWarner Losh {
184*0c16b537SWarner Losh     memcpy(memPtr, &value, sizeof(value));
185*0c16b537SWarner Losh }
186*0c16b537SWarner Losh 
187*0c16b537SWarner Losh #endif // MEM_FORCE_MEMORY_ACCESS
188*0c16b537SWarner Losh 
189*0c16b537SWarner Losh 
190*0c16b537SWarner Losh MEM_STATIC U16 MEM_readLE16(const void* memPtr)
191*0c16b537SWarner Losh {
192*0c16b537SWarner Losh     if (MEM_isLittleEndian())
193*0c16b537SWarner Losh         return MEM_read16(memPtr);
194*0c16b537SWarner Losh     else
195*0c16b537SWarner Losh     {
196*0c16b537SWarner Losh         const BYTE* p = (const BYTE*)memPtr;
197*0c16b537SWarner Losh         return (U16)(p[0] + (p[1]<<8));
198*0c16b537SWarner Losh     }
199*0c16b537SWarner Losh }
200*0c16b537SWarner Losh 
201*0c16b537SWarner Losh MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val)
202*0c16b537SWarner Losh {
203*0c16b537SWarner Losh     if (MEM_isLittleEndian())
204*0c16b537SWarner Losh     {
205*0c16b537SWarner Losh         MEM_write16(memPtr, val);
206*0c16b537SWarner Losh     }
207*0c16b537SWarner Losh     else
208*0c16b537SWarner Losh     {
209*0c16b537SWarner Losh         BYTE* p = (BYTE*)memPtr;
210*0c16b537SWarner Losh         p[0] = (BYTE)val;
211*0c16b537SWarner Losh         p[1] = (BYTE)(val>>8);
212*0c16b537SWarner Losh     }
213*0c16b537SWarner Losh }
214*0c16b537SWarner Losh 
215*0c16b537SWarner Losh MEM_STATIC U32 MEM_readLE32(const void* memPtr)
216*0c16b537SWarner Losh {
217*0c16b537SWarner Losh     if (MEM_isLittleEndian())
218*0c16b537SWarner Losh         return MEM_read32(memPtr);
219*0c16b537SWarner Losh     else
220*0c16b537SWarner Losh     {
221*0c16b537SWarner Losh         const BYTE* p = (const BYTE*)memPtr;
222*0c16b537SWarner Losh         return (U32)((U32)p[0] + ((U32)p[1]<<8) + ((U32)p[2]<<16) + ((U32)p[3]<<24));
223*0c16b537SWarner Losh     }
224*0c16b537SWarner Losh }
225*0c16b537SWarner Losh 
226*0c16b537SWarner Losh 
227*0c16b537SWarner Losh MEM_STATIC U64 MEM_readLE64(const void* memPtr)
228*0c16b537SWarner Losh {
229*0c16b537SWarner Losh     if (MEM_isLittleEndian())
230*0c16b537SWarner Losh         return MEM_read64(memPtr);
231*0c16b537SWarner Losh     else
232*0c16b537SWarner Losh     {
233*0c16b537SWarner Losh         const BYTE* p = (const BYTE*)memPtr;
234*0c16b537SWarner Losh         return (U64)((U64)p[0] + ((U64)p[1]<<8) + ((U64)p[2]<<16) + ((U64)p[3]<<24)
235*0c16b537SWarner Losh                      + ((U64)p[4]<<32) + ((U64)p[5]<<40) + ((U64)p[6]<<48) + ((U64)p[7]<<56));
236*0c16b537SWarner Losh     }
237*0c16b537SWarner Losh }
238*0c16b537SWarner Losh 
239*0c16b537SWarner Losh 
240*0c16b537SWarner Losh MEM_STATIC size_t MEM_readLEST(const void* memPtr)
241*0c16b537SWarner Losh {
242*0c16b537SWarner Losh     if (MEM_32bits())
243*0c16b537SWarner Losh         return (size_t)MEM_readLE32(memPtr);
244*0c16b537SWarner Losh     else
245*0c16b537SWarner Losh         return (size_t)MEM_readLE64(memPtr);
246*0c16b537SWarner Losh }
247*0c16b537SWarner Losh 
248*0c16b537SWarner Losh 
249*0c16b537SWarner Losh #if defined (__cplusplus)
250*0c16b537SWarner Losh }
251*0c16b537SWarner Losh #endif
252*0c16b537SWarner Losh 
253*0c16b537SWarner Losh #endif /* MEM_H_MODULE */
254*0c16b537SWarner Losh 
255*0c16b537SWarner Losh /*
256*0c16b537SWarner Losh     zstd - standard compression library
257*0c16b537SWarner Losh     Header File for static linking only
258*0c16b537SWarner Losh     Copyright (C) 2014-2015, Yann Collet.
259*0c16b537SWarner Losh 
260*0c16b537SWarner Losh     BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
261*0c16b537SWarner Losh 
262*0c16b537SWarner Losh     Redistribution and use in source and binary forms, with or without
263*0c16b537SWarner Losh     modification, are permitted provided that the following conditions are
264*0c16b537SWarner Losh     met:
265*0c16b537SWarner Losh     * Redistributions of source code must retain the above copyright
266*0c16b537SWarner Losh     notice, this list of conditions and the following disclaimer.
267*0c16b537SWarner Losh     * Redistributions in binary form must reproduce the above
268*0c16b537SWarner Losh     copyright notice, this list of conditions and the following disclaimer
269*0c16b537SWarner Losh     in the documentation and/or other materials provided with the
270*0c16b537SWarner Losh     distribution.
271*0c16b537SWarner Losh     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
272*0c16b537SWarner Losh     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
273*0c16b537SWarner Losh     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
274*0c16b537SWarner Losh     A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
275*0c16b537SWarner Losh     OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
276*0c16b537SWarner Losh     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
277*0c16b537SWarner Losh     LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
278*0c16b537SWarner Losh     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
279*0c16b537SWarner Losh     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
280*0c16b537SWarner Losh     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
281*0c16b537SWarner Losh     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
282*0c16b537SWarner Losh 
283*0c16b537SWarner Losh     You can contact the author at :
284*0c16b537SWarner Losh     - zstd source repository : https://github.com/Cyan4973/zstd
285*0c16b537SWarner Losh     - ztsd public forum : https://groups.google.com/forum/#!forum/lz4c
286*0c16b537SWarner Losh */
287*0c16b537SWarner Losh #ifndef ZSTD_STATIC_H
288*0c16b537SWarner Losh #define ZSTD_STATIC_H
289*0c16b537SWarner Losh 
290*0c16b537SWarner Losh /* The objects defined into this file shall be considered experimental.
291*0c16b537SWarner Losh  * They are not considered stable, as their prototype may change in the future.
292*0c16b537SWarner Losh  * You can use them for tests, provide feedback, or if you can endure risks of future changes.
293*0c16b537SWarner Losh  */
294*0c16b537SWarner Losh 
295*0c16b537SWarner Losh #if defined (__cplusplus)
296*0c16b537SWarner Losh extern "C" {
297*0c16b537SWarner Losh #endif
298*0c16b537SWarner Losh 
299*0c16b537SWarner Losh /* *************************************
300*0c16b537SWarner Losh *  Types
301*0c16b537SWarner Losh ***************************************/
302*0c16b537SWarner Losh #define ZSTD_WINDOWLOG_MAX 26
303*0c16b537SWarner Losh #define ZSTD_WINDOWLOG_MIN 18
304*0c16b537SWarner Losh #define ZSTD_WINDOWLOG_ABSOLUTEMIN 11
305*0c16b537SWarner Losh #define ZSTD_CONTENTLOG_MAX (ZSTD_WINDOWLOG_MAX+1)
306*0c16b537SWarner Losh #define ZSTD_CONTENTLOG_MIN 4
307*0c16b537SWarner Losh #define ZSTD_HASHLOG_MAX 28
308*0c16b537SWarner Losh #define ZSTD_HASHLOG_MIN 4
309*0c16b537SWarner Losh #define ZSTD_SEARCHLOG_MAX (ZSTD_CONTENTLOG_MAX-1)
310*0c16b537SWarner Losh #define ZSTD_SEARCHLOG_MIN 1
311*0c16b537SWarner Losh #define ZSTD_SEARCHLENGTH_MAX 7
312*0c16b537SWarner Losh #define ZSTD_SEARCHLENGTH_MIN 4
313*0c16b537SWarner Losh 
314*0c16b537SWarner Losh /** from faster to stronger */
315*0c16b537SWarner Losh typedef enum { ZSTD_fast, ZSTD_greedy, ZSTD_lazy, ZSTD_lazy2, ZSTD_btlazy2 } ZSTD_strategy;
316*0c16b537SWarner Losh 
317*0c16b537SWarner Losh typedef struct
318*0c16b537SWarner Losh {
319*0c16b537SWarner Losh     U64 srcSize;       /* optional : tells how much bytes are present in the frame. Use 0 if not known. */
320*0c16b537SWarner Losh     U32 windowLog;     /* largest match distance : larger == more compression, more memory needed during decompression */
321*0c16b537SWarner Losh     U32 contentLog;    /* full search segment : larger == more compression, slower, more memory (useless for fast) */
322*0c16b537SWarner Losh     U32 hashLog;       /* dispatch table : larger == more memory, faster */
323*0c16b537SWarner Losh     U32 searchLog;     /* nb of searches : larger == more compression, slower */
324*0c16b537SWarner Losh     U32 searchLength;  /* size of matches : larger == faster decompression, sometimes less compression */
325*0c16b537SWarner Losh     ZSTD_strategy strategy;
326*0c16b537SWarner Losh } ZSTD_parameters;
327*0c16b537SWarner Losh 
328*0c16b537SWarner Losh typedef ZSTDv04_Dctx ZSTD_DCtx;
329*0c16b537SWarner Losh 
330*0c16b537SWarner Losh /* *************************************
331*0c16b537SWarner Losh *  Advanced functions
332*0c16b537SWarner Losh ***************************************/
333*0c16b537SWarner Losh /** ZSTD_decompress_usingDict
334*0c16b537SWarner Losh *   Same as ZSTD_decompressDCtx, using a Dictionary content as prefix
335*0c16b537SWarner Losh *   Note : dict can be NULL, in which case, it's equivalent to ZSTD_decompressDCtx() */
336*0c16b537SWarner Losh static size_t ZSTD_decompress_usingDict(ZSTD_DCtx* ctx,
337*0c16b537SWarner Losh                                              void* dst, size_t maxDstSize,
338*0c16b537SWarner Losh                                        const void* src, size_t srcSize,
339*0c16b537SWarner Losh                                        const void* dict,size_t dictSize);
340*0c16b537SWarner Losh 
341*0c16b537SWarner Losh 
342*0c16b537SWarner Losh /* **************************************
343*0c16b537SWarner Losh *  Streaming functions (direct mode)
344*0c16b537SWarner Losh ****************************************/
345*0c16b537SWarner Losh static size_t ZSTD_resetDCtx(ZSTD_DCtx* dctx);
346*0c16b537SWarner Losh static size_t ZSTD_getFrameParams(ZSTD_parameters* params, const void* src, size_t srcSize);
347*0c16b537SWarner Losh static void   ZSTD_decompress_insertDictionary(ZSTD_DCtx* ctx, const void* src, size_t srcSize);
348*0c16b537SWarner Losh 
349*0c16b537SWarner Losh static size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx);
350*0c16b537SWarner Losh static size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize);
351*0c16b537SWarner Losh 
352*0c16b537SWarner Losh /**
353*0c16b537SWarner Losh   Streaming decompression, bufferless mode
354*0c16b537SWarner Losh 
355*0c16b537SWarner Losh   A ZSTD_DCtx object is required to track streaming operations.
356*0c16b537SWarner Losh   Use ZSTD_createDCtx() / ZSTD_freeDCtx() to manage it.
357*0c16b537SWarner Losh   A ZSTD_DCtx object can be re-used multiple times. Use ZSTD_resetDCtx() to return to fresh status.
358*0c16b537SWarner Losh 
359*0c16b537SWarner Losh   First operation is to retrieve frame parameters, using ZSTD_getFrameParams().
360*0c16b537SWarner Losh   This function doesn't consume its input. It needs enough input data to properly decode the frame header.
361*0c16b537SWarner Losh   Objective is to retrieve *params.windowlog, to know minimum amount of memory required during decoding.
362*0c16b537SWarner Losh   Result : 0 when successful, it means the ZSTD_parameters structure has been filled.
363*0c16b537SWarner Losh            >0 : means there is not enough data into src. Provides the expected size to successfully decode header.
364*0c16b537SWarner Losh            errorCode, which can be tested using ZSTD_isError() (For example, if it's not a ZSTD header)
365*0c16b537SWarner Losh 
366*0c16b537SWarner Losh   Then, you can optionally insert a dictionary.
367*0c16b537SWarner Losh   This operation must mimic the compressor behavior, otherwise decompression will fail or be corrupted.
368*0c16b537SWarner Losh 
369*0c16b537SWarner Losh   Then it's possible to start decompression.
370*0c16b537SWarner Losh   Use ZSTD_nextSrcSizeToDecompress() and ZSTD_decompressContinue() alternatively.
371*0c16b537SWarner Losh   ZSTD_nextSrcSizeToDecompress() tells how much bytes to provide as 'srcSize' to ZSTD_decompressContinue().
372*0c16b537SWarner Losh   ZSTD_decompressContinue() requires this exact amount of bytes, or it will fail.
373*0c16b537SWarner Losh   ZSTD_decompressContinue() needs previous data blocks during decompression, up to (1 << windowlog).
374*0c16b537SWarner Losh   They should preferably be located contiguously, prior to current block. Alternatively, a round buffer is also possible.
375*0c16b537SWarner Losh 
376*0c16b537SWarner Losh   @result of ZSTD_decompressContinue() is the number of bytes regenerated within 'dst'.
377*0c16b537SWarner Losh   It can be zero, which is not an error; it just means ZSTD_decompressContinue() has decoded some header.
378*0c16b537SWarner Losh 
379*0c16b537SWarner Losh   A frame is fully decoded when ZSTD_nextSrcSizeToDecompress() returns zero.
380*0c16b537SWarner Losh   Context can then be reset to start a new decompression.
381*0c16b537SWarner Losh */
382*0c16b537SWarner Losh 
383*0c16b537SWarner Losh 
384*0c16b537SWarner Losh #if defined (__cplusplus)
385*0c16b537SWarner Losh }
386*0c16b537SWarner Losh #endif
387*0c16b537SWarner Losh 
388*0c16b537SWarner Losh 
389*0c16b537SWarner Losh #endif  /* ZSTD_STATIC_H */
390*0c16b537SWarner Losh 
391*0c16b537SWarner Losh 
392*0c16b537SWarner Losh /*
393*0c16b537SWarner Losh     zstd_internal - common functions to include
394*0c16b537SWarner Losh     Header File for include
395*0c16b537SWarner Losh     Copyright (C) 2014-2015, Yann Collet.
396*0c16b537SWarner Losh 
397*0c16b537SWarner Losh     BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
398*0c16b537SWarner Losh 
399*0c16b537SWarner Losh     Redistribution and use in source and binary forms, with or without
400*0c16b537SWarner Losh     modification, are permitted provided that the following conditions are
401*0c16b537SWarner Losh     met:
402*0c16b537SWarner Losh     * Redistributions of source code must retain the above copyright
403*0c16b537SWarner Losh     notice, this list of conditions and the following disclaimer.
404*0c16b537SWarner Losh     * Redistributions in binary form must reproduce the above
405*0c16b537SWarner Losh     copyright notice, this list of conditions and the following disclaimer
406*0c16b537SWarner Losh     in the documentation and/or other materials provided with the
407*0c16b537SWarner Losh     distribution.
408*0c16b537SWarner Losh     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
409*0c16b537SWarner Losh     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
410*0c16b537SWarner Losh     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
411*0c16b537SWarner Losh     A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
412*0c16b537SWarner Losh     OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
413*0c16b537SWarner Losh     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
414*0c16b537SWarner Losh     LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
415*0c16b537SWarner Losh     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
416*0c16b537SWarner Losh     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
417*0c16b537SWarner Losh     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
418*0c16b537SWarner Losh     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
419*0c16b537SWarner Losh 
420*0c16b537SWarner Losh     You can contact the author at :
421*0c16b537SWarner Losh     - zstd source repository : https://github.com/Cyan4973/zstd
422*0c16b537SWarner Losh     - ztsd public forum : https://groups.google.com/forum/#!forum/lz4c
423*0c16b537SWarner Losh */
424*0c16b537SWarner Losh #ifndef ZSTD_CCOMMON_H_MODULE
425*0c16b537SWarner Losh #define ZSTD_CCOMMON_H_MODULE
426*0c16b537SWarner Losh 
427*0c16b537SWarner Losh #if defined (__cplusplus)
428*0c16b537SWarner Losh extern "C" {
429*0c16b537SWarner Losh #endif
430*0c16b537SWarner Losh 
431*0c16b537SWarner Losh /* *************************************
432*0c16b537SWarner Losh *  Common macros
433*0c16b537SWarner Losh ***************************************/
434*0c16b537SWarner Losh #define MIN(a,b) ((a)<(b) ? (a) : (b))
435*0c16b537SWarner Losh #define MAX(a,b) ((a)>(b) ? (a) : (b))
436*0c16b537SWarner Losh 
437*0c16b537SWarner Losh 
438*0c16b537SWarner Losh /* *************************************
439*0c16b537SWarner Losh *  Common constants
440*0c16b537SWarner Losh ***************************************/
441*0c16b537SWarner Losh #define ZSTD_MAGICNUMBER 0xFD2FB524   /* v0.4 */
442*0c16b537SWarner Losh 
443*0c16b537SWarner Losh #define KB *(1 <<10)
444*0c16b537SWarner Losh #define MB *(1 <<20)
445*0c16b537SWarner Losh #define GB *(1U<<30)
446*0c16b537SWarner Losh 
447*0c16b537SWarner Losh #define BLOCKSIZE (128 KB)                 /* define, for static allocation */
448*0c16b537SWarner Losh 
449*0c16b537SWarner Losh static const size_t ZSTD_blockHeaderSize = 3;
450*0c16b537SWarner Losh static const size_t ZSTD_frameHeaderSize_min = 5;
451*0c16b537SWarner Losh #define ZSTD_frameHeaderSize_max 5         /* define, for static allocation */
452*0c16b537SWarner Losh 
453*0c16b537SWarner Losh #define BIT7 128
454*0c16b537SWarner Losh #define BIT6  64
455*0c16b537SWarner Losh #define BIT5  32
456*0c16b537SWarner Losh #define BIT4  16
457*0c16b537SWarner Losh #define BIT1   2
458*0c16b537SWarner Losh #define BIT0   1
459*0c16b537SWarner Losh 
460*0c16b537SWarner Losh #define IS_RAW BIT0
461*0c16b537SWarner Losh #define IS_RLE BIT1
462*0c16b537SWarner Losh 
463*0c16b537SWarner Losh #define MINMATCH 4
464*0c16b537SWarner Losh #define REPCODE_STARTVALUE 4
465*0c16b537SWarner Losh 
466*0c16b537SWarner Losh #define MLbits   7
467*0c16b537SWarner Losh #define LLbits   6
468*0c16b537SWarner Losh #define Offbits  5
469*0c16b537SWarner Losh #define MaxML  ((1<<MLbits) - 1)
470*0c16b537SWarner Losh #define MaxLL  ((1<<LLbits) - 1)
471*0c16b537SWarner Losh #define MaxOff ((1<<Offbits)- 1)
472*0c16b537SWarner Losh #define MLFSELog   10
473*0c16b537SWarner Losh #define LLFSELog   10
474*0c16b537SWarner Losh #define OffFSELog   9
475*0c16b537SWarner Losh #define MaxSeq MAX(MaxLL, MaxML)
476*0c16b537SWarner Losh 
477*0c16b537SWarner Losh #define MIN_SEQUENCES_SIZE (2 /*seqNb*/ + 2 /*dumps*/ + 3 /*seqTables*/ + 1 /*bitStream*/)
478*0c16b537SWarner Losh #define MIN_CBLOCK_SIZE (3 /*litCSize*/ + MIN_SEQUENCES_SIZE)
479*0c16b537SWarner Losh 
480*0c16b537SWarner Losh typedef enum { bt_compressed, bt_raw, bt_rle, bt_end } blockType_t;
481*0c16b537SWarner Losh 
482*0c16b537SWarner Losh 
483*0c16b537SWarner Losh /* ******************************************
484*0c16b537SWarner Losh *  Shared functions to include for inlining
485*0c16b537SWarner Losh ********************************************/
486*0c16b537SWarner Losh static void ZSTD_copy8(void* dst, const void* src) { memcpy(dst, src, 8); }
487*0c16b537SWarner Losh 
488*0c16b537SWarner Losh #define COPY8(d,s) { ZSTD_copy8(d,s); d+=8; s+=8; }
489*0c16b537SWarner Losh 
490*0c16b537SWarner Losh /*! ZSTD_wildcopy : custom version of memcpy(), can copy up to 7-8 bytes too many */
491*0c16b537SWarner Losh static void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length)
492*0c16b537SWarner Losh {
493*0c16b537SWarner Losh     const BYTE* ip = (const BYTE*)src;
494*0c16b537SWarner Losh     BYTE* op = (BYTE*)dst;
495*0c16b537SWarner Losh     BYTE* const oend = op + length;
496*0c16b537SWarner Losh     do
497*0c16b537SWarner Losh         COPY8(op, ip)
498*0c16b537SWarner Losh     while (op < oend);
499*0c16b537SWarner Losh }
500*0c16b537SWarner Losh 
501*0c16b537SWarner Losh 
502*0c16b537SWarner Losh #if defined (__cplusplus)
503*0c16b537SWarner Losh }
504*0c16b537SWarner Losh #endif
505*0c16b537SWarner Losh 
506*0c16b537SWarner Losh 
507*0c16b537SWarner Losh /* ******************************************************************
508*0c16b537SWarner Losh    FSE : Finite State Entropy coder
509*0c16b537SWarner Losh    header file
510*0c16b537SWarner Losh    Copyright (C) 2013-2015, Yann Collet.
511*0c16b537SWarner Losh 
512*0c16b537SWarner Losh    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
513*0c16b537SWarner Losh 
514*0c16b537SWarner Losh    Redistribution and use in source and binary forms, with or without
515*0c16b537SWarner Losh    modification, are permitted provided that the following conditions are
516*0c16b537SWarner Losh    met:
517*0c16b537SWarner Losh 
518*0c16b537SWarner Losh        * Redistributions of source code must retain the above copyright
519*0c16b537SWarner Losh    notice, this list of conditions and the following disclaimer.
520*0c16b537SWarner Losh        * Redistributions in binary form must reproduce the above
521*0c16b537SWarner Losh    copyright notice, this list of conditions and the following disclaimer
522*0c16b537SWarner Losh    in the documentation and/or other materials provided with the
523*0c16b537SWarner Losh    distribution.
524*0c16b537SWarner Losh 
525*0c16b537SWarner Losh    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
526*0c16b537SWarner Losh    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
527*0c16b537SWarner Losh    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
528*0c16b537SWarner Losh    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
529*0c16b537SWarner Losh    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
530*0c16b537SWarner Losh    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
531*0c16b537SWarner Losh    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
532*0c16b537SWarner Losh    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
533*0c16b537SWarner Losh    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
534*0c16b537SWarner Losh    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
535*0c16b537SWarner Losh    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
536*0c16b537SWarner Losh 
537*0c16b537SWarner Losh    You can contact the author at :
538*0c16b537SWarner Losh    - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
539*0c16b537SWarner Losh    - Public forum : https://groups.google.com/forum/#!forum/lz4c
540*0c16b537SWarner Losh ****************************************************************** */
541*0c16b537SWarner Losh #ifndef FSE_H
542*0c16b537SWarner Losh #define FSE_H
543*0c16b537SWarner Losh 
544*0c16b537SWarner Losh #if defined (__cplusplus)
545*0c16b537SWarner Losh extern "C" {
546*0c16b537SWarner Losh #endif
547*0c16b537SWarner Losh 
548*0c16b537SWarner Losh 
549*0c16b537SWarner Losh /* *****************************************
550*0c16b537SWarner Losh *  Includes
551*0c16b537SWarner Losh ******************************************/
552*0c16b537SWarner Losh #include <stddef.h>    /* size_t, ptrdiff_t */
553*0c16b537SWarner Losh 
554*0c16b537SWarner Losh 
555*0c16b537SWarner Losh /* *****************************************
556*0c16b537SWarner Losh *  FSE simple functions
557*0c16b537SWarner Losh ******************************************/
558*0c16b537SWarner Losh static size_t FSE_decompress(void* dst,  size_t maxDstSize,
559*0c16b537SWarner Losh                 const void* cSrc, size_t cSrcSize);
560*0c16b537SWarner Losh /*!
561*0c16b537SWarner Losh FSE_decompress():
562*0c16b537SWarner Losh     Decompress FSE data from buffer 'cSrc', of size 'cSrcSize',
563*0c16b537SWarner Losh     into already allocated destination buffer 'dst', of size 'maxDstSize'.
564*0c16b537SWarner Losh     return : size of regenerated data (<= maxDstSize)
565*0c16b537SWarner Losh              or an error code, which can be tested using FSE_isError()
566*0c16b537SWarner Losh 
567*0c16b537SWarner Losh     ** Important ** : FSE_decompress() doesn't decompress non-compressible nor RLE data !!!
568*0c16b537SWarner Losh     Why ? : making this distinction requires a header.
569*0c16b537SWarner Losh     Header management is intentionally delegated to the user layer, which can better manage special cases.
570*0c16b537SWarner Losh */
571*0c16b537SWarner Losh 
572*0c16b537SWarner Losh 
573*0c16b537SWarner Losh /* *****************************************
574*0c16b537SWarner Losh *  Tool functions
575*0c16b537SWarner Losh ******************************************/
576*0c16b537SWarner Losh /* Error Management */
577*0c16b537SWarner Losh static unsigned    FSE_isError(size_t code);        /* tells if a return value is an error code */
578*0c16b537SWarner Losh 
579*0c16b537SWarner Losh 
580*0c16b537SWarner Losh 
581*0c16b537SWarner Losh /* *****************************************
582*0c16b537SWarner Losh *  FSE detailed API
583*0c16b537SWarner Losh ******************************************/
584*0c16b537SWarner Losh /*!
585*0c16b537SWarner Losh FSE_compress() does the following:
586*0c16b537SWarner Losh 1. count symbol occurrence from source[] into table count[]
587*0c16b537SWarner Losh 2. normalize counters so that sum(count[]) == Power_of_2 (2^tableLog)
588*0c16b537SWarner Losh 3. save normalized counters to memory buffer using writeNCount()
589*0c16b537SWarner Losh 4. build encoding table 'CTable' from normalized counters
590*0c16b537SWarner Losh 5. encode the data stream using encoding table 'CTable'
591*0c16b537SWarner Losh 
592*0c16b537SWarner Losh FSE_decompress() does the following:
593*0c16b537SWarner Losh 1. read normalized counters with readNCount()
594*0c16b537SWarner Losh 2. build decoding table 'DTable' from normalized counters
595*0c16b537SWarner Losh 3. decode the data stream using decoding table 'DTable'
596*0c16b537SWarner Losh 
597*0c16b537SWarner Losh The following API allows targeting specific sub-functions for advanced tasks.
598*0c16b537SWarner Losh For example, it's possible to compress several blocks using the same 'CTable',
599*0c16b537SWarner Losh or to save and provide normalized distribution using external method.
600*0c16b537SWarner Losh */
601*0c16b537SWarner Losh 
602*0c16b537SWarner Losh 
603*0c16b537SWarner Losh /* *** DECOMPRESSION *** */
604*0c16b537SWarner Losh 
605*0c16b537SWarner Losh /*!
606*0c16b537SWarner Losh FSE_readNCount():
607*0c16b537SWarner Losh    Read compactly saved 'normalizedCounter' from 'rBuffer'.
608*0c16b537SWarner Losh    return : size read from 'rBuffer'
609*0c16b537SWarner Losh             or an errorCode, which can be tested using FSE_isError()
610*0c16b537SWarner Losh             maxSymbolValuePtr[0] and tableLogPtr[0] will also be updated with their respective values */
611*0c16b537SWarner Losh static  size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSymbolValuePtr, unsigned* tableLogPtr, const void* rBuffer, size_t rBuffSize);
612*0c16b537SWarner Losh 
613*0c16b537SWarner Losh /*!
614*0c16b537SWarner Losh Constructor and Destructor of type FSE_DTable
615*0c16b537SWarner Losh     Note that its size depends on 'tableLog' */
616*0c16b537SWarner Losh typedef unsigned FSE_DTable;   /* don't allocate that. It's just a way to be more restrictive than void* */
617*0c16b537SWarner Losh 
618*0c16b537SWarner Losh /*!
619*0c16b537SWarner Losh FSE_buildDTable():
620*0c16b537SWarner Losh    Builds 'dt', which must be already allocated, using FSE_createDTable()
621*0c16b537SWarner Losh    return : 0,
622*0c16b537SWarner Losh             or an errorCode, which can be tested using FSE_isError() */
623*0c16b537SWarner Losh static size_t FSE_buildDTable ( FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);
624*0c16b537SWarner Losh 
625*0c16b537SWarner Losh /*!
626*0c16b537SWarner Losh FSE_decompress_usingDTable():
627*0c16b537SWarner Losh    Decompress compressed source 'cSrc' of size 'cSrcSize' using 'dt'
628*0c16b537SWarner Losh    into 'dst' which must be already allocated.
629*0c16b537SWarner Losh    return : size of regenerated data (necessarily <= maxDstSize)
630*0c16b537SWarner Losh             or an errorCode, which can be tested using FSE_isError() */
631*0c16b537SWarner Losh static  size_t FSE_decompress_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const FSE_DTable* dt);
632*0c16b537SWarner Losh 
633*0c16b537SWarner Losh /*!
634*0c16b537SWarner Losh Tutorial :
635*0c16b537SWarner Losh ----------
636*0c16b537SWarner Losh (Note : these functions only decompress FSE-compressed blocks.
637*0c16b537SWarner Losh  If block is uncompressed, use memcpy() instead
638*0c16b537SWarner Losh  If block is a single repeated byte, use memset() instead )
639*0c16b537SWarner Losh 
640*0c16b537SWarner Losh The first step is to obtain the normalized frequencies of symbols.
641*0c16b537SWarner Losh This can be performed by FSE_readNCount() if it was saved using FSE_writeNCount().
642*0c16b537SWarner Losh 'normalizedCounter' must be already allocated, and have at least 'maxSymbolValuePtr[0]+1' cells of signed short.
643*0c16b537SWarner Losh In practice, that means it's necessary to know 'maxSymbolValue' beforehand,
644*0c16b537SWarner Losh or size the table to handle worst case situations (typically 256).
645*0c16b537SWarner Losh FSE_readNCount() will provide 'tableLog' and 'maxSymbolValue'.
646*0c16b537SWarner Losh The result of FSE_readNCount() is the number of bytes read from 'rBuffer'.
647*0c16b537SWarner Losh Note that 'rBufferSize' must be at least 4 bytes, even if useful information is less than that.
648*0c16b537SWarner Losh If there is an error, the function will return an error code, which can be tested using FSE_isError().
649*0c16b537SWarner Losh 
650*0c16b537SWarner Losh The next step is to build the decompression tables 'FSE_DTable' from 'normalizedCounter'.
651*0c16b537SWarner Losh This is performed by the function FSE_buildDTable().
652*0c16b537SWarner Losh The space required by 'FSE_DTable' must be already allocated using FSE_createDTable().
653*0c16b537SWarner Losh If there is an error, the function will return an error code, which can be tested using FSE_isError().
654*0c16b537SWarner Losh 
655*0c16b537SWarner Losh 'FSE_DTable' can then be used to decompress 'cSrc', with FSE_decompress_usingDTable().
656*0c16b537SWarner Losh 'cSrcSize' must be strictly correct, otherwise decompression will fail.
657*0c16b537SWarner Losh FSE_decompress_usingDTable() result will tell how many bytes were regenerated (<=maxDstSize).
658*0c16b537SWarner Losh If there is an error, the function will return an error code, which can be tested using FSE_isError(). (ex: dst buffer too small)
659*0c16b537SWarner Losh */
660*0c16b537SWarner Losh 
661*0c16b537SWarner Losh 
662*0c16b537SWarner Losh #if defined (__cplusplus)
663*0c16b537SWarner Losh }
664*0c16b537SWarner Losh #endif
665*0c16b537SWarner Losh 
666*0c16b537SWarner Losh #endif  /* FSE_H */
667*0c16b537SWarner Losh 
668*0c16b537SWarner Losh 
669*0c16b537SWarner Losh /* ******************************************************************
670*0c16b537SWarner Losh    bitstream
671*0c16b537SWarner Losh    Part of NewGen Entropy library
672*0c16b537SWarner Losh    header file (to include)
673*0c16b537SWarner Losh    Copyright (C) 2013-2015, Yann Collet.
674*0c16b537SWarner Losh 
675*0c16b537SWarner Losh    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
676*0c16b537SWarner Losh 
677*0c16b537SWarner Losh    Redistribution and use in source and binary forms, with or without
678*0c16b537SWarner Losh    modification, are permitted provided that the following conditions are
679*0c16b537SWarner Losh    met:
680*0c16b537SWarner Losh 
681*0c16b537SWarner Losh        * Redistributions of source code must retain the above copyright
682*0c16b537SWarner Losh    notice, this list of conditions and the following disclaimer.
683*0c16b537SWarner Losh        * Redistributions in binary form must reproduce the above
684*0c16b537SWarner Losh    copyright notice, this list of conditions and the following disclaimer
685*0c16b537SWarner Losh    in the documentation and/or other materials provided with the
686*0c16b537SWarner Losh    distribution.
687*0c16b537SWarner Losh 
688*0c16b537SWarner Losh    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
689*0c16b537SWarner Losh    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
690*0c16b537SWarner Losh    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
691*0c16b537SWarner Losh    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
692*0c16b537SWarner Losh    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
693*0c16b537SWarner Losh    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
694*0c16b537SWarner Losh    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
695*0c16b537SWarner Losh    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
696*0c16b537SWarner Losh    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
697*0c16b537SWarner Losh    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
698*0c16b537SWarner Losh    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
699*0c16b537SWarner Losh 
700*0c16b537SWarner Losh    You can contact the author at :
701*0c16b537SWarner Losh    - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
702*0c16b537SWarner Losh    - Public forum : https://groups.google.com/forum/#!forum/lz4c
703*0c16b537SWarner Losh ****************************************************************** */
704*0c16b537SWarner Losh #ifndef BITSTREAM_H_MODULE
705*0c16b537SWarner Losh #define BITSTREAM_H_MODULE
706*0c16b537SWarner Losh 
707*0c16b537SWarner Losh #if defined (__cplusplus)
708*0c16b537SWarner Losh extern "C" {
709*0c16b537SWarner Losh #endif
710*0c16b537SWarner Losh 
711*0c16b537SWarner Losh 
712*0c16b537SWarner Losh /*
713*0c16b537SWarner Losh *  This API consists of small unitary functions, which highly benefit from being inlined.
714*0c16b537SWarner Losh *  Since link-time-optimization is not available for all compilers,
715*0c16b537SWarner Losh *  these functions are defined into a .h to be included.
716*0c16b537SWarner Losh */
717*0c16b537SWarner Losh 
718*0c16b537SWarner Losh /**********************************************
719*0c16b537SWarner Losh *  bitStream decompression API (read backward)
720*0c16b537SWarner Losh **********************************************/
721*0c16b537SWarner Losh typedef struct
722*0c16b537SWarner Losh {
723*0c16b537SWarner Losh     size_t   bitContainer;
724*0c16b537SWarner Losh     unsigned bitsConsumed;
725*0c16b537SWarner Losh     const char* ptr;
726*0c16b537SWarner Losh     const char* start;
727*0c16b537SWarner Losh } BIT_DStream_t;
728*0c16b537SWarner Losh 
729*0c16b537SWarner Losh typedef enum { BIT_DStream_unfinished = 0,
730*0c16b537SWarner Losh                BIT_DStream_endOfBuffer = 1,
731*0c16b537SWarner Losh                BIT_DStream_completed = 2,
732*0c16b537SWarner Losh                BIT_DStream_overflow = 3 } BIT_DStream_status;  /* result of BIT_reloadDStream() */
733*0c16b537SWarner Losh                /* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */
734*0c16b537SWarner Losh 
735*0c16b537SWarner Losh MEM_STATIC size_t   BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize);
736*0c16b537SWarner Losh MEM_STATIC size_t   BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits);
737*0c16b537SWarner Losh MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD);
738*0c16b537SWarner Losh MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD);
739*0c16b537SWarner Losh 
740*0c16b537SWarner Losh 
741*0c16b537SWarner Losh /*
742*0c16b537SWarner Losh * Start by invoking BIT_initDStream().
743*0c16b537SWarner Losh * A chunk of the bitStream is then stored into a local register.
744*0c16b537SWarner Losh * Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
745*0c16b537SWarner Losh * You can then retrieve bitFields stored into the local register, **in reverse order**.
746*0c16b537SWarner Losh * Local register is manually filled from memory by the BIT_reloadDStream() method.
747*0c16b537SWarner Losh * A reload guarantee a minimum of ((8*sizeof(size_t))-7) bits when its result is BIT_DStream_unfinished.
748*0c16b537SWarner Losh * Otherwise, it can be less than that, so proceed accordingly.
749*0c16b537SWarner Losh * Checking if DStream has reached its end can be performed with BIT_endOfDStream()
750*0c16b537SWarner Losh */
751*0c16b537SWarner Losh 
752*0c16b537SWarner Losh 
753*0c16b537SWarner Losh /******************************************
754*0c16b537SWarner Losh *  unsafe API
755*0c16b537SWarner Losh ******************************************/
756*0c16b537SWarner Losh MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits);
757*0c16b537SWarner Losh /* faster, but works only if nbBits >= 1 */
758*0c16b537SWarner Losh 
759*0c16b537SWarner Losh 
760*0c16b537SWarner Losh 
761*0c16b537SWarner Losh /****************************************************************
762*0c16b537SWarner Losh *  Helper functions
763*0c16b537SWarner Losh ****************************************************************/
764*0c16b537SWarner Losh MEM_STATIC unsigned BIT_highbit32 (register U32 val)
765*0c16b537SWarner Losh {
766*0c16b537SWarner Losh #   if defined(_MSC_VER)   /* Visual */
767*0c16b537SWarner Losh     unsigned long r=0;
768*0c16b537SWarner Losh     _BitScanReverse ( &r, val );
769*0c16b537SWarner Losh     return (unsigned) r;
770*0c16b537SWarner Losh #   elif defined(__GNUC__) && (__GNUC__ >= 3)   /* Use GCC Intrinsic */
771*0c16b537SWarner Losh     return 31 - __builtin_clz (val);
772*0c16b537SWarner Losh #   else   /* Software version */
773*0c16b537SWarner 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 };
774*0c16b537SWarner Losh     U32 v = val;
775*0c16b537SWarner Losh     unsigned r;
776*0c16b537SWarner Losh     v |= v >> 1;
777*0c16b537SWarner Losh     v |= v >> 2;
778*0c16b537SWarner Losh     v |= v >> 4;
779*0c16b537SWarner Losh     v |= v >> 8;
780*0c16b537SWarner Losh     v |= v >> 16;
781*0c16b537SWarner Losh     r = DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27];
782*0c16b537SWarner Losh     return r;
783*0c16b537SWarner Losh #   endif
784*0c16b537SWarner Losh }
785*0c16b537SWarner Losh 
786*0c16b537SWarner Losh 
787*0c16b537SWarner Losh /**********************************************************
788*0c16b537SWarner Losh * bitStream decoding
789*0c16b537SWarner Losh **********************************************************/
790*0c16b537SWarner Losh 
791*0c16b537SWarner Losh /*!BIT_initDStream
792*0c16b537SWarner Losh *  Initialize a BIT_DStream_t.
793*0c16b537SWarner Losh *  @bitD : a pointer to an already allocated BIT_DStream_t structure
794*0c16b537SWarner Losh *  @srcBuffer must point at the beginning of a bitStream
795*0c16b537SWarner Losh *  @srcSize must be the exact size of the bitStream
796*0c16b537SWarner Losh *  @result : size of stream (== srcSize) or an errorCode if a problem is detected
797*0c16b537SWarner Losh */
798*0c16b537SWarner Losh MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize)
799*0c16b537SWarner Losh {
800*0c16b537SWarner Losh     if (srcSize < 1) { memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); }
801*0c16b537SWarner Losh 
802*0c16b537SWarner Losh     if (srcSize >=  sizeof(size_t))   /* normal case */
803*0c16b537SWarner Losh     {
804*0c16b537SWarner Losh         U32 contain32;
805*0c16b537SWarner Losh         bitD->start = (const char*)srcBuffer;
806*0c16b537SWarner Losh         bitD->ptr   = (const char*)srcBuffer + srcSize - sizeof(size_t);
807*0c16b537SWarner Losh         bitD->bitContainer = MEM_readLEST(bitD->ptr);
808*0c16b537SWarner Losh         contain32 = ((const BYTE*)srcBuffer)[srcSize-1];
809*0c16b537SWarner Losh         if (contain32 == 0) return ERROR(GENERIC);   /* endMark not present */
810*0c16b537SWarner Losh         bitD->bitsConsumed = 8 - BIT_highbit32(contain32);
811*0c16b537SWarner Losh     }
812*0c16b537SWarner Losh     else
813*0c16b537SWarner Losh     {
814*0c16b537SWarner Losh         U32 contain32;
815*0c16b537SWarner Losh         bitD->start = (const char*)srcBuffer;
816*0c16b537SWarner Losh         bitD->ptr   = bitD->start;
817*0c16b537SWarner Losh         bitD->bitContainer = *(const BYTE*)(bitD->start);
818*0c16b537SWarner Losh         switch(srcSize)
819*0c16b537SWarner Losh         {
820*0c16b537SWarner Losh             case 7: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[6]) << (sizeof(size_t)*8 - 16);/* fall-through */
821*0c16b537SWarner Losh             case 6: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[5]) << (sizeof(size_t)*8 - 24);/* fall-through */
822*0c16b537SWarner Losh             case 5: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[4]) << (sizeof(size_t)*8 - 32);/* fall-through */
823*0c16b537SWarner Losh             case 4: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[3]) << 24; /* fall-through */
824*0c16b537SWarner Losh             case 3: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[2]) << 16; /* fall-through */
825*0c16b537SWarner Losh             case 2: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[1]) <<  8; /* fall-through */
826*0c16b537SWarner Losh             default: break;
827*0c16b537SWarner Losh         }
828*0c16b537SWarner Losh         contain32 = ((const BYTE*)srcBuffer)[srcSize-1];
829*0c16b537SWarner Losh         if (contain32 == 0) return ERROR(GENERIC);   /* endMark not present */
830*0c16b537SWarner Losh         bitD->bitsConsumed = 8 - BIT_highbit32(contain32);
831*0c16b537SWarner Losh         bitD->bitsConsumed += (U32)(sizeof(size_t) - srcSize)*8;
832*0c16b537SWarner Losh     }
833*0c16b537SWarner Losh 
834*0c16b537SWarner Losh     return srcSize;
835*0c16b537SWarner Losh }
836*0c16b537SWarner Losh 
837*0c16b537SWarner Losh /*!BIT_lookBits
838*0c16b537SWarner Losh  * Provides next n bits from local register
839*0c16b537SWarner Losh  * local register is not modified (bits are still present for next read/look)
840*0c16b537SWarner Losh  * On 32-bits, maxNbBits==25
841*0c16b537SWarner Losh  * On 64-bits, maxNbBits==57
842*0c16b537SWarner Losh  * @return : value extracted
843*0c16b537SWarner Losh  */
844*0c16b537SWarner Losh MEM_STATIC size_t BIT_lookBits(BIT_DStream_t* bitD, U32 nbBits)
845*0c16b537SWarner Losh {
846*0c16b537SWarner Losh     const U32 bitMask = sizeof(bitD->bitContainer)*8 - 1;
847*0c16b537SWarner Losh     return ((bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> 1) >> ((bitMask-nbBits) & bitMask);
848*0c16b537SWarner Losh }
849*0c16b537SWarner Losh 
850*0c16b537SWarner Losh /*! BIT_lookBitsFast :
851*0c16b537SWarner Losh *   unsafe version; only works only if nbBits >= 1 */
852*0c16b537SWarner Losh MEM_STATIC size_t BIT_lookBitsFast(BIT_DStream_t* bitD, U32 nbBits)
853*0c16b537SWarner Losh {
854*0c16b537SWarner Losh     const U32 bitMask = sizeof(bitD->bitContainer)*8 - 1;
855*0c16b537SWarner Losh     return (bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> (((bitMask+1)-nbBits) & bitMask);
856*0c16b537SWarner Losh }
857*0c16b537SWarner Losh 
858*0c16b537SWarner Losh MEM_STATIC void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)
859*0c16b537SWarner Losh {
860*0c16b537SWarner Losh     bitD->bitsConsumed += nbBits;
861*0c16b537SWarner Losh }
862*0c16b537SWarner Losh 
863*0c16b537SWarner Losh /*!BIT_readBits
864*0c16b537SWarner Losh  * Read next n bits from local register.
865*0c16b537SWarner Losh  * pay attention to not read more than nbBits contained into local register.
866*0c16b537SWarner Losh  * @return : extracted value.
867*0c16b537SWarner Losh  */
868*0c16b537SWarner Losh MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, U32 nbBits)
869*0c16b537SWarner Losh {
870*0c16b537SWarner Losh     size_t value = BIT_lookBits(bitD, nbBits);
871*0c16b537SWarner Losh     BIT_skipBits(bitD, nbBits);
872*0c16b537SWarner Losh     return value;
873*0c16b537SWarner Losh }
874*0c16b537SWarner Losh 
875*0c16b537SWarner Losh /*!BIT_readBitsFast :
876*0c16b537SWarner Losh *  unsafe version; only works only if nbBits >= 1 */
877*0c16b537SWarner Losh MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, U32 nbBits)
878*0c16b537SWarner Losh {
879*0c16b537SWarner Losh     size_t value = BIT_lookBitsFast(bitD, nbBits);
880*0c16b537SWarner Losh     BIT_skipBits(bitD, nbBits);
881*0c16b537SWarner Losh     return value;
882*0c16b537SWarner Losh }
883*0c16b537SWarner Losh 
884*0c16b537SWarner Losh MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD)
885*0c16b537SWarner Losh {
886*0c16b537SWarner Losh     if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8))  /* should never happen */
887*0c16b537SWarner Losh         return BIT_DStream_overflow;
888*0c16b537SWarner Losh 
889*0c16b537SWarner Losh     if (bitD->ptr >= bitD->start + sizeof(bitD->bitContainer))
890*0c16b537SWarner Losh     {
891*0c16b537SWarner Losh         bitD->ptr -= bitD->bitsConsumed >> 3;
892*0c16b537SWarner Losh         bitD->bitsConsumed &= 7;
893*0c16b537SWarner Losh         bitD->bitContainer = MEM_readLEST(bitD->ptr);
894*0c16b537SWarner Losh         return BIT_DStream_unfinished;
895*0c16b537SWarner Losh     }
896*0c16b537SWarner Losh     if (bitD->ptr == bitD->start)
897*0c16b537SWarner Losh     {
898*0c16b537SWarner Losh         if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BIT_DStream_endOfBuffer;
899*0c16b537SWarner Losh         return BIT_DStream_completed;
900*0c16b537SWarner Losh     }
901*0c16b537SWarner Losh     {
902*0c16b537SWarner Losh         U32 nbBytes = bitD->bitsConsumed >> 3;
903*0c16b537SWarner Losh         BIT_DStream_status result = BIT_DStream_unfinished;
904*0c16b537SWarner Losh         if (bitD->ptr - nbBytes < bitD->start)
905*0c16b537SWarner Losh         {
906*0c16b537SWarner Losh             nbBytes = (U32)(bitD->ptr - bitD->start);  /* ptr > start */
907*0c16b537SWarner Losh             result = BIT_DStream_endOfBuffer;
908*0c16b537SWarner Losh         }
909*0c16b537SWarner Losh         bitD->ptr -= nbBytes;
910*0c16b537SWarner Losh         bitD->bitsConsumed -= nbBytes*8;
911*0c16b537SWarner Losh         bitD->bitContainer = MEM_readLEST(bitD->ptr);   /* reminder : srcSize > sizeof(bitD) */
912*0c16b537SWarner Losh         return result;
913*0c16b537SWarner Losh     }
914*0c16b537SWarner Losh }
915*0c16b537SWarner Losh 
916*0c16b537SWarner Losh /*! BIT_endOfDStream
917*0c16b537SWarner Losh *   @return Tells if DStream has reached its exact end
918*0c16b537SWarner Losh */
919*0c16b537SWarner Losh MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* DStream)
920*0c16b537SWarner Losh {
921*0c16b537SWarner Losh     return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer)*8));
922*0c16b537SWarner Losh }
923*0c16b537SWarner Losh 
924*0c16b537SWarner Losh #if defined (__cplusplus)
925*0c16b537SWarner Losh }
926*0c16b537SWarner Losh #endif
927*0c16b537SWarner Losh 
928*0c16b537SWarner Losh #endif /* BITSTREAM_H_MODULE */
929*0c16b537SWarner Losh 
930*0c16b537SWarner Losh 
931*0c16b537SWarner Losh 
932*0c16b537SWarner Losh /* ******************************************************************
933*0c16b537SWarner Losh    FSE : Finite State Entropy coder
934*0c16b537SWarner Losh    header file for static linking (only)
935*0c16b537SWarner Losh    Copyright (C) 2013-2015, Yann Collet
936*0c16b537SWarner Losh 
937*0c16b537SWarner Losh    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
938*0c16b537SWarner Losh 
939*0c16b537SWarner Losh    Redistribution and use in source and binary forms, with or without
940*0c16b537SWarner Losh    modification, are permitted provided that the following conditions are
941*0c16b537SWarner Losh    met:
942*0c16b537SWarner Losh 
943*0c16b537SWarner Losh        * Redistributions of source code must retain the above copyright
944*0c16b537SWarner Losh    notice, this list of conditions and the following disclaimer.
945*0c16b537SWarner Losh        * Redistributions in binary form must reproduce the above
946*0c16b537SWarner Losh    copyright notice, this list of conditions and the following disclaimer
947*0c16b537SWarner Losh    in the documentation and/or other materials provided with the
948*0c16b537SWarner Losh    distribution.
949*0c16b537SWarner Losh 
950*0c16b537SWarner Losh    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
951*0c16b537SWarner Losh    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
952*0c16b537SWarner Losh    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
953*0c16b537SWarner Losh    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
954*0c16b537SWarner Losh    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
955*0c16b537SWarner Losh    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
956*0c16b537SWarner Losh    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
957*0c16b537SWarner Losh    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
958*0c16b537SWarner Losh    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
959*0c16b537SWarner Losh    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
960*0c16b537SWarner Losh    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
961*0c16b537SWarner Losh 
962*0c16b537SWarner Losh    You can contact the author at :
963*0c16b537SWarner Losh    - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
964*0c16b537SWarner Losh    - Public forum : https://groups.google.com/forum/#!forum/lz4c
965*0c16b537SWarner Losh ****************************************************************** */
966*0c16b537SWarner Losh #ifndef FSE_STATIC_H
967*0c16b537SWarner Losh #define FSE_STATIC_H
968*0c16b537SWarner Losh 
969*0c16b537SWarner Losh #if defined (__cplusplus)
970*0c16b537SWarner Losh extern "C" {
971*0c16b537SWarner Losh #endif
972*0c16b537SWarner Losh 
973*0c16b537SWarner Losh 
974*0c16b537SWarner Losh /* *****************************************
975*0c16b537SWarner Losh *  Static allocation
976*0c16b537SWarner Losh *******************************************/
977*0c16b537SWarner Losh /* FSE buffer bounds */
978*0c16b537SWarner Losh #define FSE_NCOUNTBOUND 512
979*0c16b537SWarner Losh #define FSE_BLOCKBOUND(size) (size + (size>>7))
980*0c16b537SWarner Losh #define FSE_COMPRESSBOUND(size) (FSE_NCOUNTBOUND + FSE_BLOCKBOUND(size))   /* Macro version, useful for static allocation */
981*0c16b537SWarner Losh 
982*0c16b537SWarner Losh /* It is possible to statically allocate FSE CTable/DTable as a table of unsigned using below macros */
983*0c16b537SWarner Losh #define FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue)   (1 + (1<<(maxTableLog-1)) + ((maxSymbolValue+1)*2))
984*0c16b537SWarner Losh #define FSE_DTABLE_SIZE_U32(maxTableLog)                   (1 + (1<<maxTableLog))
985*0c16b537SWarner Losh 
986*0c16b537SWarner Losh 
987*0c16b537SWarner Losh /* *****************************************
988*0c16b537SWarner Losh *  FSE advanced API
989*0c16b537SWarner Losh *******************************************/
990*0c16b537SWarner Losh static size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits);
991*0c16b537SWarner Losh /* build a fake FSE_DTable, designed to read an uncompressed bitstream where each symbol uses nbBits */
992*0c16b537SWarner Losh 
993*0c16b537SWarner Losh static size_t FSE_buildDTable_rle (FSE_DTable* dt, unsigned char symbolValue);
994*0c16b537SWarner Losh /* build a fake FSE_DTable, designed to always generate the same symbolValue */
995*0c16b537SWarner Losh 
996*0c16b537SWarner Losh 
997*0c16b537SWarner Losh 
998*0c16b537SWarner Losh /* *****************************************
999*0c16b537SWarner Losh *  FSE symbol decompression API
1000*0c16b537SWarner Losh *******************************************/
1001*0c16b537SWarner Losh typedef struct
1002*0c16b537SWarner Losh {
1003*0c16b537SWarner Losh     size_t      state;
1004*0c16b537SWarner Losh     const void* table;   /* precise table may vary, depending on U16 */
1005*0c16b537SWarner Losh } FSE_DState_t;
1006*0c16b537SWarner Losh 
1007*0c16b537SWarner Losh 
1008*0c16b537SWarner Losh static void     FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt);
1009*0c16b537SWarner Losh 
1010*0c16b537SWarner Losh static unsigned char FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD);
1011*0c16b537SWarner Losh 
1012*0c16b537SWarner Losh static unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr);
1013*0c16b537SWarner Losh 
1014*0c16b537SWarner Losh /*!
1015*0c16b537SWarner Losh Let's now decompose FSE_decompress_usingDTable() into its unitary components.
1016*0c16b537SWarner Losh You will decode FSE-encoded symbols from the bitStream,
1017*0c16b537SWarner Losh and also any other bitFields you put in, **in reverse order**.
1018*0c16b537SWarner Losh 
1019*0c16b537SWarner Losh You will need a few variables to track your bitStream. They are :
1020*0c16b537SWarner Losh 
1021*0c16b537SWarner Losh BIT_DStream_t DStream;    // Stream context
1022*0c16b537SWarner Losh FSE_DState_t  DState;     // State context. Multiple ones are possible
1023*0c16b537SWarner Losh FSE_DTable*   DTablePtr;  // Decoding table, provided by FSE_buildDTable()
1024*0c16b537SWarner Losh 
1025*0c16b537SWarner Losh The first thing to do is to init the bitStream.
1026*0c16b537SWarner Losh     errorCode = BIT_initDStream(&DStream, srcBuffer, srcSize);
1027*0c16b537SWarner Losh 
1028*0c16b537SWarner Losh You should then retrieve your initial state(s)
1029*0c16b537SWarner Losh (in reverse flushing order if you have several ones) :
1030*0c16b537SWarner Losh     errorCode = FSE_initDState(&DState, &DStream, DTablePtr);
1031*0c16b537SWarner Losh 
1032*0c16b537SWarner Losh You can then decode your data, symbol after symbol.
1033*0c16b537SWarner Losh For information the maximum number of bits read by FSE_decodeSymbol() is 'tableLog'.
1034*0c16b537SWarner Losh Keep in mind that symbols are decoded in reverse order, like a LIFO stack (last in, first out).
1035*0c16b537SWarner Losh     unsigned char symbol = FSE_decodeSymbol(&DState, &DStream);
1036*0c16b537SWarner Losh 
1037*0c16b537SWarner Losh You can retrieve any bitfield you eventually stored into the bitStream (in reverse order)
1038*0c16b537SWarner Losh Note : maximum allowed nbBits is 25, for 32-bits compatibility
1039*0c16b537SWarner Losh     size_t bitField = BIT_readBits(&DStream, nbBits);
1040*0c16b537SWarner Losh 
1041*0c16b537SWarner Losh All above operations only read from local register (which size depends on size_t).
1042*0c16b537SWarner Losh Refueling the register from memory is manually performed by the reload method.
1043*0c16b537SWarner Losh     endSignal = FSE_reloadDStream(&DStream);
1044*0c16b537SWarner Losh 
1045*0c16b537SWarner Losh BIT_reloadDStream() result tells if there is still some more data to read from DStream.
1046*0c16b537SWarner Losh BIT_DStream_unfinished : there is still some data left into the DStream.
1047*0c16b537SWarner Losh BIT_DStream_endOfBuffer : Dstream reached end of buffer. Its container may no longer be completely filled.
1048*0c16b537SWarner Losh BIT_DStream_completed : Dstream reached its exact end, corresponding in general to decompression completed.
1049*0c16b537SWarner Losh BIT_DStream_tooFar : Dstream went too far. Decompression result is corrupted.
1050*0c16b537SWarner Losh 
1051*0c16b537SWarner Losh When reaching end of buffer (BIT_DStream_endOfBuffer), progress slowly, notably if you decode multiple symbols per loop,
1052*0c16b537SWarner Losh to properly detect the exact end of stream.
1053*0c16b537SWarner Losh After each decoded symbol, check if DStream is fully consumed using this simple test :
1054*0c16b537SWarner Losh     BIT_reloadDStream(&DStream) >= BIT_DStream_completed
1055*0c16b537SWarner Losh 
1056*0c16b537SWarner Losh When it's done, verify decompression is fully completed, by checking both DStream and the relevant states.
1057*0c16b537SWarner Losh Checking if DStream has reached its end is performed by :
1058*0c16b537SWarner Losh     BIT_endOfDStream(&DStream);
1059*0c16b537SWarner Losh Check also the states. There might be some symbols left there, if some high probability ones (>50%) are possible.
1060*0c16b537SWarner Losh     FSE_endOfDState(&DState);
1061*0c16b537SWarner Losh */
1062*0c16b537SWarner Losh 
1063*0c16b537SWarner Losh 
1064*0c16b537SWarner Losh /* *****************************************
1065*0c16b537SWarner Losh *  FSE unsafe API
1066*0c16b537SWarner Losh *******************************************/
1067*0c16b537SWarner Losh static unsigned char FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD);
1068*0c16b537SWarner Losh /* faster, but works only if nbBits is always >= 1 (otherwise, result will be corrupted) */
1069*0c16b537SWarner Losh 
1070*0c16b537SWarner Losh 
1071*0c16b537SWarner Losh /* *****************************************
1072*0c16b537SWarner Losh *  Implementation of inlined functions
1073*0c16b537SWarner Losh *******************************************/
1074*0c16b537SWarner Losh /* decompression */
1075*0c16b537SWarner Losh 
1076*0c16b537SWarner Losh typedef struct {
1077*0c16b537SWarner Losh     U16 tableLog;
1078*0c16b537SWarner Losh     U16 fastMode;
1079*0c16b537SWarner Losh } FSE_DTableHeader;   /* sizeof U32 */
1080*0c16b537SWarner Losh 
1081*0c16b537SWarner Losh typedef struct
1082*0c16b537SWarner Losh {
1083*0c16b537SWarner Losh     unsigned short newState;
1084*0c16b537SWarner Losh     unsigned char  symbol;
1085*0c16b537SWarner Losh     unsigned char  nbBits;
1086*0c16b537SWarner Losh } FSE_decode_t;   /* size == U32 */
1087*0c16b537SWarner Losh 
1088*0c16b537SWarner Losh MEM_STATIC void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt)
1089*0c16b537SWarner Losh {
1090*0c16b537SWarner Losh     FSE_DTableHeader DTableH;
1091*0c16b537SWarner Losh     memcpy(&DTableH, dt, sizeof(DTableH));
1092*0c16b537SWarner Losh     DStatePtr->state = BIT_readBits(bitD, DTableH.tableLog);
1093*0c16b537SWarner Losh     BIT_reloadDStream(bitD);
1094*0c16b537SWarner Losh     DStatePtr->table = dt + 1;
1095*0c16b537SWarner Losh }
1096*0c16b537SWarner Losh 
1097*0c16b537SWarner Losh MEM_STATIC BYTE FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
1098*0c16b537SWarner Losh {
1099*0c16b537SWarner Losh     const FSE_decode_t DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
1100*0c16b537SWarner Losh     const U32  nbBits = DInfo.nbBits;
1101*0c16b537SWarner Losh     BYTE symbol = DInfo.symbol;
1102*0c16b537SWarner Losh     size_t lowBits = BIT_readBits(bitD, nbBits);
1103*0c16b537SWarner Losh 
1104*0c16b537SWarner Losh     DStatePtr->state = DInfo.newState + lowBits;
1105*0c16b537SWarner Losh     return symbol;
1106*0c16b537SWarner Losh }
1107*0c16b537SWarner Losh 
1108*0c16b537SWarner Losh MEM_STATIC BYTE FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
1109*0c16b537SWarner Losh {
1110*0c16b537SWarner Losh     const FSE_decode_t DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
1111*0c16b537SWarner Losh     const U32 nbBits = DInfo.nbBits;
1112*0c16b537SWarner Losh     BYTE symbol = DInfo.symbol;
1113*0c16b537SWarner Losh     size_t lowBits = BIT_readBitsFast(bitD, nbBits);
1114*0c16b537SWarner Losh 
1115*0c16b537SWarner Losh     DStatePtr->state = DInfo.newState + lowBits;
1116*0c16b537SWarner Losh     return symbol;
1117*0c16b537SWarner Losh }
1118*0c16b537SWarner Losh 
1119*0c16b537SWarner Losh MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr)
1120*0c16b537SWarner Losh {
1121*0c16b537SWarner Losh     return DStatePtr->state == 0;
1122*0c16b537SWarner Losh }
1123*0c16b537SWarner Losh 
1124*0c16b537SWarner Losh 
1125*0c16b537SWarner Losh #if defined (__cplusplus)
1126*0c16b537SWarner Losh }
1127*0c16b537SWarner Losh #endif
1128*0c16b537SWarner Losh 
1129*0c16b537SWarner Losh #endif  /* FSE_STATIC_H */
1130*0c16b537SWarner Losh 
1131*0c16b537SWarner Losh /* ******************************************************************
1132*0c16b537SWarner Losh    FSE : Finite State Entropy coder
1133*0c16b537SWarner Losh    Copyright (C) 2013-2015, Yann Collet.
1134*0c16b537SWarner Losh 
1135*0c16b537SWarner Losh    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
1136*0c16b537SWarner Losh 
1137*0c16b537SWarner Losh    Redistribution and use in source and binary forms, with or without
1138*0c16b537SWarner Losh    modification, are permitted provided that the following conditions are
1139*0c16b537SWarner Losh    met:
1140*0c16b537SWarner Losh 
1141*0c16b537SWarner Losh        * Redistributions of source code must retain the above copyright
1142*0c16b537SWarner Losh    notice, this list of conditions and the following disclaimer.
1143*0c16b537SWarner Losh        * Redistributions in binary form must reproduce the above
1144*0c16b537SWarner Losh    copyright notice, this list of conditions and the following disclaimer
1145*0c16b537SWarner Losh    in the documentation and/or other materials provided with the
1146*0c16b537SWarner Losh    distribution.
1147*0c16b537SWarner Losh 
1148*0c16b537SWarner Losh    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1149*0c16b537SWarner Losh    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1150*0c16b537SWarner Losh    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1151*0c16b537SWarner Losh    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1152*0c16b537SWarner Losh    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1153*0c16b537SWarner Losh    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1154*0c16b537SWarner Losh    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1155*0c16b537SWarner Losh    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1156*0c16b537SWarner Losh    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1157*0c16b537SWarner Losh    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1158*0c16b537SWarner Losh    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1159*0c16b537SWarner Losh 
1160*0c16b537SWarner Losh     You can contact the author at :
1161*0c16b537SWarner Losh     - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
1162*0c16b537SWarner Losh     - Public forum : https://groups.google.com/forum/#!forum/lz4c
1163*0c16b537SWarner Losh ****************************************************************** */
1164*0c16b537SWarner Losh 
1165*0c16b537SWarner Losh #ifndef FSE_COMMONDEFS_ONLY
1166*0c16b537SWarner Losh 
1167*0c16b537SWarner Losh /* **************************************************************
1168*0c16b537SWarner Losh *  Tuning parameters
1169*0c16b537SWarner Losh ****************************************************************/
1170*0c16b537SWarner Losh /*!MEMORY_USAGE :
1171*0c16b537SWarner Losh *  Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
1172*0c16b537SWarner Losh *  Increasing memory usage improves compression ratio
1173*0c16b537SWarner Losh *  Reduced memory usage can improve speed, due to cache effect
1174*0c16b537SWarner Losh *  Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */
1175*0c16b537SWarner Losh #define FSE_MAX_MEMORY_USAGE 14
1176*0c16b537SWarner Losh #define FSE_DEFAULT_MEMORY_USAGE 13
1177*0c16b537SWarner Losh 
1178*0c16b537SWarner Losh /*!FSE_MAX_SYMBOL_VALUE :
1179*0c16b537SWarner Losh *  Maximum symbol value authorized.
1180*0c16b537SWarner Losh *  Required for proper stack allocation */
1181*0c16b537SWarner Losh #define FSE_MAX_SYMBOL_VALUE 255
1182*0c16b537SWarner Losh 
1183*0c16b537SWarner Losh 
1184*0c16b537SWarner Losh /* **************************************************************
1185*0c16b537SWarner Losh *  template functions type & suffix
1186*0c16b537SWarner Losh ****************************************************************/
1187*0c16b537SWarner Losh #define FSE_FUNCTION_TYPE BYTE
1188*0c16b537SWarner Losh #define FSE_FUNCTION_EXTENSION
1189*0c16b537SWarner Losh #define FSE_DECODE_TYPE FSE_decode_t
1190*0c16b537SWarner Losh 
1191*0c16b537SWarner Losh 
1192*0c16b537SWarner Losh #endif   /* !FSE_COMMONDEFS_ONLY */
1193*0c16b537SWarner Losh 
1194*0c16b537SWarner Losh /* **************************************************************
1195*0c16b537SWarner Losh *  Compiler specifics
1196*0c16b537SWarner Losh ****************************************************************/
1197*0c16b537SWarner Losh #ifdef _MSC_VER    /* Visual Studio */
1198*0c16b537SWarner Losh #  define FORCE_INLINE static __forceinline
1199*0c16b537SWarner Losh #  include <intrin.h>                    /* For Visual 2005 */
1200*0c16b537SWarner Losh #  pragma warning(disable : 4127)        /* disable: C4127: conditional expression is constant */
1201*0c16b537SWarner Losh #  pragma warning(disable : 4214)        /* disable: C4214: non-int bitfields */
1202*0c16b537SWarner Losh #else
1203*0c16b537SWarner Losh #  if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L   /* C99 */
1204*0c16b537SWarner Losh #    ifdef __GNUC__
1205*0c16b537SWarner Losh #      define FORCE_INLINE static inline __attribute__((always_inline))
1206*0c16b537SWarner Losh #    else
1207*0c16b537SWarner Losh #      define FORCE_INLINE static inline
1208*0c16b537SWarner Losh #    endif
1209*0c16b537SWarner Losh #  else
1210*0c16b537SWarner Losh #    define FORCE_INLINE static
1211*0c16b537SWarner Losh #  endif /* __STDC_VERSION__ */
1212*0c16b537SWarner Losh #endif
1213*0c16b537SWarner Losh 
1214*0c16b537SWarner Losh 
1215*0c16b537SWarner Losh /* **************************************************************
1216*0c16b537SWarner Losh *  Dependencies
1217*0c16b537SWarner Losh ****************************************************************/
1218*0c16b537SWarner Losh #include <stdlib.h>     /* malloc, free, qsort */
1219*0c16b537SWarner Losh #include <string.h>     /* memcpy, memset */
1220*0c16b537SWarner Losh #include <stdio.h>      /* printf (debug) */
1221*0c16b537SWarner Losh 
1222*0c16b537SWarner Losh 
1223*0c16b537SWarner Losh /* ***************************************************************
1224*0c16b537SWarner Losh *  Constants
1225*0c16b537SWarner Losh *****************************************************************/
1226*0c16b537SWarner Losh #define FSE_MAX_TABLELOG  (FSE_MAX_MEMORY_USAGE-2)
1227*0c16b537SWarner Losh #define FSE_MAX_TABLESIZE (1U<<FSE_MAX_TABLELOG)
1228*0c16b537SWarner Losh #define FSE_MAXTABLESIZE_MASK (FSE_MAX_TABLESIZE-1)
1229*0c16b537SWarner Losh #define FSE_DEFAULT_TABLELOG (FSE_DEFAULT_MEMORY_USAGE-2)
1230*0c16b537SWarner Losh #define FSE_MIN_TABLELOG 5
1231*0c16b537SWarner Losh 
1232*0c16b537SWarner Losh #define FSE_TABLELOG_ABSOLUTE_MAX 15
1233*0c16b537SWarner Losh #if FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX
1234*0c16b537SWarner Losh #error "FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX is not supported"
1235*0c16b537SWarner Losh #endif
1236*0c16b537SWarner Losh 
1237*0c16b537SWarner Losh 
1238*0c16b537SWarner Losh /* **************************************************************
1239*0c16b537SWarner Losh *  Error Management
1240*0c16b537SWarner Losh ****************************************************************/
1241*0c16b537SWarner Losh #define FSE_STATIC_ASSERT(c) { enum { FSE_static_assert = 1/(int)(!!(c)) }; }   /* use only *after* variable declarations */
1242*0c16b537SWarner Losh 
1243*0c16b537SWarner Losh 
1244*0c16b537SWarner Losh /* **************************************************************
1245*0c16b537SWarner Losh *  Complex types
1246*0c16b537SWarner Losh ****************************************************************/
1247*0c16b537SWarner Losh typedef U32 DTable_max_t[FSE_DTABLE_SIZE_U32(FSE_MAX_TABLELOG)];
1248*0c16b537SWarner Losh 
1249*0c16b537SWarner Losh 
1250*0c16b537SWarner Losh /*-**************************************************************
1251*0c16b537SWarner Losh *  Templates
1252*0c16b537SWarner Losh ****************************************************************/
1253*0c16b537SWarner Losh /*
1254*0c16b537SWarner Losh   designed to be included
1255*0c16b537SWarner Losh   for type-specific functions (template emulation in C)
1256*0c16b537SWarner Losh   Objective is to write these functions only once, for improved maintenance
1257*0c16b537SWarner Losh */
1258*0c16b537SWarner Losh 
1259*0c16b537SWarner Losh /* safety checks */
1260*0c16b537SWarner Losh #ifndef FSE_FUNCTION_EXTENSION
1261*0c16b537SWarner Losh #  error "FSE_FUNCTION_EXTENSION must be defined"
1262*0c16b537SWarner Losh #endif
1263*0c16b537SWarner Losh #ifndef FSE_FUNCTION_TYPE
1264*0c16b537SWarner Losh #  error "FSE_FUNCTION_TYPE must be defined"
1265*0c16b537SWarner Losh #endif
1266*0c16b537SWarner Losh 
1267*0c16b537SWarner Losh /* Function names */
1268*0c16b537SWarner Losh #define FSE_CAT(X,Y) X##Y
1269*0c16b537SWarner Losh #define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y)
1270*0c16b537SWarner Losh #define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y)
1271*0c16b537SWarner Losh 
1272*0c16b537SWarner Losh static U32 FSE_tableStep(U32 tableSize) { return (tableSize>>1) + (tableSize>>3) + 3; }
1273*0c16b537SWarner Losh 
1274*0c16b537SWarner Losh 
1275*0c16b537SWarner Losh static size_t FSE_buildDTable(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
1276*0c16b537SWarner Losh {
1277*0c16b537SWarner Losh     FSE_DTableHeader DTableH;
1278*0c16b537SWarner Losh     void* const tdPtr = dt+1;   /* because dt is unsigned, 32-bits aligned on 32-bits */
1279*0c16b537SWarner Losh     FSE_DECODE_TYPE* const tableDecode = (FSE_DECODE_TYPE*) (tdPtr);
1280*0c16b537SWarner Losh     const U32 tableSize = 1 << tableLog;
1281*0c16b537SWarner Losh     const U32 tableMask = tableSize-1;
1282*0c16b537SWarner Losh     const U32 step = FSE_tableStep(tableSize);
1283*0c16b537SWarner Losh     U16 symbolNext[FSE_MAX_SYMBOL_VALUE+1];
1284*0c16b537SWarner Losh     U32 position = 0;
1285*0c16b537SWarner Losh     U32 highThreshold = tableSize-1;
1286*0c16b537SWarner Losh     const S16 largeLimit= (S16)(1 << (tableLog-1));
1287*0c16b537SWarner Losh     U32 noLarge = 1;
1288*0c16b537SWarner Losh     U32 s;
1289*0c16b537SWarner Losh 
1290*0c16b537SWarner Losh     /* Sanity Checks */
1291*0c16b537SWarner Losh     if (maxSymbolValue > FSE_MAX_SYMBOL_VALUE) return ERROR(maxSymbolValue_tooLarge);
1292*0c16b537SWarner Losh     if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge);
1293*0c16b537SWarner Losh 
1294*0c16b537SWarner Losh     /* Init, lay down lowprob symbols */
1295*0c16b537SWarner Losh     DTableH.tableLog = (U16)tableLog;
1296*0c16b537SWarner Losh     for (s=0; s<=maxSymbolValue; s++)
1297*0c16b537SWarner Losh     {
1298*0c16b537SWarner Losh         if (normalizedCounter[s]==-1)
1299*0c16b537SWarner Losh         {
1300*0c16b537SWarner Losh             tableDecode[highThreshold--].symbol = (FSE_FUNCTION_TYPE)s;
1301*0c16b537SWarner Losh             symbolNext[s] = 1;
1302*0c16b537SWarner Losh         }
1303*0c16b537SWarner Losh         else
1304*0c16b537SWarner Losh         {
1305*0c16b537SWarner Losh             if (normalizedCounter[s] >= largeLimit) noLarge=0;
1306*0c16b537SWarner Losh             symbolNext[s] = normalizedCounter[s];
1307*0c16b537SWarner Losh         }
1308*0c16b537SWarner Losh     }
1309*0c16b537SWarner Losh 
1310*0c16b537SWarner Losh     /* Spread symbols */
1311*0c16b537SWarner Losh     for (s=0; s<=maxSymbolValue; s++)
1312*0c16b537SWarner Losh     {
1313*0c16b537SWarner Losh         int i;
1314*0c16b537SWarner Losh         for (i=0; i<normalizedCounter[s]; i++)
1315*0c16b537SWarner Losh         {
1316*0c16b537SWarner Losh             tableDecode[position].symbol = (FSE_FUNCTION_TYPE)s;
1317*0c16b537SWarner Losh             position = (position + step) & tableMask;
1318*0c16b537SWarner Losh             while (position > highThreshold) position = (position + step) & tableMask;   /* lowprob area */
1319*0c16b537SWarner Losh         }
1320*0c16b537SWarner Losh     }
1321*0c16b537SWarner Losh 
1322*0c16b537SWarner Losh     if (position!=0) return ERROR(GENERIC);   /* position must reach all cells once, otherwise normalizedCounter is incorrect */
1323*0c16b537SWarner Losh 
1324*0c16b537SWarner Losh     /* Build Decoding table */
1325*0c16b537SWarner Losh     {
1326*0c16b537SWarner Losh         U32 i;
1327*0c16b537SWarner Losh         for (i=0; i<tableSize; i++)
1328*0c16b537SWarner Losh         {
1329*0c16b537SWarner Losh             FSE_FUNCTION_TYPE symbol = (FSE_FUNCTION_TYPE)(tableDecode[i].symbol);
1330*0c16b537SWarner Losh             U16 nextState = symbolNext[symbol]++;
1331*0c16b537SWarner Losh             tableDecode[i].nbBits = (BYTE) (tableLog - BIT_highbit32 ((U32)nextState) );
1332*0c16b537SWarner Losh             tableDecode[i].newState = (U16) ( (nextState << tableDecode[i].nbBits) - tableSize);
1333*0c16b537SWarner Losh         }
1334*0c16b537SWarner Losh     }
1335*0c16b537SWarner Losh 
1336*0c16b537SWarner Losh     DTableH.fastMode = (U16)noLarge;
1337*0c16b537SWarner Losh     memcpy(dt, &DTableH, sizeof(DTableH));
1338*0c16b537SWarner Losh     return 0;
1339*0c16b537SWarner Losh }
1340*0c16b537SWarner Losh 
1341*0c16b537SWarner Losh 
1342*0c16b537SWarner Losh #ifndef FSE_COMMONDEFS_ONLY
1343*0c16b537SWarner Losh /******************************************
1344*0c16b537SWarner Losh *  FSE helper functions
1345*0c16b537SWarner Losh ******************************************/
1346*0c16b537SWarner Losh static unsigned FSE_isError(size_t code) { return ERR_isError(code); }
1347*0c16b537SWarner Losh 
1348*0c16b537SWarner Losh 
1349*0c16b537SWarner Losh /****************************************************************
1350*0c16b537SWarner Losh *  FSE NCount encoding-decoding
1351*0c16b537SWarner Losh ****************************************************************/
1352*0c16b537SWarner Losh static short FSE_abs(short a)
1353*0c16b537SWarner Losh {
1354*0c16b537SWarner Losh     return a<0 ? -a : a;
1355*0c16b537SWarner Losh }
1356*0c16b537SWarner Losh 
1357*0c16b537SWarner Losh static size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
1358*0c16b537SWarner Losh                  const void* headerBuffer, size_t hbSize)
1359*0c16b537SWarner Losh {
1360*0c16b537SWarner Losh     const BYTE* const istart = (const BYTE*) headerBuffer;
1361*0c16b537SWarner Losh     const BYTE* const iend = istart + hbSize;
1362*0c16b537SWarner Losh     const BYTE* ip = istart;
1363*0c16b537SWarner Losh     int nbBits;
1364*0c16b537SWarner Losh     int remaining;
1365*0c16b537SWarner Losh     int threshold;
1366*0c16b537SWarner Losh     U32 bitStream;
1367*0c16b537SWarner Losh     int bitCount;
1368*0c16b537SWarner Losh     unsigned charnum = 0;
1369*0c16b537SWarner Losh     int previous0 = 0;
1370*0c16b537SWarner Losh 
1371*0c16b537SWarner Losh     if (hbSize < 4) return ERROR(srcSize_wrong);
1372*0c16b537SWarner Losh     bitStream = MEM_readLE32(ip);
1373*0c16b537SWarner Losh     nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG;   /* extract tableLog */
1374*0c16b537SWarner Losh     if (nbBits > FSE_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge);
1375*0c16b537SWarner Losh     bitStream >>= 4;
1376*0c16b537SWarner Losh     bitCount = 4;
1377*0c16b537SWarner Losh     *tableLogPtr = nbBits;
1378*0c16b537SWarner Losh     remaining = (1<<nbBits)+1;
1379*0c16b537SWarner Losh     threshold = 1<<nbBits;
1380*0c16b537SWarner Losh     nbBits++;
1381*0c16b537SWarner Losh 
1382*0c16b537SWarner Losh     while ((remaining>1) && (charnum<=*maxSVPtr))
1383*0c16b537SWarner Losh     {
1384*0c16b537SWarner Losh         if (previous0)
1385*0c16b537SWarner Losh         {
1386*0c16b537SWarner Losh             unsigned n0 = charnum;
1387*0c16b537SWarner Losh             while ((bitStream & 0xFFFF) == 0xFFFF)
1388*0c16b537SWarner Losh             {
1389*0c16b537SWarner Losh                 n0+=24;
1390*0c16b537SWarner Losh                 if (ip < iend-5)
1391*0c16b537SWarner Losh                 {
1392*0c16b537SWarner Losh                     ip+=2;
1393*0c16b537SWarner Losh                     bitStream = MEM_readLE32(ip) >> bitCount;
1394*0c16b537SWarner Losh                 }
1395*0c16b537SWarner Losh                 else
1396*0c16b537SWarner Losh                 {
1397*0c16b537SWarner Losh                     bitStream >>= 16;
1398*0c16b537SWarner Losh                     bitCount+=16;
1399*0c16b537SWarner Losh                 }
1400*0c16b537SWarner Losh             }
1401*0c16b537SWarner Losh             while ((bitStream & 3) == 3)
1402*0c16b537SWarner Losh             {
1403*0c16b537SWarner Losh                 n0+=3;
1404*0c16b537SWarner Losh                 bitStream>>=2;
1405*0c16b537SWarner Losh                 bitCount+=2;
1406*0c16b537SWarner Losh             }
1407*0c16b537SWarner Losh             n0 += bitStream & 3;
1408*0c16b537SWarner Losh             bitCount += 2;
1409*0c16b537SWarner Losh             if (n0 > *maxSVPtr) return ERROR(maxSymbolValue_tooSmall);
1410*0c16b537SWarner Losh             while (charnum < n0) normalizedCounter[charnum++] = 0;
1411*0c16b537SWarner Losh             if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4))
1412*0c16b537SWarner Losh             {
1413*0c16b537SWarner Losh                 ip += bitCount>>3;
1414*0c16b537SWarner Losh                 bitCount &= 7;
1415*0c16b537SWarner Losh                 bitStream = MEM_readLE32(ip) >> bitCount;
1416*0c16b537SWarner Losh             }
1417*0c16b537SWarner Losh             else
1418*0c16b537SWarner Losh                 bitStream >>= 2;
1419*0c16b537SWarner Losh         }
1420*0c16b537SWarner Losh         {
1421*0c16b537SWarner Losh             const short max = (short)((2*threshold-1)-remaining);
1422*0c16b537SWarner Losh             short count;
1423*0c16b537SWarner Losh 
1424*0c16b537SWarner Losh             if ((bitStream & (threshold-1)) < (U32)max)
1425*0c16b537SWarner Losh             {
1426*0c16b537SWarner Losh                 count = (short)(bitStream & (threshold-1));
1427*0c16b537SWarner Losh                 bitCount   += nbBits-1;
1428*0c16b537SWarner Losh             }
1429*0c16b537SWarner Losh             else
1430*0c16b537SWarner Losh             {
1431*0c16b537SWarner Losh                 count = (short)(bitStream & (2*threshold-1));
1432*0c16b537SWarner Losh                 if (count >= threshold) count -= max;
1433*0c16b537SWarner Losh                 bitCount   += nbBits;
1434*0c16b537SWarner Losh             }
1435*0c16b537SWarner Losh 
1436*0c16b537SWarner Losh             count--;   /* extra accuracy */
1437*0c16b537SWarner Losh             remaining -= FSE_abs(count);
1438*0c16b537SWarner Losh             normalizedCounter[charnum++] = count;
1439*0c16b537SWarner Losh             previous0 = !count;
1440*0c16b537SWarner Losh             while (remaining < threshold)
1441*0c16b537SWarner Losh             {
1442*0c16b537SWarner Losh                 nbBits--;
1443*0c16b537SWarner Losh                 threshold >>= 1;
1444*0c16b537SWarner Losh             }
1445*0c16b537SWarner Losh 
1446*0c16b537SWarner Losh             {
1447*0c16b537SWarner Losh                 if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4))
1448*0c16b537SWarner Losh                 {
1449*0c16b537SWarner Losh                     ip += bitCount>>3;
1450*0c16b537SWarner Losh                     bitCount &= 7;
1451*0c16b537SWarner Losh                 }
1452*0c16b537SWarner Losh                 else
1453*0c16b537SWarner Losh                 {
1454*0c16b537SWarner Losh                     bitCount -= (int)(8 * (iend - 4 - ip));
1455*0c16b537SWarner Losh                     ip = iend - 4;
1456*0c16b537SWarner Losh                 }
1457*0c16b537SWarner Losh                 bitStream = MEM_readLE32(ip) >> (bitCount & 31);
1458*0c16b537SWarner Losh             }
1459*0c16b537SWarner Losh         }
1460*0c16b537SWarner Losh     }
1461*0c16b537SWarner Losh     if (remaining != 1) return ERROR(GENERIC);
1462*0c16b537SWarner Losh     *maxSVPtr = charnum-1;
1463*0c16b537SWarner Losh 
1464*0c16b537SWarner Losh     ip += (bitCount+7)>>3;
1465*0c16b537SWarner Losh     if ((size_t)(ip-istart) > hbSize) return ERROR(srcSize_wrong);
1466*0c16b537SWarner Losh     return ip-istart;
1467*0c16b537SWarner Losh }
1468*0c16b537SWarner Losh 
1469*0c16b537SWarner Losh 
1470*0c16b537SWarner Losh /*********************************************************
1471*0c16b537SWarner Losh *  Decompression (Byte symbols)
1472*0c16b537SWarner Losh *********************************************************/
1473*0c16b537SWarner Losh static size_t FSE_buildDTable_rle (FSE_DTable* dt, BYTE symbolValue)
1474*0c16b537SWarner Losh {
1475*0c16b537SWarner Losh     void* ptr = dt;
1476*0c16b537SWarner Losh     FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr;
1477*0c16b537SWarner Losh     void* dPtr = dt + 1;
1478*0c16b537SWarner Losh     FSE_decode_t* const cell = (FSE_decode_t*)dPtr;
1479*0c16b537SWarner Losh 
1480*0c16b537SWarner Losh     DTableH->tableLog = 0;
1481*0c16b537SWarner Losh     DTableH->fastMode = 0;
1482*0c16b537SWarner Losh 
1483*0c16b537SWarner Losh     cell->newState = 0;
1484*0c16b537SWarner Losh     cell->symbol = symbolValue;
1485*0c16b537SWarner Losh     cell->nbBits = 0;
1486*0c16b537SWarner Losh 
1487*0c16b537SWarner Losh     return 0;
1488*0c16b537SWarner Losh }
1489*0c16b537SWarner Losh 
1490*0c16b537SWarner Losh 
1491*0c16b537SWarner Losh static size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits)
1492*0c16b537SWarner Losh {
1493*0c16b537SWarner Losh     void* ptr = dt;
1494*0c16b537SWarner Losh     FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr;
1495*0c16b537SWarner Losh     void* dPtr = dt + 1;
1496*0c16b537SWarner Losh     FSE_decode_t* const dinfo = (FSE_decode_t*)dPtr;
1497*0c16b537SWarner Losh     const unsigned tableSize = 1 << nbBits;
1498*0c16b537SWarner Losh     const unsigned tableMask = tableSize - 1;
1499*0c16b537SWarner Losh     const unsigned maxSymbolValue = tableMask;
1500*0c16b537SWarner Losh     unsigned s;
1501*0c16b537SWarner Losh 
1502*0c16b537SWarner Losh     /* Sanity checks */
1503*0c16b537SWarner Losh     if (nbBits < 1) return ERROR(GENERIC);         /* min size */
1504*0c16b537SWarner Losh 
1505*0c16b537SWarner Losh     /* Build Decoding Table */
1506*0c16b537SWarner Losh     DTableH->tableLog = (U16)nbBits;
1507*0c16b537SWarner Losh     DTableH->fastMode = 1;
1508*0c16b537SWarner Losh     for (s=0; s<=maxSymbolValue; s++)
1509*0c16b537SWarner Losh     {
1510*0c16b537SWarner Losh         dinfo[s].newState = 0;
1511*0c16b537SWarner Losh         dinfo[s].symbol = (BYTE)s;
1512*0c16b537SWarner Losh         dinfo[s].nbBits = (BYTE)nbBits;
1513*0c16b537SWarner Losh     }
1514*0c16b537SWarner Losh 
1515*0c16b537SWarner Losh     return 0;
1516*0c16b537SWarner Losh }
1517*0c16b537SWarner Losh 
1518*0c16b537SWarner Losh FORCE_INLINE size_t FSE_decompress_usingDTable_generic(
1519*0c16b537SWarner Losh           void* dst, size_t maxDstSize,
1520*0c16b537SWarner Losh     const void* cSrc, size_t cSrcSize,
1521*0c16b537SWarner Losh     const FSE_DTable* dt, const unsigned fast)
1522*0c16b537SWarner Losh {
1523*0c16b537SWarner Losh     BYTE* const ostart = (BYTE*) dst;
1524*0c16b537SWarner Losh     BYTE* op = ostart;
1525*0c16b537SWarner Losh     BYTE* const omax = op + maxDstSize;
1526*0c16b537SWarner Losh     BYTE* const olimit = omax-3;
1527*0c16b537SWarner Losh 
1528*0c16b537SWarner Losh     BIT_DStream_t bitD;
1529*0c16b537SWarner Losh     FSE_DState_t state1;
1530*0c16b537SWarner Losh     FSE_DState_t state2;
1531*0c16b537SWarner Losh     size_t errorCode;
1532*0c16b537SWarner Losh 
1533*0c16b537SWarner Losh     /* Init */
1534*0c16b537SWarner Losh     errorCode = BIT_initDStream(&bitD, cSrc, cSrcSize);   /* replaced last arg by maxCompressed Size */
1535*0c16b537SWarner Losh     if (FSE_isError(errorCode)) return errorCode;
1536*0c16b537SWarner Losh 
1537*0c16b537SWarner Losh     FSE_initDState(&state1, &bitD, dt);
1538*0c16b537SWarner Losh     FSE_initDState(&state2, &bitD, dt);
1539*0c16b537SWarner Losh 
1540*0c16b537SWarner Losh #define FSE_GETSYMBOL(statePtr) fast ? FSE_decodeSymbolFast(statePtr, &bitD) : FSE_decodeSymbol(statePtr, &bitD)
1541*0c16b537SWarner Losh 
1542*0c16b537SWarner Losh     /* 4 symbols per loop */
1543*0c16b537SWarner Losh     for ( ; (BIT_reloadDStream(&bitD)==BIT_DStream_unfinished) && (op<olimit) ; op+=4)
1544*0c16b537SWarner Losh     {
1545*0c16b537SWarner Losh         op[0] = FSE_GETSYMBOL(&state1);
1546*0c16b537SWarner Losh 
1547*0c16b537SWarner Losh         if (FSE_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8)    /* This test must be static */
1548*0c16b537SWarner Losh             BIT_reloadDStream(&bitD);
1549*0c16b537SWarner Losh 
1550*0c16b537SWarner Losh         op[1] = FSE_GETSYMBOL(&state2);
1551*0c16b537SWarner Losh 
1552*0c16b537SWarner Losh         if (FSE_MAX_TABLELOG*4+7 > sizeof(bitD.bitContainer)*8)    /* This test must be static */
1553*0c16b537SWarner Losh             { if (BIT_reloadDStream(&bitD) > BIT_DStream_unfinished) { op+=2; break; } }
1554*0c16b537SWarner Losh 
1555*0c16b537SWarner Losh         op[2] = FSE_GETSYMBOL(&state1);
1556*0c16b537SWarner Losh 
1557*0c16b537SWarner Losh         if (FSE_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8)    /* This test must be static */
1558*0c16b537SWarner Losh             BIT_reloadDStream(&bitD);
1559*0c16b537SWarner Losh 
1560*0c16b537SWarner Losh         op[3] = FSE_GETSYMBOL(&state2);
1561*0c16b537SWarner Losh     }
1562*0c16b537SWarner Losh 
1563*0c16b537SWarner Losh     /* tail */
1564*0c16b537SWarner Losh     /* note : BIT_reloadDStream(&bitD) >= FSE_DStream_partiallyFilled; Ends at exactly BIT_DStream_completed */
1565*0c16b537SWarner Losh     while (1)
1566*0c16b537SWarner Losh     {
1567*0c16b537SWarner Losh         if ( (BIT_reloadDStream(&bitD)>BIT_DStream_completed) || (op==omax) || (BIT_endOfDStream(&bitD) && (fast || FSE_endOfDState(&state1))) )
1568*0c16b537SWarner Losh             break;
1569*0c16b537SWarner Losh 
1570*0c16b537SWarner Losh         *op++ = FSE_GETSYMBOL(&state1);
1571*0c16b537SWarner Losh 
1572*0c16b537SWarner Losh         if ( (BIT_reloadDStream(&bitD)>BIT_DStream_completed) || (op==omax) || (BIT_endOfDStream(&bitD) && (fast || FSE_endOfDState(&state2))) )
1573*0c16b537SWarner Losh             break;
1574*0c16b537SWarner Losh 
1575*0c16b537SWarner Losh         *op++ = FSE_GETSYMBOL(&state2);
1576*0c16b537SWarner Losh     }
1577*0c16b537SWarner Losh 
1578*0c16b537SWarner Losh     /* end ? */
1579*0c16b537SWarner Losh     if (BIT_endOfDStream(&bitD) && FSE_endOfDState(&state1) && FSE_endOfDState(&state2))
1580*0c16b537SWarner Losh         return op-ostart;
1581*0c16b537SWarner Losh 
1582*0c16b537SWarner Losh     if (op==omax) return ERROR(dstSize_tooSmall);   /* dst buffer is full, but cSrc unfinished */
1583*0c16b537SWarner Losh 
1584*0c16b537SWarner Losh     return ERROR(corruption_detected);
1585*0c16b537SWarner Losh }
1586*0c16b537SWarner Losh 
1587*0c16b537SWarner Losh 
1588*0c16b537SWarner Losh static size_t FSE_decompress_usingDTable(void* dst, size_t originalSize,
1589*0c16b537SWarner Losh                             const void* cSrc, size_t cSrcSize,
1590*0c16b537SWarner Losh                             const FSE_DTable* dt)
1591*0c16b537SWarner Losh {
1592*0c16b537SWarner Losh     FSE_DTableHeader DTableH;
1593*0c16b537SWarner Losh     U32 fastMode;
1594*0c16b537SWarner Losh 
1595*0c16b537SWarner Losh     memcpy(&DTableH, dt, sizeof(DTableH));
1596*0c16b537SWarner Losh     fastMode = DTableH.fastMode;
1597*0c16b537SWarner Losh 
1598*0c16b537SWarner Losh     /* select fast mode (static) */
1599*0c16b537SWarner Losh     if (fastMode) return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 1);
1600*0c16b537SWarner Losh     return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 0);
1601*0c16b537SWarner Losh }
1602*0c16b537SWarner Losh 
1603*0c16b537SWarner Losh 
1604*0c16b537SWarner Losh static size_t FSE_decompress(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize)
1605*0c16b537SWarner Losh {
1606*0c16b537SWarner Losh     const BYTE* const istart = (const BYTE*)cSrc;
1607*0c16b537SWarner Losh     const BYTE* ip = istart;
1608*0c16b537SWarner Losh     short counting[FSE_MAX_SYMBOL_VALUE+1];
1609*0c16b537SWarner Losh     DTable_max_t dt;   /* Static analyzer seems unable to understand this table will be properly initialized later */
1610*0c16b537SWarner Losh     unsigned tableLog;
1611*0c16b537SWarner Losh     unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE;
1612*0c16b537SWarner Losh     size_t errorCode;
1613*0c16b537SWarner Losh 
1614*0c16b537SWarner Losh     if (cSrcSize<2) return ERROR(srcSize_wrong);   /* too small input size */
1615*0c16b537SWarner Losh 
1616*0c16b537SWarner Losh     /* normal FSE decoding mode */
1617*0c16b537SWarner Losh     errorCode = FSE_readNCount (counting, &maxSymbolValue, &tableLog, istart, cSrcSize);
1618*0c16b537SWarner Losh     if (FSE_isError(errorCode)) return errorCode;
1619*0c16b537SWarner Losh     if (errorCode >= cSrcSize) return ERROR(srcSize_wrong);   /* too small input size */
1620*0c16b537SWarner Losh     ip += errorCode;
1621*0c16b537SWarner Losh     cSrcSize -= errorCode;
1622*0c16b537SWarner Losh 
1623*0c16b537SWarner Losh     errorCode = FSE_buildDTable (dt, counting, maxSymbolValue, tableLog);
1624*0c16b537SWarner Losh     if (FSE_isError(errorCode)) return errorCode;
1625*0c16b537SWarner Losh 
1626*0c16b537SWarner Losh     /* always return, even if it is an error code */
1627*0c16b537SWarner Losh     return FSE_decompress_usingDTable (dst, maxDstSize, ip, cSrcSize, dt);
1628*0c16b537SWarner Losh }
1629*0c16b537SWarner Losh 
1630*0c16b537SWarner Losh 
1631*0c16b537SWarner Losh 
1632*0c16b537SWarner Losh #endif   /* FSE_COMMONDEFS_ONLY */
1633*0c16b537SWarner Losh 
1634*0c16b537SWarner Losh 
1635*0c16b537SWarner Losh /* ******************************************************************
1636*0c16b537SWarner Losh    Huff0 : Huffman coder, part of New Generation Entropy library
1637*0c16b537SWarner Losh    header file
1638*0c16b537SWarner Losh    Copyright (C) 2013-2015, Yann Collet.
1639*0c16b537SWarner Losh 
1640*0c16b537SWarner Losh    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
1641*0c16b537SWarner Losh 
1642*0c16b537SWarner Losh    Redistribution and use in source and binary forms, with or without
1643*0c16b537SWarner Losh    modification, are permitted provided that the following conditions are
1644*0c16b537SWarner Losh    met:
1645*0c16b537SWarner Losh 
1646*0c16b537SWarner Losh        * Redistributions of source code must retain the above copyright
1647*0c16b537SWarner Losh    notice, this list of conditions and the following disclaimer.
1648*0c16b537SWarner Losh        * Redistributions in binary form must reproduce the above
1649*0c16b537SWarner Losh    copyright notice, this list of conditions and the following disclaimer
1650*0c16b537SWarner Losh    in the documentation and/or other materials provided with the
1651*0c16b537SWarner Losh    distribution.
1652*0c16b537SWarner Losh 
1653*0c16b537SWarner Losh    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1654*0c16b537SWarner Losh    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1655*0c16b537SWarner Losh    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1656*0c16b537SWarner Losh    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1657*0c16b537SWarner Losh    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1658*0c16b537SWarner Losh    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1659*0c16b537SWarner Losh    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1660*0c16b537SWarner Losh    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1661*0c16b537SWarner Losh    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1662*0c16b537SWarner Losh    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1663*0c16b537SWarner Losh    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1664*0c16b537SWarner Losh 
1665*0c16b537SWarner Losh    You can contact the author at :
1666*0c16b537SWarner Losh    - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
1667*0c16b537SWarner Losh    - Public forum : https://groups.google.com/forum/#!forum/lz4c
1668*0c16b537SWarner Losh ****************************************************************** */
1669*0c16b537SWarner Losh #ifndef HUFF0_H
1670*0c16b537SWarner Losh #define HUFF0_H
1671*0c16b537SWarner Losh 
1672*0c16b537SWarner Losh #if defined (__cplusplus)
1673*0c16b537SWarner Losh extern "C" {
1674*0c16b537SWarner Losh #endif
1675*0c16b537SWarner Losh 
1676*0c16b537SWarner Losh 
1677*0c16b537SWarner Losh /* ****************************************
1678*0c16b537SWarner Losh *  Dependency
1679*0c16b537SWarner Losh ******************************************/
1680*0c16b537SWarner Losh #include <stddef.h>    /* size_t */
1681*0c16b537SWarner Losh 
1682*0c16b537SWarner Losh 
1683*0c16b537SWarner Losh /* ****************************************
1684*0c16b537SWarner Losh *  Huff0 simple functions
1685*0c16b537SWarner Losh ******************************************/
1686*0c16b537SWarner Losh static size_t HUF_decompress(void* dst,  size_t dstSize,
1687*0c16b537SWarner Losh                 const void* cSrc, size_t cSrcSize);
1688*0c16b537SWarner Losh /*!
1689*0c16b537SWarner Losh HUF_decompress():
1690*0c16b537SWarner Losh     Decompress Huff0 data from buffer 'cSrc', of size 'cSrcSize',
1691*0c16b537SWarner Losh     into already allocated destination buffer 'dst', of size 'dstSize'.
1692*0c16b537SWarner Losh     'dstSize' must be the exact size of original (uncompressed) data.
1693*0c16b537SWarner Losh     Note : in contrast with FSE, HUF_decompress can regenerate RLE (cSrcSize==1) and uncompressed (cSrcSize==dstSize) data, because it knows size to regenerate.
1694*0c16b537SWarner Losh     @return : size of regenerated data (== dstSize)
1695*0c16b537SWarner Losh               or an error code, which can be tested using HUF_isError()
1696*0c16b537SWarner Losh */
1697*0c16b537SWarner Losh 
1698*0c16b537SWarner Losh 
1699*0c16b537SWarner Losh /* ****************************************
1700*0c16b537SWarner Losh *  Tool functions
1701*0c16b537SWarner Losh ******************************************/
1702*0c16b537SWarner Losh /* Error Management */
1703*0c16b537SWarner Losh static unsigned    HUF_isError(size_t code);        /* tells if a return value is an error code */
1704*0c16b537SWarner Losh 
1705*0c16b537SWarner Losh 
1706*0c16b537SWarner Losh #if defined (__cplusplus)
1707*0c16b537SWarner Losh }
1708*0c16b537SWarner Losh #endif
1709*0c16b537SWarner Losh 
1710*0c16b537SWarner Losh #endif   /* HUFF0_H */
1711*0c16b537SWarner Losh 
1712*0c16b537SWarner Losh 
1713*0c16b537SWarner Losh /* ******************************************************************
1714*0c16b537SWarner Losh    Huff0 : Huffman coder, part of New Generation Entropy library
1715*0c16b537SWarner Losh    header file for static linking (only)
1716*0c16b537SWarner Losh    Copyright (C) 2013-2015, Yann Collet
1717*0c16b537SWarner Losh 
1718*0c16b537SWarner Losh    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
1719*0c16b537SWarner Losh 
1720*0c16b537SWarner Losh    Redistribution and use in source and binary forms, with or without
1721*0c16b537SWarner Losh    modification, are permitted provided that the following conditions are
1722*0c16b537SWarner Losh    met:
1723*0c16b537SWarner Losh 
1724*0c16b537SWarner Losh        * Redistributions of source code must retain the above copyright
1725*0c16b537SWarner Losh    notice, this list of conditions and the following disclaimer.
1726*0c16b537SWarner Losh        * Redistributions in binary form must reproduce the above
1727*0c16b537SWarner Losh    copyright notice, this list of conditions and the following disclaimer
1728*0c16b537SWarner Losh    in the documentation and/or other materials provided with the
1729*0c16b537SWarner Losh    distribution.
1730*0c16b537SWarner Losh 
1731*0c16b537SWarner Losh    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1732*0c16b537SWarner Losh    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1733*0c16b537SWarner Losh    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1734*0c16b537SWarner Losh    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1735*0c16b537SWarner Losh    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1736*0c16b537SWarner Losh    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1737*0c16b537SWarner Losh    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1738*0c16b537SWarner Losh    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1739*0c16b537SWarner Losh    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1740*0c16b537SWarner Losh    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1741*0c16b537SWarner Losh    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1742*0c16b537SWarner Losh 
1743*0c16b537SWarner Losh    You can contact the author at :
1744*0c16b537SWarner Losh    - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
1745*0c16b537SWarner Losh    - Public forum : https://groups.google.com/forum/#!forum/lz4c
1746*0c16b537SWarner Losh ****************************************************************** */
1747*0c16b537SWarner Losh #ifndef HUFF0_STATIC_H
1748*0c16b537SWarner Losh #define HUFF0_STATIC_H
1749*0c16b537SWarner Losh 
1750*0c16b537SWarner Losh #if defined (__cplusplus)
1751*0c16b537SWarner Losh extern "C" {
1752*0c16b537SWarner Losh #endif
1753*0c16b537SWarner Losh 
1754*0c16b537SWarner Losh 
1755*0c16b537SWarner Losh 
1756*0c16b537SWarner Losh /* ****************************************
1757*0c16b537SWarner Losh *  Static allocation macros
1758*0c16b537SWarner Losh ******************************************/
1759*0c16b537SWarner Losh /* static allocation of Huff0's DTable */
1760*0c16b537SWarner Losh #define HUF_DTABLE_SIZE(maxTableLog)   (1 + (1<<maxTableLog))  /* nb Cells; use unsigned short for X2, unsigned int for X4 */
1761*0c16b537SWarner Losh #define HUF_CREATE_STATIC_DTABLEX2(DTable, maxTableLog) \
1762*0c16b537SWarner Losh         unsigned short DTable[HUF_DTABLE_SIZE(maxTableLog)] = { maxTableLog }
1763*0c16b537SWarner Losh #define HUF_CREATE_STATIC_DTABLEX4(DTable, maxTableLog) \
1764*0c16b537SWarner Losh         unsigned int DTable[HUF_DTABLE_SIZE(maxTableLog)] = { maxTableLog }
1765*0c16b537SWarner Losh #define HUF_CREATE_STATIC_DTABLEX6(DTable, maxTableLog) \
1766*0c16b537SWarner Losh         unsigned int DTable[HUF_DTABLE_SIZE(maxTableLog) * 3 / 2] = { maxTableLog }
1767*0c16b537SWarner Losh 
1768*0c16b537SWarner Losh 
1769*0c16b537SWarner Losh /* ****************************************
1770*0c16b537SWarner Losh *  Advanced decompression functions
1771*0c16b537SWarner Losh ******************************************/
1772*0c16b537SWarner Losh static size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /* single-symbol decoder */
1773*0c16b537SWarner Losh static size_t HUF_decompress4X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /* double-symbols decoder */
1774*0c16b537SWarner Losh 
1775*0c16b537SWarner Losh 
1776*0c16b537SWarner Losh /* ****************************************
1777*0c16b537SWarner Losh *  Huff0 detailed API
1778*0c16b537SWarner Losh ******************************************/
1779*0c16b537SWarner Losh /*!
1780*0c16b537SWarner Losh HUF_decompress() does the following:
1781*0c16b537SWarner Losh 1. select the decompression algorithm (X2, X4, X6) based on pre-computed heuristics
1782*0c16b537SWarner Losh 2. build Huffman table from save, using HUF_readDTableXn()
1783*0c16b537SWarner Losh 3. decode 1 or 4 segments in parallel using HUF_decompressSXn_usingDTable
1784*0c16b537SWarner Losh 
1785*0c16b537SWarner Losh */
1786*0c16b537SWarner Losh static size_t HUF_readDTableX2 (unsigned short* DTable, const void* src, size_t srcSize);
1787*0c16b537SWarner Losh static size_t HUF_readDTableX4 (unsigned* DTable, const void* src, size_t srcSize);
1788*0c16b537SWarner Losh 
1789*0c16b537SWarner Losh static size_t HUF_decompress4X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const unsigned short* DTable);
1790*0c16b537SWarner Losh static size_t HUF_decompress4X4_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const unsigned* DTable);
1791*0c16b537SWarner Losh 
1792*0c16b537SWarner Losh 
1793*0c16b537SWarner Losh #if defined (__cplusplus)
1794*0c16b537SWarner Losh }
1795*0c16b537SWarner Losh #endif
1796*0c16b537SWarner Losh 
1797*0c16b537SWarner Losh #endif /* HUFF0_STATIC_H */
1798*0c16b537SWarner Losh 
1799*0c16b537SWarner Losh 
1800*0c16b537SWarner Losh 
1801*0c16b537SWarner Losh /* ******************************************************************
1802*0c16b537SWarner Losh    Huff0 : Huffman coder, part of New Generation Entropy library
1803*0c16b537SWarner Losh    Copyright (C) 2013-2015, Yann Collet.
1804*0c16b537SWarner Losh 
1805*0c16b537SWarner Losh    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
1806*0c16b537SWarner Losh 
1807*0c16b537SWarner Losh    Redistribution and use in source and binary forms, with or without
1808*0c16b537SWarner Losh    modification, are permitted provided that the following conditions are
1809*0c16b537SWarner Losh    met:
1810*0c16b537SWarner Losh 
1811*0c16b537SWarner Losh        * Redistributions of source code must retain the above copyright
1812*0c16b537SWarner Losh    notice, this list of conditions and the following disclaimer.
1813*0c16b537SWarner Losh        * Redistributions in binary form must reproduce the above
1814*0c16b537SWarner Losh    copyright notice, this list of conditions and the following disclaimer
1815*0c16b537SWarner Losh    in the documentation and/or other materials provided with the
1816*0c16b537SWarner Losh    distribution.
1817*0c16b537SWarner Losh 
1818*0c16b537SWarner Losh    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1819*0c16b537SWarner Losh    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1820*0c16b537SWarner Losh    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1821*0c16b537SWarner Losh    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1822*0c16b537SWarner Losh    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1823*0c16b537SWarner Losh    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1824*0c16b537SWarner Losh    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1825*0c16b537SWarner Losh    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1826*0c16b537SWarner Losh    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1827*0c16b537SWarner Losh    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1828*0c16b537SWarner Losh    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1829*0c16b537SWarner Losh 
1830*0c16b537SWarner Losh     You can contact the author at :
1831*0c16b537SWarner Losh     - FSE+Huff0 source repository : https://github.com/Cyan4973/FiniteStateEntropy
1832*0c16b537SWarner Losh ****************************************************************** */
1833*0c16b537SWarner Losh 
1834*0c16b537SWarner Losh /* **************************************************************
1835*0c16b537SWarner Losh *  Compiler specifics
1836*0c16b537SWarner Losh ****************************************************************/
1837*0c16b537SWarner Losh #if defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
1838*0c16b537SWarner Losh /* inline is defined */
1839*0c16b537SWarner Losh #elif defined(_MSC_VER)
1840*0c16b537SWarner Losh #  define inline __inline
1841*0c16b537SWarner Losh #else
1842*0c16b537SWarner Losh #  define inline /* disable inline */
1843*0c16b537SWarner Losh #endif
1844*0c16b537SWarner Losh 
1845*0c16b537SWarner Losh 
1846*0c16b537SWarner Losh #ifdef _MSC_VER    /* Visual Studio */
1847*0c16b537SWarner Losh #  pragma warning(disable : 4127)        /* disable: C4127: conditional expression is constant */
1848*0c16b537SWarner Losh #endif
1849*0c16b537SWarner Losh 
1850*0c16b537SWarner Losh 
1851*0c16b537SWarner Losh /* **************************************************************
1852*0c16b537SWarner Losh *  Includes
1853*0c16b537SWarner Losh ****************************************************************/
1854*0c16b537SWarner Losh #include <stdlib.h>     /* malloc, free, qsort */
1855*0c16b537SWarner Losh #include <string.h>     /* memcpy, memset */
1856*0c16b537SWarner Losh #include <stdio.h>      /* printf (debug) */
1857*0c16b537SWarner Losh 
1858*0c16b537SWarner Losh 
1859*0c16b537SWarner Losh /* **************************************************************
1860*0c16b537SWarner Losh *  Constants
1861*0c16b537SWarner Losh ****************************************************************/
1862*0c16b537SWarner Losh #define HUF_ABSOLUTEMAX_TABLELOG  16   /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */
1863*0c16b537SWarner Losh #define HUF_MAX_TABLELOG  12           /* max configured tableLog (for static allocation); can be modified up to HUF_ABSOLUTEMAX_TABLELOG */
1864*0c16b537SWarner Losh #define HUF_DEFAULT_TABLELOG  HUF_MAX_TABLELOG   /* tableLog by default, when not specified */
1865*0c16b537SWarner Losh #define HUF_MAX_SYMBOL_VALUE 255
1866*0c16b537SWarner Losh #if (HUF_MAX_TABLELOG > HUF_ABSOLUTEMAX_TABLELOG)
1867*0c16b537SWarner Losh #  error "HUF_MAX_TABLELOG is too large !"
1868*0c16b537SWarner Losh #endif
1869*0c16b537SWarner Losh 
1870*0c16b537SWarner Losh 
1871*0c16b537SWarner Losh /* **************************************************************
1872*0c16b537SWarner Losh *  Error Management
1873*0c16b537SWarner Losh ****************************************************************/
1874*0c16b537SWarner Losh static unsigned HUF_isError(size_t code) { return ERR_isError(code); }
1875*0c16b537SWarner Losh #define HUF_STATIC_ASSERT(c) { enum { HUF_static_assert = 1/(int)(!!(c)) }; }   /* use only *after* variable declarations */
1876*0c16b537SWarner Losh 
1877*0c16b537SWarner Losh 
1878*0c16b537SWarner Losh 
1879*0c16b537SWarner Losh /*-*******************************************************
1880*0c16b537SWarner Losh *  Huff0 : Huffman block decompression
1881*0c16b537SWarner Losh *********************************************************/
1882*0c16b537SWarner Losh typedef struct { BYTE byte; BYTE nbBits; } HUF_DEltX2;   /* single-symbol decoding */
1883*0c16b537SWarner Losh 
1884*0c16b537SWarner Losh typedef struct { U16 sequence; BYTE nbBits; BYTE length; } HUF_DEltX4;  /* double-symbols decoding */
1885*0c16b537SWarner Losh 
1886*0c16b537SWarner Losh typedef struct { BYTE symbol; BYTE weight; } sortedSymbol_t;
1887*0c16b537SWarner Losh 
1888*0c16b537SWarner Losh /*! HUF_readStats
1889*0c16b537SWarner Losh     Read compact Huffman tree, saved by HUF_writeCTable
1890*0c16b537SWarner Losh     @huffWeight : destination buffer
1891*0c16b537SWarner Losh     @return : size read from `src`
1892*0c16b537SWarner Losh */
1893*0c16b537SWarner Losh static size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats,
1894*0c16b537SWarner Losh                             U32* nbSymbolsPtr, U32* tableLogPtr,
1895*0c16b537SWarner Losh                             const void* src, size_t srcSize)
1896*0c16b537SWarner Losh {
1897*0c16b537SWarner Losh     U32 weightTotal;
1898*0c16b537SWarner Losh     U32 tableLog;
1899*0c16b537SWarner Losh     const BYTE* ip = (const BYTE*) src;
1900*0c16b537SWarner Losh     size_t iSize;
1901*0c16b537SWarner Losh     size_t oSize;
1902*0c16b537SWarner Losh     U32 n;
1903*0c16b537SWarner Losh 
1904*0c16b537SWarner Losh     if (!srcSize) return ERROR(srcSize_wrong);
1905*0c16b537SWarner Losh     iSize = ip[0];
1906*0c16b537SWarner Losh     //memset(huffWeight, 0, hwSize);   /* is not necessary, even though some analyzer complain ... */
1907*0c16b537SWarner Losh 
1908*0c16b537SWarner Losh     if (iSize >= 128)  /* special header */
1909*0c16b537SWarner Losh     {
1910*0c16b537SWarner Losh         if (iSize >= (242))   /* RLE */
1911*0c16b537SWarner Losh         {
1912*0c16b537SWarner Losh             static int l[14] = { 1, 2, 3, 4, 7, 8, 15, 16, 31, 32, 63, 64, 127, 128 };
1913*0c16b537SWarner Losh             oSize = l[iSize-242];
1914*0c16b537SWarner Losh             memset(huffWeight, 1, hwSize);
1915*0c16b537SWarner Losh             iSize = 0;
1916*0c16b537SWarner Losh         }
1917*0c16b537SWarner Losh         else   /* Incompressible */
1918*0c16b537SWarner Losh         {
1919*0c16b537SWarner Losh             oSize = iSize - 127;
1920*0c16b537SWarner Losh             iSize = ((oSize+1)/2);
1921*0c16b537SWarner Losh             if (iSize+1 > srcSize) return ERROR(srcSize_wrong);
1922*0c16b537SWarner Losh             if (oSize >= hwSize) return ERROR(corruption_detected);
1923*0c16b537SWarner Losh             ip += 1;
1924*0c16b537SWarner Losh             for (n=0; n<oSize; n+=2)
1925*0c16b537SWarner Losh             {
1926*0c16b537SWarner Losh                 huffWeight[n]   = ip[n/2] >> 4;
1927*0c16b537SWarner Losh                 huffWeight[n+1] = ip[n/2] & 15;
1928*0c16b537SWarner Losh             }
1929*0c16b537SWarner Losh         }
1930*0c16b537SWarner Losh     }
1931*0c16b537SWarner Losh     else  /* header compressed with FSE (normal case) */
1932*0c16b537SWarner Losh     {
1933*0c16b537SWarner Losh         if (iSize+1 > srcSize) return ERROR(srcSize_wrong);
1934*0c16b537SWarner Losh         oSize = FSE_decompress(huffWeight, hwSize-1, ip+1, iSize);   /* max (hwSize-1) values decoded, as last one is implied */
1935*0c16b537SWarner Losh         if (FSE_isError(oSize)) return oSize;
1936*0c16b537SWarner Losh     }
1937*0c16b537SWarner Losh 
1938*0c16b537SWarner Losh     /* collect weight stats */
1939*0c16b537SWarner Losh     memset(rankStats, 0, (HUF_ABSOLUTEMAX_TABLELOG + 1) * sizeof(U32));
1940*0c16b537SWarner Losh     weightTotal = 0;
1941*0c16b537SWarner Losh     for (n=0; n<oSize; n++)
1942*0c16b537SWarner Losh     {
1943*0c16b537SWarner Losh         if (huffWeight[n] >= HUF_ABSOLUTEMAX_TABLELOG) return ERROR(corruption_detected);
1944*0c16b537SWarner Losh         rankStats[huffWeight[n]]++;
1945*0c16b537SWarner Losh         weightTotal += (1 << huffWeight[n]) >> 1;
1946*0c16b537SWarner Losh     }
1947*0c16b537SWarner Losh     if (weightTotal == 0) return ERROR(corruption_detected);
1948*0c16b537SWarner Losh 
1949*0c16b537SWarner Losh     /* get last non-null symbol weight (implied, total must be 2^n) */
1950*0c16b537SWarner Losh     tableLog = BIT_highbit32(weightTotal) + 1;
1951*0c16b537SWarner Losh     if (tableLog > HUF_ABSOLUTEMAX_TABLELOG) return ERROR(corruption_detected);
1952*0c16b537SWarner Losh     {
1953*0c16b537SWarner Losh         U32 total = 1 << tableLog;
1954*0c16b537SWarner Losh         U32 rest = total - weightTotal;
1955*0c16b537SWarner Losh         U32 verif = 1 << BIT_highbit32(rest);
1956*0c16b537SWarner Losh         U32 lastWeight = BIT_highbit32(rest) + 1;
1957*0c16b537SWarner Losh         if (verif != rest) return ERROR(corruption_detected);    /* last value must be a clean power of 2 */
1958*0c16b537SWarner Losh         huffWeight[oSize] = (BYTE)lastWeight;
1959*0c16b537SWarner Losh         rankStats[lastWeight]++;
1960*0c16b537SWarner Losh     }
1961*0c16b537SWarner Losh 
1962*0c16b537SWarner Losh     /* check tree construction validity */
1963*0c16b537SWarner Losh     if ((rankStats[1] < 2) || (rankStats[1] & 1)) return ERROR(corruption_detected);   /* by construction : at least 2 elts of rank 1, must be even */
1964*0c16b537SWarner Losh 
1965*0c16b537SWarner Losh     /* results */
1966*0c16b537SWarner Losh     *nbSymbolsPtr = (U32)(oSize+1);
1967*0c16b537SWarner Losh     *tableLogPtr = tableLog;
1968*0c16b537SWarner Losh     return iSize+1;
1969*0c16b537SWarner Losh }
1970*0c16b537SWarner Losh 
1971*0c16b537SWarner Losh 
1972*0c16b537SWarner Losh /**************************/
1973*0c16b537SWarner Losh /* single-symbol decoding */
1974*0c16b537SWarner Losh /**************************/
1975*0c16b537SWarner Losh 
1976*0c16b537SWarner Losh static size_t HUF_readDTableX2 (U16* DTable, const void* src, size_t srcSize)
1977*0c16b537SWarner Losh {
1978*0c16b537SWarner Losh     BYTE huffWeight[HUF_MAX_SYMBOL_VALUE + 1];
1979*0c16b537SWarner Losh     U32 rankVal[HUF_ABSOLUTEMAX_TABLELOG + 1];   /* large enough for values from 0 to 16 */
1980*0c16b537SWarner Losh     U32 tableLog = 0;
1981*0c16b537SWarner Losh     size_t iSize;
1982*0c16b537SWarner Losh     U32 nbSymbols = 0;
1983*0c16b537SWarner Losh     U32 n;
1984*0c16b537SWarner Losh     U32 nextRankStart;
1985*0c16b537SWarner Losh     void* const dtPtr = DTable + 1;
1986*0c16b537SWarner Losh     HUF_DEltX2* const dt = (HUF_DEltX2*)dtPtr;
1987*0c16b537SWarner Losh 
1988*0c16b537SWarner Losh     HUF_STATIC_ASSERT(sizeof(HUF_DEltX2) == sizeof(U16));   /* if compilation fails here, assertion is false */
1989*0c16b537SWarner Losh     //memset(huffWeight, 0, sizeof(huffWeight));   /* is not necessary, even though some analyzer complain ... */
1990*0c16b537SWarner Losh 
1991*0c16b537SWarner Losh     iSize = HUF_readStats(huffWeight, HUF_MAX_SYMBOL_VALUE + 1, rankVal, &nbSymbols, &tableLog, src, srcSize);
1992*0c16b537SWarner Losh     if (HUF_isError(iSize)) return iSize;
1993*0c16b537SWarner Losh 
1994*0c16b537SWarner Losh     /* check result */
1995*0c16b537SWarner Losh     if (tableLog > DTable[0]) return ERROR(tableLog_tooLarge);   /* DTable is too small */
1996*0c16b537SWarner Losh     DTable[0] = (U16)tableLog;   /* maybe should separate sizeof DTable, as allocated, from used size of DTable, in case of DTable re-use */
1997*0c16b537SWarner Losh 
1998*0c16b537SWarner Losh     /* Prepare ranks */
1999*0c16b537SWarner Losh     nextRankStart = 0;
2000*0c16b537SWarner Losh     for (n=1; n<=tableLog; n++)
2001*0c16b537SWarner Losh     {
2002*0c16b537SWarner Losh         U32 current = nextRankStart;
2003*0c16b537SWarner Losh         nextRankStart += (rankVal[n] << (n-1));
2004*0c16b537SWarner Losh         rankVal[n] = current;
2005*0c16b537SWarner Losh     }
2006*0c16b537SWarner Losh 
2007*0c16b537SWarner Losh     /* fill DTable */
2008*0c16b537SWarner Losh     for (n=0; n<nbSymbols; n++)
2009*0c16b537SWarner Losh     {
2010*0c16b537SWarner Losh         const U32 w = huffWeight[n];
2011*0c16b537SWarner Losh         const U32 length = (1 << w) >> 1;
2012*0c16b537SWarner Losh         U32 i;
2013*0c16b537SWarner Losh         HUF_DEltX2 D;
2014*0c16b537SWarner Losh         D.byte = (BYTE)n; D.nbBits = (BYTE)(tableLog + 1 - w);
2015*0c16b537SWarner Losh         for (i = rankVal[w]; i < rankVal[w] + length; i++)
2016*0c16b537SWarner Losh             dt[i] = D;
2017*0c16b537SWarner Losh         rankVal[w] += length;
2018*0c16b537SWarner Losh     }
2019*0c16b537SWarner Losh 
2020*0c16b537SWarner Losh     return iSize;
2021*0c16b537SWarner Losh }
2022*0c16b537SWarner Losh 
2023*0c16b537SWarner Losh static BYTE HUF_decodeSymbolX2(BIT_DStream_t* Dstream, const HUF_DEltX2* dt, const U32 dtLog)
2024*0c16b537SWarner Losh {
2025*0c16b537SWarner Losh         const size_t val = BIT_lookBitsFast(Dstream, dtLog); /* note : dtLog >= 1 */
2026*0c16b537SWarner Losh         const BYTE c = dt[val].byte;
2027*0c16b537SWarner Losh         BIT_skipBits(Dstream, dt[val].nbBits);
2028*0c16b537SWarner Losh         return c;
2029*0c16b537SWarner Losh }
2030*0c16b537SWarner Losh 
2031*0c16b537SWarner Losh #define HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr) \
2032*0c16b537SWarner Losh     *ptr++ = HUF_decodeSymbolX2(DStreamPtr, dt, dtLog)
2033*0c16b537SWarner Losh 
2034*0c16b537SWarner Losh #define HUF_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \
2035*0c16b537SWarner Losh     if (MEM_64bits() || (HUF_MAX_TABLELOG<=12)) \
2036*0c16b537SWarner Losh         HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr)
2037*0c16b537SWarner Losh 
2038*0c16b537SWarner Losh #define HUF_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \
2039*0c16b537SWarner Losh     if (MEM_64bits()) \
2040*0c16b537SWarner Losh         HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr)
2041*0c16b537SWarner Losh 
2042*0c16b537SWarner Losh static inline size_t HUF_decodeStreamX2(BYTE* p, BIT_DStream_t* const bitDPtr, BYTE* const pEnd, const HUF_DEltX2* const dt, const U32 dtLog)
2043*0c16b537SWarner Losh {
2044*0c16b537SWarner Losh     BYTE* const pStart = p;
2045*0c16b537SWarner Losh 
2046*0c16b537SWarner Losh     /* up to 4 symbols at a time */
2047*0c16b537SWarner Losh     while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p <= pEnd-4))
2048*0c16b537SWarner Losh     {
2049*0c16b537SWarner Losh         HUF_DECODE_SYMBOLX2_2(p, bitDPtr);
2050*0c16b537SWarner Losh         HUF_DECODE_SYMBOLX2_1(p, bitDPtr);
2051*0c16b537SWarner Losh         HUF_DECODE_SYMBOLX2_2(p, bitDPtr);
2052*0c16b537SWarner Losh         HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
2053*0c16b537SWarner Losh     }
2054*0c16b537SWarner Losh 
2055*0c16b537SWarner Losh     /* closer to the end */
2056*0c16b537SWarner Losh     while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p < pEnd))
2057*0c16b537SWarner Losh         HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
2058*0c16b537SWarner Losh 
2059*0c16b537SWarner Losh     /* no more data to retrieve from bitstream, hence no need to reload */
2060*0c16b537SWarner Losh     while (p < pEnd)
2061*0c16b537SWarner Losh         HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
2062*0c16b537SWarner Losh 
2063*0c16b537SWarner Losh     return pEnd-pStart;
2064*0c16b537SWarner Losh }
2065*0c16b537SWarner Losh 
2066*0c16b537SWarner Losh 
2067*0c16b537SWarner Losh static size_t HUF_decompress4X2_usingDTable(
2068*0c16b537SWarner Losh           void* dst,  size_t dstSize,
2069*0c16b537SWarner Losh     const void* cSrc, size_t cSrcSize,
2070*0c16b537SWarner Losh     const U16* DTable)
2071*0c16b537SWarner Losh {
2072*0c16b537SWarner Losh     if (cSrcSize < 10) return ERROR(corruption_detected);   /* strict minimum : jump table + 1 byte per stream */
2073*0c16b537SWarner Losh 
2074*0c16b537SWarner Losh     {
2075*0c16b537SWarner Losh         const BYTE* const istart = (const BYTE*) cSrc;
2076*0c16b537SWarner Losh         BYTE* const ostart = (BYTE*) dst;
2077*0c16b537SWarner Losh         BYTE* const oend = ostart + dstSize;
2078*0c16b537SWarner Losh         const void* const dtPtr = DTable;
2079*0c16b537SWarner Losh         const HUF_DEltX2* const dt = ((const HUF_DEltX2*)dtPtr) +1;
2080*0c16b537SWarner Losh         const U32 dtLog = DTable[0];
2081*0c16b537SWarner Losh         size_t errorCode;
2082*0c16b537SWarner Losh 
2083*0c16b537SWarner Losh         /* Init */
2084*0c16b537SWarner Losh         BIT_DStream_t bitD1;
2085*0c16b537SWarner Losh         BIT_DStream_t bitD2;
2086*0c16b537SWarner Losh         BIT_DStream_t bitD3;
2087*0c16b537SWarner Losh         BIT_DStream_t bitD4;
2088*0c16b537SWarner Losh         const size_t length1 = MEM_readLE16(istart);
2089*0c16b537SWarner Losh         const size_t length2 = MEM_readLE16(istart+2);
2090*0c16b537SWarner Losh         const size_t length3 = MEM_readLE16(istart+4);
2091*0c16b537SWarner Losh         size_t length4;
2092*0c16b537SWarner Losh         const BYTE* const istart1 = istart + 6;  /* jumpTable */
2093*0c16b537SWarner Losh         const BYTE* const istart2 = istart1 + length1;
2094*0c16b537SWarner Losh         const BYTE* const istart3 = istart2 + length2;
2095*0c16b537SWarner Losh         const BYTE* const istart4 = istart3 + length3;
2096*0c16b537SWarner Losh         const size_t segmentSize = (dstSize+3) / 4;
2097*0c16b537SWarner Losh         BYTE* const opStart2 = ostart + segmentSize;
2098*0c16b537SWarner Losh         BYTE* const opStart3 = opStart2 + segmentSize;
2099*0c16b537SWarner Losh         BYTE* const opStart4 = opStart3 + segmentSize;
2100*0c16b537SWarner Losh         BYTE* op1 = ostart;
2101*0c16b537SWarner Losh         BYTE* op2 = opStart2;
2102*0c16b537SWarner Losh         BYTE* op3 = opStart3;
2103*0c16b537SWarner Losh         BYTE* op4 = opStart4;
2104*0c16b537SWarner Losh         U32 endSignal;
2105*0c16b537SWarner Losh 
2106*0c16b537SWarner Losh         length4 = cSrcSize - (length1 + length2 + length3 + 6);
2107*0c16b537SWarner Losh         if (length4 > cSrcSize) return ERROR(corruption_detected);   /* overflow */
2108*0c16b537SWarner Losh         errorCode = BIT_initDStream(&bitD1, istart1, length1);
2109*0c16b537SWarner Losh         if (HUF_isError(errorCode)) return errorCode;
2110*0c16b537SWarner Losh         errorCode = BIT_initDStream(&bitD2, istart2, length2);
2111*0c16b537SWarner Losh         if (HUF_isError(errorCode)) return errorCode;
2112*0c16b537SWarner Losh         errorCode = BIT_initDStream(&bitD3, istart3, length3);
2113*0c16b537SWarner Losh         if (HUF_isError(errorCode)) return errorCode;
2114*0c16b537SWarner Losh         errorCode = BIT_initDStream(&bitD4, istart4, length4);
2115*0c16b537SWarner Losh         if (HUF_isError(errorCode)) return errorCode;
2116*0c16b537SWarner Losh 
2117*0c16b537SWarner Losh         /* 16-32 symbols per loop (4-8 symbols per stream) */
2118*0c16b537SWarner Losh         endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
2119*0c16b537SWarner Losh         for ( ; (endSignal==BIT_DStream_unfinished) && (op4<(oend-7)) ; )
2120*0c16b537SWarner Losh         {
2121*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
2122*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
2123*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
2124*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX2_2(op4, &bitD4);
2125*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX2_1(op1, &bitD1);
2126*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX2_1(op2, &bitD2);
2127*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX2_1(op3, &bitD3);
2128*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX2_1(op4, &bitD4);
2129*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
2130*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
2131*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
2132*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX2_2(op4, &bitD4);
2133*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX2_0(op1, &bitD1);
2134*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX2_0(op2, &bitD2);
2135*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX2_0(op3, &bitD3);
2136*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX2_0(op4, &bitD4);
2137*0c16b537SWarner Losh 
2138*0c16b537SWarner Losh             endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
2139*0c16b537SWarner Losh         }
2140*0c16b537SWarner Losh 
2141*0c16b537SWarner Losh         /* check corruption */
2142*0c16b537SWarner Losh         if (op1 > opStart2) return ERROR(corruption_detected);
2143*0c16b537SWarner Losh         if (op2 > opStart3) return ERROR(corruption_detected);
2144*0c16b537SWarner Losh         if (op3 > opStart4) return ERROR(corruption_detected);
2145*0c16b537SWarner Losh         /* note : op4 supposed already verified within main loop */
2146*0c16b537SWarner Losh 
2147*0c16b537SWarner Losh         /* finish bitStreams one by one */
2148*0c16b537SWarner Losh         HUF_decodeStreamX2(op1, &bitD1, opStart2, dt, dtLog);
2149*0c16b537SWarner Losh         HUF_decodeStreamX2(op2, &bitD2, opStart3, dt, dtLog);
2150*0c16b537SWarner Losh         HUF_decodeStreamX2(op3, &bitD3, opStart4, dt, dtLog);
2151*0c16b537SWarner Losh         HUF_decodeStreamX2(op4, &bitD4, oend,     dt, dtLog);
2152*0c16b537SWarner Losh 
2153*0c16b537SWarner Losh         /* check */
2154*0c16b537SWarner Losh         endSignal = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4);
2155*0c16b537SWarner Losh         if (!endSignal) return ERROR(corruption_detected);
2156*0c16b537SWarner Losh 
2157*0c16b537SWarner Losh         /* decoded size */
2158*0c16b537SWarner Losh         return dstSize;
2159*0c16b537SWarner Losh     }
2160*0c16b537SWarner Losh }
2161*0c16b537SWarner Losh 
2162*0c16b537SWarner Losh 
2163*0c16b537SWarner Losh static size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
2164*0c16b537SWarner Losh {
2165*0c16b537SWarner Losh     HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_MAX_TABLELOG);
2166*0c16b537SWarner Losh     const BYTE* ip = (const BYTE*) cSrc;
2167*0c16b537SWarner Losh     size_t errorCode;
2168*0c16b537SWarner Losh 
2169*0c16b537SWarner Losh     errorCode = HUF_readDTableX2 (DTable, cSrc, cSrcSize);
2170*0c16b537SWarner Losh     if (HUF_isError(errorCode)) return errorCode;
2171*0c16b537SWarner Losh     if (errorCode >= cSrcSize) return ERROR(srcSize_wrong);
2172*0c16b537SWarner Losh     ip += errorCode;
2173*0c16b537SWarner Losh     cSrcSize -= errorCode;
2174*0c16b537SWarner Losh 
2175*0c16b537SWarner Losh     return HUF_decompress4X2_usingDTable (dst, dstSize, ip, cSrcSize, DTable);
2176*0c16b537SWarner Losh }
2177*0c16b537SWarner Losh 
2178*0c16b537SWarner Losh 
2179*0c16b537SWarner Losh /***************************/
2180*0c16b537SWarner Losh /* double-symbols decoding */
2181*0c16b537SWarner Losh /***************************/
2182*0c16b537SWarner Losh 
2183*0c16b537SWarner Losh static void HUF_fillDTableX4Level2(HUF_DEltX4* DTable, U32 sizeLog, const U32 consumed,
2184*0c16b537SWarner Losh                            const U32* rankValOrigin, const int minWeight,
2185*0c16b537SWarner Losh                            const sortedSymbol_t* sortedSymbols, const U32 sortedListSize,
2186*0c16b537SWarner Losh                            U32 nbBitsBaseline, U16 baseSeq)
2187*0c16b537SWarner Losh {
2188*0c16b537SWarner Losh     HUF_DEltX4 DElt;
2189*0c16b537SWarner Losh     U32 rankVal[HUF_ABSOLUTEMAX_TABLELOG + 1];
2190*0c16b537SWarner Losh     U32 s;
2191*0c16b537SWarner Losh 
2192*0c16b537SWarner Losh     /* get pre-calculated rankVal */
2193*0c16b537SWarner Losh     memcpy(rankVal, rankValOrigin, sizeof(rankVal));
2194*0c16b537SWarner Losh 
2195*0c16b537SWarner Losh     /* fill skipped values */
2196*0c16b537SWarner Losh     if (minWeight>1)
2197*0c16b537SWarner Losh     {
2198*0c16b537SWarner Losh         U32 i, skipSize = rankVal[minWeight];
2199*0c16b537SWarner Losh         MEM_writeLE16(&(DElt.sequence), baseSeq);
2200*0c16b537SWarner Losh         DElt.nbBits   = (BYTE)(consumed);
2201*0c16b537SWarner Losh         DElt.length   = 1;
2202*0c16b537SWarner Losh         for (i = 0; i < skipSize; i++)
2203*0c16b537SWarner Losh             DTable[i] = DElt;
2204*0c16b537SWarner Losh     }
2205*0c16b537SWarner Losh 
2206*0c16b537SWarner Losh     /* fill DTable */
2207*0c16b537SWarner Losh     for (s=0; s<sortedListSize; s++)   /* note : sortedSymbols already skipped */
2208*0c16b537SWarner Losh     {
2209*0c16b537SWarner Losh         const U32 symbol = sortedSymbols[s].symbol;
2210*0c16b537SWarner Losh         const U32 weight = sortedSymbols[s].weight;
2211*0c16b537SWarner Losh         const U32 nbBits = nbBitsBaseline - weight;
2212*0c16b537SWarner Losh         const U32 length = 1 << (sizeLog-nbBits);
2213*0c16b537SWarner Losh         const U32 start = rankVal[weight];
2214*0c16b537SWarner Losh         U32 i = start;
2215*0c16b537SWarner Losh         const U32 end = start + length;
2216*0c16b537SWarner Losh 
2217*0c16b537SWarner Losh         MEM_writeLE16(&(DElt.sequence), (U16)(baseSeq + (symbol << 8)));
2218*0c16b537SWarner Losh         DElt.nbBits = (BYTE)(nbBits + consumed);
2219*0c16b537SWarner Losh         DElt.length = 2;
2220*0c16b537SWarner Losh         do { DTable[i++] = DElt; } while (i<end);   /* since length >= 1 */
2221*0c16b537SWarner Losh 
2222*0c16b537SWarner Losh         rankVal[weight] += length;
2223*0c16b537SWarner Losh     }
2224*0c16b537SWarner Losh }
2225*0c16b537SWarner Losh 
2226*0c16b537SWarner Losh typedef U32 rankVal_t[HUF_ABSOLUTEMAX_TABLELOG][HUF_ABSOLUTEMAX_TABLELOG + 1];
2227*0c16b537SWarner Losh 
2228*0c16b537SWarner Losh static void HUF_fillDTableX4(HUF_DEltX4* DTable, const U32 targetLog,
2229*0c16b537SWarner Losh                            const sortedSymbol_t* sortedList, const U32 sortedListSize,
2230*0c16b537SWarner Losh                            const U32* rankStart, rankVal_t rankValOrigin, const U32 maxWeight,
2231*0c16b537SWarner Losh                            const U32 nbBitsBaseline)
2232*0c16b537SWarner Losh {
2233*0c16b537SWarner Losh     U32 rankVal[HUF_ABSOLUTEMAX_TABLELOG + 1];
2234*0c16b537SWarner Losh     const int scaleLog = nbBitsBaseline - targetLog;   /* note : targetLog >= srcLog, hence scaleLog <= 1 */
2235*0c16b537SWarner Losh     const U32 minBits  = nbBitsBaseline - maxWeight;
2236*0c16b537SWarner Losh     U32 s;
2237*0c16b537SWarner Losh 
2238*0c16b537SWarner Losh     memcpy(rankVal, rankValOrigin, sizeof(rankVal));
2239*0c16b537SWarner Losh 
2240*0c16b537SWarner Losh     /* fill DTable */
2241*0c16b537SWarner Losh     for (s=0; s<sortedListSize; s++)
2242*0c16b537SWarner Losh     {
2243*0c16b537SWarner Losh         const U16 symbol = sortedList[s].symbol;
2244*0c16b537SWarner Losh         const U32 weight = sortedList[s].weight;
2245*0c16b537SWarner Losh         const U32 nbBits = nbBitsBaseline - weight;
2246*0c16b537SWarner Losh         const U32 start = rankVal[weight];
2247*0c16b537SWarner Losh         const U32 length = 1 << (targetLog-nbBits);
2248*0c16b537SWarner Losh 
2249*0c16b537SWarner Losh         if (targetLog-nbBits >= minBits)   /* enough room for a second symbol */
2250*0c16b537SWarner Losh         {
2251*0c16b537SWarner Losh             U32 sortedRank;
2252*0c16b537SWarner Losh             int minWeight = nbBits + scaleLog;
2253*0c16b537SWarner Losh             if (minWeight < 1) minWeight = 1;
2254*0c16b537SWarner Losh             sortedRank = rankStart[minWeight];
2255*0c16b537SWarner Losh             HUF_fillDTableX4Level2(DTable+start, targetLog-nbBits, nbBits,
2256*0c16b537SWarner Losh                            rankValOrigin[nbBits], minWeight,
2257*0c16b537SWarner Losh                            sortedList+sortedRank, sortedListSize-sortedRank,
2258*0c16b537SWarner Losh                            nbBitsBaseline, symbol);
2259*0c16b537SWarner Losh         }
2260*0c16b537SWarner Losh         else
2261*0c16b537SWarner Losh         {
2262*0c16b537SWarner Losh             U32 i;
2263*0c16b537SWarner Losh             const U32 end = start + length;
2264*0c16b537SWarner Losh             HUF_DEltX4 DElt;
2265*0c16b537SWarner Losh 
2266*0c16b537SWarner Losh             MEM_writeLE16(&(DElt.sequence), symbol);
2267*0c16b537SWarner Losh             DElt.nbBits   = (BYTE)(nbBits);
2268*0c16b537SWarner Losh             DElt.length   = 1;
2269*0c16b537SWarner Losh             for (i = start; i < end; i++)
2270*0c16b537SWarner Losh                 DTable[i] = DElt;
2271*0c16b537SWarner Losh         }
2272*0c16b537SWarner Losh         rankVal[weight] += length;
2273*0c16b537SWarner Losh     }
2274*0c16b537SWarner Losh }
2275*0c16b537SWarner Losh 
2276*0c16b537SWarner Losh static size_t HUF_readDTableX4 (U32* DTable, const void* src, size_t srcSize)
2277*0c16b537SWarner Losh {
2278*0c16b537SWarner Losh     BYTE weightList[HUF_MAX_SYMBOL_VALUE + 1];
2279*0c16b537SWarner Losh     sortedSymbol_t sortedSymbol[HUF_MAX_SYMBOL_VALUE + 1];
2280*0c16b537SWarner Losh     U32 rankStats[HUF_ABSOLUTEMAX_TABLELOG + 1] = { 0 };
2281*0c16b537SWarner Losh     U32 rankStart0[HUF_ABSOLUTEMAX_TABLELOG + 2] = { 0 };
2282*0c16b537SWarner Losh     U32* const rankStart = rankStart0+1;
2283*0c16b537SWarner Losh     rankVal_t rankVal;
2284*0c16b537SWarner Losh     U32 tableLog, maxW, sizeOfSort, nbSymbols;
2285*0c16b537SWarner Losh     const U32 memLog = DTable[0];
2286*0c16b537SWarner Losh     size_t iSize;
2287*0c16b537SWarner Losh     void* dtPtr = DTable;
2288*0c16b537SWarner Losh     HUF_DEltX4* const dt = ((HUF_DEltX4*)dtPtr) + 1;
2289*0c16b537SWarner Losh 
2290*0c16b537SWarner Losh     HUF_STATIC_ASSERT(sizeof(HUF_DEltX4) == sizeof(U32));   /* if compilation fails here, assertion is false */
2291*0c16b537SWarner Losh     if (memLog > HUF_ABSOLUTEMAX_TABLELOG) return ERROR(tableLog_tooLarge);
2292*0c16b537SWarner Losh     //memset(weightList, 0, sizeof(weightList));   /* is not necessary, even though some analyzer complain ... */
2293*0c16b537SWarner Losh 
2294*0c16b537SWarner Losh     iSize = HUF_readStats(weightList, HUF_MAX_SYMBOL_VALUE + 1, rankStats, &nbSymbols, &tableLog, src, srcSize);
2295*0c16b537SWarner Losh     if (HUF_isError(iSize)) return iSize;
2296*0c16b537SWarner Losh 
2297*0c16b537SWarner Losh     /* check result */
2298*0c16b537SWarner Losh     if (tableLog > memLog) return ERROR(tableLog_tooLarge);   /* DTable can't fit code depth */
2299*0c16b537SWarner Losh 
2300*0c16b537SWarner Losh     /* find maxWeight */
2301*0c16b537SWarner Losh     for (maxW = tableLog; rankStats[maxW]==0; maxW--)
2302*0c16b537SWarner Losh         { if (!maxW) return ERROR(GENERIC); }  /* necessarily finds a solution before maxW==0 */
2303*0c16b537SWarner Losh 
2304*0c16b537SWarner Losh     /* Get start index of each weight */
2305*0c16b537SWarner Losh     {
2306*0c16b537SWarner Losh         U32 w, nextRankStart = 0;
2307*0c16b537SWarner Losh         for (w=1; w<=maxW; w++)
2308*0c16b537SWarner Losh         {
2309*0c16b537SWarner Losh             U32 current = nextRankStart;
2310*0c16b537SWarner Losh             nextRankStart += rankStats[w];
2311*0c16b537SWarner Losh             rankStart[w] = current;
2312*0c16b537SWarner Losh         }
2313*0c16b537SWarner Losh         rankStart[0] = nextRankStart;   /* put all 0w symbols at the end of sorted list*/
2314*0c16b537SWarner Losh         sizeOfSort = nextRankStart;
2315*0c16b537SWarner Losh     }
2316*0c16b537SWarner Losh 
2317*0c16b537SWarner Losh     /* sort symbols by weight */
2318*0c16b537SWarner Losh     {
2319*0c16b537SWarner Losh         U32 s;
2320*0c16b537SWarner Losh         for (s=0; s<nbSymbols; s++)
2321*0c16b537SWarner Losh         {
2322*0c16b537SWarner Losh             U32 w = weightList[s];
2323*0c16b537SWarner Losh             U32 r = rankStart[w]++;
2324*0c16b537SWarner Losh             sortedSymbol[r].symbol = (BYTE)s;
2325*0c16b537SWarner Losh             sortedSymbol[r].weight = (BYTE)w;
2326*0c16b537SWarner Losh         }
2327*0c16b537SWarner Losh         rankStart[0] = 0;   /* forget 0w symbols; this is beginning of weight(1) */
2328*0c16b537SWarner Losh     }
2329*0c16b537SWarner Losh 
2330*0c16b537SWarner Losh     /* Build rankVal */
2331*0c16b537SWarner Losh     {
2332*0c16b537SWarner Losh         const U32 minBits = tableLog+1 - maxW;
2333*0c16b537SWarner Losh         U32 nextRankVal = 0;
2334*0c16b537SWarner Losh         U32 w, consumed;
2335*0c16b537SWarner Losh         const int rescale = (memLog-tableLog) - 1;   /* tableLog <= memLog */
2336*0c16b537SWarner Losh         U32* rankVal0 = rankVal[0];
2337*0c16b537SWarner Losh         for (w=1; w<=maxW; w++)
2338*0c16b537SWarner Losh         {
2339*0c16b537SWarner Losh             U32 current = nextRankVal;
2340*0c16b537SWarner Losh             nextRankVal += rankStats[w] << (w+rescale);
2341*0c16b537SWarner Losh             rankVal0[w] = current;
2342*0c16b537SWarner Losh         }
2343*0c16b537SWarner Losh         for (consumed = minBits; consumed <= memLog - minBits; consumed++)
2344*0c16b537SWarner Losh         {
2345*0c16b537SWarner Losh             U32* rankValPtr = rankVal[consumed];
2346*0c16b537SWarner Losh             for (w = 1; w <= maxW; w++)
2347*0c16b537SWarner Losh             {
2348*0c16b537SWarner Losh                 rankValPtr[w] = rankVal0[w] >> consumed;
2349*0c16b537SWarner Losh             }
2350*0c16b537SWarner Losh         }
2351*0c16b537SWarner Losh     }
2352*0c16b537SWarner Losh 
2353*0c16b537SWarner Losh     HUF_fillDTableX4(dt, memLog,
2354*0c16b537SWarner Losh                    sortedSymbol, sizeOfSort,
2355*0c16b537SWarner Losh                    rankStart0, rankVal, maxW,
2356*0c16b537SWarner Losh                    tableLog+1);
2357*0c16b537SWarner Losh 
2358*0c16b537SWarner Losh     return iSize;
2359*0c16b537SWarner Losh }
2360*0c16b537SWarner Losh 
2361*0c16b537SWarner Losh 
2362*0c16b537SWarner Losh static U32 HUF_decodeSymbolX4(void* op, BIT_DStream_t* DStream, const HUF_DEltX4* dt, const U32 dtLog)
2363*0c16b537SWarner Losh {
2364*0c16b537SWarner Losh     const size_t val = BIT_lookBitsFast(DStream, dtLog);   /* note : dtLog >= 1 */
2365*0c16b537SWarner Losh     memcpy(op, dt+val, 2);
2366*0c16b537SWarner Losh     BIT_skipBits(DStream, dt[val].nbBits);
2367*0c16b537SWarner Losh     return dt[val].length;
2368*0c16b537SWarner Losh }
2369*0c16b537SWarner Losh 
2370*0c16b537SWarner Losh static U32 HUF_decodeLastSymbolX4(void* op, BIT_DStream_t* DStream, const HUF_DEltX4* dt, const U32 dtLog)
2371*0c16b537SWarner Losh {
2372*0c16b537SWarner Losh     const size_t val = BIT_lookBitsFast(DStream, dtLog);   /* note : dtLog >= 1 */
2373*0c16b537SWarner Losh     memcpy(op, dt+val, 1);
2374*0c16b537SWarner Losh     if (dt[val].length==1) BIT_skipBits(DStream, dt[val].nbBits);
2375*0c16b537SWarner Losh     else
2376*0c16b537SWarner Losh     {
2377*0c16b537SWarner Losh         if (DStream->bitsConsumed < (sizeof(DStream->bitContainer)*8))
2378*0c16b537SWarner Losh         {
2379*0c16b537SWarner Losh             BIT_skipBits(DStream, dt[val].nbBits);
2380*0c16b537SWarner Losh             if (DStream->bitsConsumed > (sizeof(DStream->bitContainer)*8))
2381*0c16b537SWarner 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 */
2382*0c16b537SWarner Losh         }
2383*0c16b537SWarner Losh     }
2384*0c16b537SWarner Losh     return 1;
2385*0c16b537SWarner Losh }
2386*0c16b537SWarner Losh 
2387*0c16b537SWarner Losh 
2388*0c16b537SWarner Losh #define HUF_DECODE_SYMBOLX4_0(ptr, DStreamPtr) \
2389*0c16b537SWarner Losh     ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
2390*0c16b537SWarner Losh 
2391*0c16b537SWarner Losh #define HUF_DECODE_SYMBOLX4_1(ptr, DStreamPtr) \
2392*0c16b537SWarner Losh     if (MEM_64bits() || (HUF_MAX_TABLELOG<=12)) \
2393*0c16b537SWarner Losh         ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
2394*0c16b537SWarner Losh 
2395*0c16b537SWarner Losh #define HUF_DECODE_SYMBOLX4_2(ptr, DStreamPtr) \
2396*0c16b537SWarner Losh     if (MEM_64bits()) \
2397*0c16b537SWarner Losh         ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
2398*0c16b537SWarner Losh 
2399*0c16b537SWarner Losh static inline size_t HUF_decodeStreamX4(BYTE* p, BIT_DStream_t* bitDPtr, BYTE* const pEnd, const HUF_DEltX4* const dt, const U32 dtLog)
2400*0c16b537SWarner Losh {
2401*0c16b537SWarner Losh     BYTE* const pStart = p;
2402*0c16b537SWarner Losh 
2403*0c16b537SWarner Losh     /* up to 8 symbols at a time */
2404*0c16b537SWarner Losh     while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p < pEnd-7))
2405*0c16b537SWarner Losh     {
2406*0c16b537SWarner Losh         HUF_DECODE_SYMBOLX4_2(p, bitDPtr);
2407*0c16b537SWarner Losh         HUF_DECODE_SYMBOLX4_1(p, bitDPtr);
2408*0c16b537SWarner Losh         HUF_DECODE_SYMBOLX4_2(p, bitDPtr);
2409*0c16b537SWarner Losh         HUF_DECODE_SYMBOLX4_0(p, bitDPtr);
2410*0c16b537SWarner Losh     }
2411*0c16b537SWarner Losh 
2412*0c16b537SWarner Losh     /* closer to the end */
2413*0c16b537SWarner Losh     while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p <= pEnd-2))
2414*0c16b537SWarner Losh         HUF_DECODE_SYMBOLX4_0(p, bitDPtr);
2415*0c16b537SWarner Losh 
2416*0c16b537SWarner Losh     while (p <= pEnd-2)
2417*0c16b537SWarner Losh         HUF_DECODE_SYMBOLX4_0(p, bitDPtr);   /* no need to reload : reached the end of DStream */
2418*0c16b537SWarner Losh 
2419*0c16b537SWarner Losh     if (p < pEnd)
2420*0c16b537SWarner Losh         p += HUF_decodeLastSymbolX4(p, bitDPtr, dt, dtLog);
2421*0c16b537SWarner Losh 
2422*0c16b537SWarner Losh     return p-pStart;
2423*0c16b537SWarner Losh }
2424*0c16b537SWarner Losh 
2425*0c16b537SWarner Losh static size_t HUF_decompress4X4_usingDTable(
2426*0c16b537SWarner Losh           void* dst,  size_t dstSize,
2427*0c16b537SWarner Losh     const void* cSrc, size_t cSrcSize,
2428*0c16b537SWarner Losh     const U32* DTable)
2429*0c16b537SWarner Losh {
2430*0c16b537SWarner Losh     if (cSrcSize < 10) return ERROR(corruption_detected);   /* strict minimum : jump table + 1 byte per stream */
2431*0c16b537SWarner Losh 
2432*0c16b537SWarner Losh     {
2433*0c16b537SWarner Losh         const BYTE* const istart = (const BYTE*) cSrc;
2434*0c16b537SWarner Losh         BYTE* const ostart = (BYTE*) dst;
2435*0c16b537SWarner Losh         BYTE* const oend = ostart + dstSize;
2436*0c16b537SWarner Losh         const void* const dtPtr = DTable;
2437*0c16b537SWarner Losh         const HUF_DEltX4* const dt = ((const HUF_DEltX4*)dtPtr) +1;
2438*0c16b537SWarner Losh         const U32 dtLog = DTable[0];
2439*0c16b537SWarner Losh         size_t errorCode;
2440*0c16b537SWarner Losh 
2441*0c16b537SWarner Losh         /* Init */
2442*0c16b537SWarner Losh         BIT_DStream_t bitD1;
2443*0c16b537SWarner Losh         BIT_DStream_t bitD2;
2444*0c16b537SWarner Losh         BIT_DStream_t bitD3;
2445*0c16b537SWarner Losh         BIT_DStream_t bitD4;
2446*0c16b537SWarner Losh         const size_t length1 = MEM_readLE16(istart);
2447*0c16b537SWarner Losh         const size_t length2 = MEM_readLE16(istart+2);
2448*0c16b537SWarner Losh         const size_t length3 = MEM_readLE16(istart+4);
2449*0c16b537SWarner Losh         size_t length4;
2450*0c16b537SWarner Losh         const BYTE* const istart1 = istart + 6;  /* jumpTable */
2451*0c16b537SWarner Losh         const BYTE* const istart2 = istart1 + length1;
2452*0c16b537SWarner Losh         const BYTE* const istart3 = istart2 + length2;
2453*0c16b537SWarner Losh         const BYTE* const istart4 = istart3 + length3;
2454*0c16b537SWarner Losh         const size_t segmentSize = (dstSize+3) / 4;
2455*0c16b537SWarner Losh         BYTE* const opStart2 = ostart + segmentSize;
2456*0c16b537SWarner Losh         BYTE* const opStart3 = opStart2 + segmentSize;
2457*0c16b537SWarner Losh         BYTE* const opStart4 = opStart3 + segmentSize;
2458*0c16b537SWarner Losh         BYTE* op1 = ostart;
2459*0c16b537SWarner Losh         BYTE* op2 = opStart2;
2460*0c16b537SWarner Losh         BYTE* op3 = opStart3;
2461*0c16b537SWarner Losh         BYTE* op4 = opStart4;
2462*0c16b537SWarner Losh         U32 endSignal;
2463*0c16b537SWarner Losh 
2464*0c16b537SWarner Losh         length4 = cSrcSize - (length1 + length2 + length3 + 6);
2465*0c16b537SWarner Losh         if (length4 > cSrcSize) return ERROR(corruption_detected);   /* overflow */
2466*0c16b537SWarner Losh         errorCode = BIT_initDStream(&bitD1, istart1, length1);
2467*0c16b537SWarner Losh         if (HUF_isError(errorCode)) return errorCode;
2468*0c16b537SWarner Losh         errorCode = BIT_initDStream(&bitD2, istart2, length2);
2469*0c16b537SWarner Losh         if (HUF_isError(errorCode)) return errorCode;
2470*0c16b537SWarner Losh         errorCode = BIT_initDStream(&bitD3, istart3, length3);
2471*0c16b537SWarner Losh         if (HUF_isError(errorCode)) return errorCode;
2472*0c16b537SWarner Losh         errorCode = BIT_initDStream(&bitD4, istart4, length4);
2473*0c16b537SWarner Losh         if (HUF_isError(errorCode)) return errorCode;
2474*0c16b537SWarner Losh 
2475*0c16b537SWarner Losh         /* 16-32 symbols per loop (4-8 symbols per stream) */
2476*0c16b537SWarner Losh         endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
2477*0c16b537SWarner Losh         for ( ; (endSignal==BIT_DStream_unfinished) && (op4<(oend-7)) ; )
2478*0c16b537SWarner Losh         {
2479*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX4_2(op1, &bitD1);
2480*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX4_2(op2, &bitD2);
2481*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX4_2(op3, &bitD3);
2482*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX4_2(op4, &bitD4);
2483*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX4_1(op1, &bitD1);
2484*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX4_1(op2, &bitD2);
2485*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX4_1(op3, &bitD3);
2486*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX4_1(op4, &bitD4);
2487*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX4_2(op1, &bitD1);
2488*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX4_2(op2, &bitD2);
2489*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX4_2(op3, &bitD3);
2490*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX4_2(op4, &bitD4);
2491*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX4_0(op1, &bitD1);
2492*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX4_0(op2, &bitD2);
2493*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX4_0(op3, &bitD3);
2494*0c16b537SWarner Losh             HUF_DECODE_SYMBOLX4_0(op4, &bitD4);
2495*0c16b537SWarner Losh 
2496*0c16b537SWarner Losh             endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
2497*0c16b537SWarner Losh         }
2498*0c16b537SWarner Losh 
2499*0c16b537SWarner Losh         /* check corruption */
2500*0c16b537SWarner Losh         if (op1 > opStart2) return ERROR(corruption_detected);
2501*0c16b537SWarner Losh         if (op2 > opStart3) return ERROR(corruption_detected);
2502*0c16b537SWarner Losh         if (op3 > opStart4) return ERROR(corruption_detected);
2503*0c16b537SWarner Losh         /* note : op4 supposed already verified within main loop */
2504*0c16b537SWarner Losh 
2505*0c16b537SWarner Losh         /* finish bitStreams one by one */
2506*0c16b537SWarner Losh         HUF_decodeStreamX4(op1, &bitD1, opStart2, dt, dtLog);
2507*0c16b537SWarner Losh         HUF_decodeStreamX4(op2, &bitD2, opStart3, dt, dtLog);
2508*0c16b537SWarner Losh         HUF_decodeStreamX4(op3, &bitD3, opStart4, dt, dtLog);
2509*0c16b537SWarner Losh         HUF_decodeStreamX4(op4, &bitD4, oend,     dt, dtLog);
2510*0c16b537SWarner Losh 
2511*0c16b537SWarner Losh         /* check */
2512*0c16b537SWarner Losh         endSignal = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4);
2513*0c16b537SWarner Losh         if (!endSignal) return ERROR(corruption_detected);
2514*0c16b537SWarner Losh 
2515*0c16b537SWarner Losh         /* decoded size */
2516*0c16b537SWarner Losh         return dstSize;
2517*0c16b537SWarner Losh     }
2518*0c16b537SWarner Losh }
2519*0c16b537SWarner Losh 
2520*0c16b537SWarner Losh 
2521*0c16b537SWarner Losh static size_t HUF_decompress4X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
2522*0c16b537SWarner Losh {
2523*0c16b537SWarner Losh     HUF_CREATE_STATIC_DTABLEX4(DTable, HUF_MAX_TABLELOG);
2524*0c16b537SWarner Losh     const BYTE* ip = (const BYTE*) cSrc;
2525*0c16b537SWarner Losh 
2526*0c16b537SWarner Losh     size_t hSize = HUF_readDTableX4 (DTable, cSrc, cSrcSize);
2527*0c16b537SWarner Losh     if (HUF_isError(hSize)) return hSize;
2528*0c16b537SWarner Losh     if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
2529*0c16b537SWarner Losh     ip += hSize;
2530*0c16b537SWarner Losh     cSrcSize -= hSize;
2531*0c16b537SWarner Losh 
2532*0c16b537SWarner Losh     return HUF_decompress4X4_usingDTable (dst, dstSize, ip, cSrcSize, DTable);
2533*0c16b537SWarner Losh }
2534*0c16b537SWarner Losh 
2535*0c16b537SWarner Losh 
2536*0c16b537SWarner Losh /**********************************/
2537*0c16b537SWarner Losh /* Generic decompression selector */
2538*0c16b537SWarner Losh /**********************************/
2539*0c16b537SWarner Losh 
2540*0c16b537SWarner Losh typedef struct { U32 tableTime; U32 decode256Time; } algo_time_t;
2541*0c16b537SWarner Losh static const algo_time_t algoTime[16 /* Quantization */][3 /* single, double, quad */] =
2542*0c16b537SWarner Losh {
2543*0c16b537SWarner Losh     /* single, double, quad */
2544*0c16b537SWarner Losh     {{0,0}, {1,1}, {2,2}},  /* Q==0 : impossible */
2545*0c16b537SWarner Losh     {{0,0}, {1,1}, {2,2}},  /* Q==1 : impossible */
2546*0c16b537SWarner Losh     {{  38,130}, {1313, 74}, {2151, 38}},   /* Q == 2 : 12-18% */
2547*0c16b537SWarner Losh     {{ 448,128}, {1353, 74}, {2238, 41}},   /* Q == 3 : 18-25% */
2548*0c16b537SWarner Losh     {{ 556,128}, {1353, 74}, {2238, 47}},   /* Q == 4 : 25-32% */
2549*0c16b537SWarner Losh     {{ 714,128}, {1418, 74}, {2436, 53}},   /* Q == 5 : 32-38% */
2550*0c16b537SWarner Losh     {{ 883,128}, {1437, 74}, {2464, 61}},   /* Q == 6 : 38-44% */
2551*0c16b537SWarner Losh     {{ 897,128}, {1515, 75}, {2622, 68}},   /* Q == 7 : 44-50% */
2552*0c16b537SWarner Losh     {{ 926,128}, {1613, 75}, {2730, 75}},   /* Q == 8 : 50-56% */
2553*0c16b537SWarner Losh     {{ 947,128}, {1729, 77}, {3359, 77}},   /* Q == 9 : 56-62% */
2554*0c16b537SWarner Losh     {{1107,128}, {2083, 81}, {4006, 84}},   /* Q ==10 : 62-69% */
2555*0c16b537SWarner Losh     {{1177,128}, {2379, 87}, {4785, 88}},   /* Q ==11 : 69-75% */
2556*0c16b537SWarner Losh     {{1242,128}, {2415, 93}, {5155, 84}},   /* Q ==12 : 75-81% */
2557*0c16b537SWarner Losh     {{1349,128}, {2644,106}, {5260,106}},   /* Q ==13 : 81-87% */
2558*0c16b537SWarner Losh     {{1455,128}, {2422,124}, {4174,124}},   /* Q ==14 : 87-93% */
2559*0c16b537SWarner Losh     {{ 722,128}, {1891,145}, {1936,146}},   /* Q ==15 : 93-99% */
2560*0c16b537SWarner Losh };
2561*0c16b537SWarner Losh 
2562*0c16b537SWarner Losh typedef size_t (*decompressionAlgo)(void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);
2563*0c16b537SWarner Losh 
2564*0c16b537SWarner Losh static size_t HUF_decompress (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
2565*0c16b537SWarner Losh {
2566*0c16b537SWarner Losh     static const decompressionAlgo decompress[3] = { HUF_decompress4X2, HUF_decompress4X4, NULL };
2567*0c16b537SWarner Losh     /* estimate decompression time */
2568*0c16b537SWarner Losh     U32 Q;
2569*0c16b537SWarner Losh     const U32 D256 = (U32)(dstSize >> 8);
2570*0c16b537SWarner Losh     U32 Dtime[3];
2571*0c16b537SWarner Losh     U32 algoNb = 0;
2572*0c16b537SWarner Losh     int n;
2573*0c16b537SWarner Losh 
2574*0c16b537SWarner Losh     /* validation checks */
2575*0c16b537SWarner Losh     if (dstSize == 0) return ERROR(dstSize_tooSmall);
2576*0c16b537SWarner Losh     if (cSrcSize > dstSize) return ERROR(corruption_detected);   /* invalid */
2577*0c16b537SWarner Losh     if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; }   /* not compressed */
2578*0c16b537SWarner Losh     if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; }   /* RLE */
2579*0c16b537SWarner Losh 
2580*0c16b537SWarner Losh     /* decoder timing evaluation */
2581*0c16b537SWarner Losh     Q = (U32)(cSrcSize * 16 / dstSize);   /* Q < 16 since dstSize > cSrcSize */
2582*0c16b537SWarner Losh     for (n=0; n<3; n++)
2583*0c16b537SWarner Losh         Dtime[n] = algoTime[Q][n].tableTime + (algoTime[Q][n].decode256Time * D256);
2584*0c16b537SWarner Losh 
2585*0c16b537SWarner Losh     Dtime[1] += Dtime[1] >> 4; Dtime[2] += Dtime[2] >> 3; /* advantage to algorithms using less memory, for cache eviction */
2586*0c16b537SWarner Losh 
2587*0c16b537SWarner Losh     if (Dtime[1] < Dtime[0]) algoNb = 1;
2588*0c16b537SWarner Losh 
2589*0c16b537SWarner Losh     return decompress[algoNb](dst, dstSize, cSrc, cSrcSize);
2590*0c16b537SWarner Losh 
2591*0c16b537SWarner Losh     //return HUF_decompress4X2(dst, dstSize, cSrc, cSrcSize);   /* multi-streams single-symbol decoding */
2592*0c16b537SWarner Losh     //return HUF_decompress4X4(dst, dstSize, cSrc, cSrcSize);   /* multi-streams double-symbols decoding */
2593*0c16b537SWarner Losh     //return HUF_decompress4X6(dst, dstSize, cSrc, cSrcSize);   /* multi-streams quad-symbols decoding */
2594*0c16b537SWarner Losh }
2595*0c16b537SWarner Losh 
2596*0c16b537SWarner Losh 
2597*0c16b537SWarner Losh 
2598*0c16b537SWarner Losh #endif   /* ZSTD_CCOMMON_H_MODULE */
2599*0c16b537SWarner Losh 
2600*0c16b537SWarner Losh 
2601*0c16b537SWarner Losh /*
2602*0c16b537SWarner Losh     zstd - decompression module fo v0.4 legacy format
2603*0c16b537SWarner Losh     Copyright (C) 2015-2016, Yann Collet.
2604*0c16b537SWarner Losh 
2605*0c16b537SWarner Losh     BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
2606*0c16b537SWarner Losh 
2607*0c16b537SWarner Losh     Redistribution and use in source and binary forms, with or without
2608*0c16b537SWarner Losh     modification, are permitted provided that the following conditions are
2609*0c16b537SWarner Losh     met:
2610*0c16b537SWarner Losh     * Redistributions of source code must retain the above copyright
2611*0c16b537SWarner Losh     notice, this list of conditions and the following disclaimer.
2612*0c16b537SWarner Losh     * Redistributions in binary form must reproduce the above
2613*0c16b537SWarner Losh     copyright notice, this list of conditions and the following disclaimer
2614*0c16b537SWarner Losh     in the documentation and/or other materials provided with the
2615*0c16b537SWarner Losh     distribution.
2616*0c16b537SWarner Losh     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2617*0c16b537SWarner Losh     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2618*0c16b537SWarner Losh     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2619*0c16b537SWarner Losh     A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2620*0c16b537SWarner Losh     OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2621*0c16b537SWarner Losh     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2622*0c16b537SWarner Losh     LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2623*0c16b537SWarner Losh     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2624*0c16b537SWarner Losh     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2625*0c16b537SWarner Losh     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2626*0c16b537SWarner Losh     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2627*0c16b537SWarner Losh 
2628*0c16b537SWarner Losh     You can contact the author at :
2629*0c16b537SWarner Losh     - zstd source repository : https://github.com/Cyan4973/zstd
2630*0c16b537SWarner Losh     - ztsd public forum : https://groups.google.com/forum/#!forum/lz4c
2631*0c16b537SWarner Losh */
2632*0c16b537SWarner Losh 
2633*0c16b537SWarner Losh /* ***************************************************************
2634*0c16b537SWarner Losh *  Tuning parameters
2635*0c16b537SWarner Losh *****************************************************************/
2636*0c16b537SWarner Losh /*!
2637*0c16b537SWarner Losh  * HEAPMODE :
2638*0c16b537SWarner Losh  * Select how default decompression function ZSTD_decompress() will allocate memory,
2639*0c16b537SWarner Losh  * in memory stack (0), or in memory heap (1, requires malloc())
2640*0c16b537SWarner Losh  */
2641*0c16b537SWarner Losh #ifndef ZSTD_HEAPMODE
2642*0c16b537SWarner Losh #  define ZSTD_HEAPMODE 1
2643*0c16b537SWarner Losh #endif
2644*0c16b537SWarner Losh 
2645*0c16b537SWarner Losh 
2646*0c16b537SWarner Losh /* *******************************************************
2647*0c16b537SWarner Losh *  Includes
2648*0c16b537SWarner Losh *********************************************************/
2649*0c16b537SWarner Losh #include <stdlib.h>      /* calloc */
2650*0c16b537SWarner Losh #include <string.h>      /* memcpy, memmove */
2651*0c16b537SWarner Losh #include <stdio.h>       /* debug : printf */
2652*0c16b537SWarner Losh 
2653*0c16b537SWarner Losh 
2654*0c16b537SWarner Losh /* *******************************************************
2655*0c16b537SWarner Losh *  Compiler specifics
2656*0c16b537SWarner Losh *********************************************************/
2657*0c16b537SWarner Losh #ifdef _MSC_VER    /* Visual Studio */
2658*0c16b537SWarner Losh #  include <intrin.h>                    /* For Visual 2005 */
2659*0c16b537SWarner Losh #  pragma warning(disable : 4127)        /* disable: C4127: conditional expression is constant */
2660*0c16b537SWarner Losh #  pragma warning(disable : 4324)        /* disable: C4324: padded structure */
2661*0c16b537SWarner Losh #endif
2662*0c16b537SWarner Losh 
2663*0c16b537SWarner Losh 
2664*0c16b537SWarner Losh /* *************************************
2665*0c16b537SWarner Losh *  Local types
2666*0c16b537SWarner Losh ***************************************/
2667*0c16b537SWarner Losh typedef struct
2668*0c16b537SWarner Losh {
2669*0c16b537SWarner Losh     blockType_t blockType;
2670*0c16b537SWarner Losh     U32 origSize;
2671*0c16b537SWarner Losh } blockProperties_t;
2672*0c16b537SWarner Losh 
2673*0c16b537SWarner Losh 
2674*0c16b537SWarner Losh /* *******************************************************
2675*0c16b537SWarner Losh *  Memory operations
2676*0c16b537SWarner Losh **********************************************************/
2677*0c16b537SWarner Losh static void ZSTD_copy4(void* dst, const void* src) { memcpy(dst, src, 4); }
2678*0c16b537SWarner Losh 
2679*0c16b537SWarner Losh 
2680*0c16b537SWarner Losh /* *************************************
2681*0c16b537SWarner Losh *  Error Management
2682*0c16b537SWarner Losh ***************************************/
2683*0c16b537SWarner Losh 
2684*0c16b537SWarner Losh /*! ZSTD_isError
2685*0c16b537SWarner Losh *   tells if a return value is an error code */
2686*0c16b537SWarner Losh static unsigned ZSTD_isError(size_t code) { return ERR_isError(code); }
2687*0c16b537SWarner Losh 
2688*0c16b537SWarner Losh 
2689*0c16b537SWarner Losh /* *************************************************************
2690*0c16b537SWarner Losh *   Context management
2691*0c16b537SWarner Losh ***************************************************************/
2692*0c16b537SWarner Losh typedef enum { ZSTDds_getFrameHeaderSize, ZSTDds_decodeFrameHeader,
2693*0c16b537SWarner Losh                ZSTDds_decodeBlockHeader, ZSTDds_decompressBlock } ZSTD_dStage;
2694*0c16b537SWarner Losh 
2695*0c16b537SWarner Losh struct ZSTDv04_Dctx_s
2696*0c16b537SWarner Losh {
2697*0c16b537SWarner Losh     U32 LLTable[FSE_DTABLE_SIZE_U32(LLFSELog)];
2698*0c16b537SWarner Losh     U32 OffTable[FSE_DTABLE_SIZE_U32(OffFSELog)];
2699*0c16b537SWarner Losh     U32 MLTable[FSE_DTABLE_SIZE_U32(MLFSELog)];
2700*0c16b537SWarner Losh     const void* previousDstEnd;
2701*0c16b537SWarner Losh     const void* base;
2702*0c16b537SWarner Losh     const void* vBase;
2703*0c16b537SWarner Losh     const void* dictEnd;
2704*0c16b537SWarner Losh     size_t expected;
2705*0c16b537SWarner Losh     size_t headerSize;
2706*0c16b537SWarner Losh     ZSTD_parameters params;
2707*0c16b537SWarner Losh     blockType_t bType;
2708*0c16b537SWarner Losh     ZSTD_dStage stage;
2709*0c16b537SWarner Losh     const BYTE* litPtr;
2710*0c16b537SWarner Losh     size_t litSize;
2711*0c16b537SWarner Losh     BYTE litBuffer[BLOCKSIZE + 8 /* margin for wildcopy */];
2712*0c16b537SWarner Losh     BYTE headerBuffer[ZSTD_frameHeaderSize_max];
2713*0c16b537SWarner Losh };  /* typedef'd to ZSTD_DCtx within "zstd_static.h" */
2714*0c16b537SWarner Losh 
2715*0c16b537SWarner Losh static size_t ZSTD_resetDCtx(ZSTD_DCtx* dctx)
2716*0c16b537SWarner Losh {
2717*0c16b537SWarner Losh     dctx->expected = ZSTD_frameHeaderSize_min;
2718*0c16b537SWarner Losh     dctx->stage = ZSTDds_getFrameHeaderSize;
2719*0c16b537SWarner Losh     dctx->previousDstEnd = NULL;
2720*0c16b537SWarner Losh     dctx->base = NULL;
2721*0c16b537SWarner Losh     dctx->vBase = NULL;
2722*0c16b537SWarner Losh     dctx->dictEnd = NULL;
2723*0c16b537SWarner Losh     return 0;
2724*0c16b537SWarner Losh }
2725*0c16b537SWarner Losh 
2726*0c16b537SWarner Losh static ZSTD_DCtx* ZSTD_createDCtx(void)
2727*0c16b537SWarner Losh {
2728*0c16b537SWarner Losh     ZSTD_DCtx* dctx = (ZSTD_DCtx*)malloc(sizeof(ZSTD_DCtx));
2729*0c16b537SWarner Losh     if (dctx==NULL) return NULL;
2730*0c16b537SWarner Losh     ZSTD_resetDCtx(dctx);
2731*0c16b537SWarner Losh     return dctx;
2732*0c16b537SWarner Losh }
2733*0c16b537SWarner Losh 
2734*0c16b537SWarner Losh static size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx)
2735*0c16b537SWarner Losh {
2736*0c16b537SWarner Losh     free(dctx);
2737*0c16b537SWarner Losh     return 0;
2738*0c16b537SWarner Losh }
2739*0c16b537SWarner Losh 
2740*0c16b537SWarner Losh 
2741*0c16b537SWarner Losh /* *************************************************************
2742*0c16b537SWarner Losh *   Decompression section
2743*0c16b537SWarner Losh ***************************************************************/
2744*0c16b537SWarner Losh /** ZSTD_decodeFrameHeader_Part1
2745*0c16b537SWarner Losh *   decode the 1st part of the Frame Header, which tells Frame Header size.
2746*0c16b537SWarner Losh *   srcSize must be == ZSTD_frameHeaderSize_min
2747*0c16b537SWarner Losh *   @return : the full size of the Frame Header */
2748*0c16b537SWarner Losh static size_t ZSTD_decodeFrameHeader_Part1(ZSTD_DCtx* zc, const void* src, size_t srcSize)
2749*0c16b537SWarner Losh {
2750*0c16b537SWarner Losh     U32 magicNumber;
2751*0c16b537SWarner Losh     if (srcSize != ZSTD_frameHeaderSize_min) return ERROR(srcSize_wrong);
2752*0c16b537SWarner Losh     magicNumber = MEM_readLE32(src);
2753*0c16b537SWarner Losh     if (magicNumber != ZSTD_MAGICNUMBER) return ERROR(prefix_unknown);
2754*0c16b537SWarner Losh     zc->headerSize = ZSTD_frameHeaderSize_min;
2755*0c16b537SWarner Losh     return zc->headerSize;
2756*0c16b537SWarner Losh }
2757*0c16b537SWarner Losh 
2758*0c16b537SWarner Losh 
2759*0c16b537SWarner Losh static size_t ZSTD_getFrameParams(ZSTD_parameters* params, const void* src, size_t srcSize)
2760*0c16b537SWarner Losh {
2761*0c16b537SWarner Losh     U32 magicNumber;
2762*0c16b537SWarner Losh     if (srcSize < ZSTD_frameHeaderSize_min) return ZSTD_frameHeaderSize_max;
2763*0c16b537SWarner Losh     magicNumber = MEM_readLE32(src);
2764*0c16b537SWarner Losh     if (magicNumber != ZSTD_MAGICNUMBER) return ERROR(prefix_unknown);
2765*0c16b537SWarner Losh     memset(params, 0, sizeof(*params));
2766*0c16b537SWarner Losh     params->windowLog = (((const BYTE*)src)[4] & 15) + ZSTD_WINDOWLOG_ABSOLUTEMIN;
2767*0c16b537SWarner Losh     if ((((const BYTE*)src)[4] >> 4) != 0) return ERROR(frameParameter_unsupported);   /* reserved bits */
2768*0c16b537SWarner Losh     return 0;
2769*0c16b537SWarner Losh }
2770*0c16b537SWarner Losh 
2771*0c16b537SWarner Losh /** ZSTD_decodeFrameHeader_Part2
2772*0c16b537SWarner Losh *   decode the full Frame Header
2773*0c16b537SWarner Losh *   srcSize must be the size provided by ZSTD_decodeFrameHeader_Part1
2774*0c16b537SWarner Losh *   @return : 0, or an error code, which can be tested using ZSTD_isError() */
2775*0c16b537SWarner Losh static size_t ZSTD_decodeFrameHeader_Part2(ZSTD_DCtx* zc, const void* src, size_t srcSize)
2776*0c16b537SWarner Losh {
2777*0c16b537SWarner Losh     size_t result;
2778*0c16b537SWarner Losh     if (srcSize != zc->headerSize) return ERROR(srcSize_wrong);
2779*0c16b537SWarner Losh     result = ZSTD_getFrameParams(&(zc->params), src, srcSize);
2780*0c16b537SWarner Losh     if ((MEM_32bits()) && (zc->params.windowLog > 25)) return ERROR(frameParameter_unsupported);
2781*0c16b537SWarner Losh     return result;
2782*0c16b537SWarner Losh }
2783*0c16b537SWarner Losh 
2784*0c16b537SWarner Losh 
2785*0c16b537SWarner Losh static size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr)
2786*0c16b537SWarner Losh {
2787*0c16b537SWarner Losh     const BYTE* const in = (const BYTE* const)src;
2788*0c16b537SWarner Losh     BYTE headerFlags;
2789*0c16b537SWarner Losh     U32 cSize;
2790*0c16b537SWarner Losh 
2791*0c16b537SWarner Losh     if (srcSize < 3) return ERROR(srcSize_wrong);
2792*0c16b537SWarner Losh 
2793*0c16b537SWarner Losh     headerFlags = *in;
2794*0c16b537SWarner Losh     cSize = in[2] + (in[1]<<8) + ((in[0] & 7)<<16);
2795*0c16b537SWarner Losh 
2796*0c16b537SWarner Losh     bpPtr->blockType = (blockType_t)(headerFlags >> 6);
2797*0c16b537SWarner Losh     bpPtr->origSize = (bpPtr->blockType == bt_rle) ? cSize : 0;
2798*0c16b537SWarner Losh 
2799*0c16b537SWarner Losh     if (bpPtr->blockType == bt_end) return 0;
2800*0c16b537SWarner Losh     if (bpPtr->blockType == bt_rle) return 1;
2801*0c16b537SWarner Losh     return cSize;
2802*0c16b537SWarner Losh }
2803*0c16b537SWarner Losh 
2804*0c16b537SWarner Losh static size_t ZSTD_copyRawBlock(void* dst, size_t maxDstSize, const void* src, size_t srcSize)
2805*0c16b537SWarner Losh {
2806*0c16b537SWarner Losh     if (srcSize > maxDstSize) return ERROR(dstSize_tooSmall);
2807*0c16b537SWarner Losh     memcpy(dst, src, srcSize);
2808*0c16b537SWarner Losh     return srcSize;
2809*0c16b537SWarner Losh }
2810*0c16b537SWarner Losh 
2811*0c16b537SWarner Losh 
2812*0c16b537SWarner Losh /** ZSTD_decompressLiterals
2813*0c16b537SWarner Losh     @return : nb of bytes read from src, or an error code*/
2814*0c16b537SWarner Losh static size_t ZSTD_decompressLiterals(void* dst, size_t* maxDstSizePtr,
2815*0c16b537SWarner Losh                                 const void* src, size_t srcSize)
2816*0c16b537SWarner Losh {
2817*0c16b537SWarner Losh     const BYTE* ip = (const BYTE*)src;
2818*0c16b537SWarner Losh 
2819*0c16b537SWarner Losh     const size_t litSize = (MEM_readLE32(src) & 0x1FFFFF) >> 2;   /* no buffer issue : srcSize >= MIN_CBLOCK_SIZE */
2820*0c16b537SWarner Losh     const size_t litCSize = (MEM_readLE32(ip+2) & 0xFFFFFF) >> 5;   /* no buffer issue : srcSize >= MIN_CBLOCK_SIZE */
2821*0c16b537SWarner Losh 
2822*0c16b537SWarner Losh     if (litSize > *maxDstSizePtr) return ERROR(corruption_detected);
2823*0c16b537SWarner Losh     if (litCSize + 5 > srcSize) return ERROR(corruption_detected);
2824*0c16b537SWarner Losh 
2825*0c16b537SWarner Losh     if (HUF_isError(HUF_decompress(dst, litSize, ip+5, litCSize))) return ERROR(corruption_detected);
2826*0c16b537SWarner Losh 
2827*0c16b537SWarner Losh     *maxDstSizePtr = litSize;
2828*0c16b537SWarner Losh     return litCSize + 5;
2829*0c16b537SWarner Losh }
2830*0c16b537SWarner Losh 
2831*0c16b537SWarner Losh 
2832*0c16b537SWarner Losh /** ZSTD_decodeLiteralsBlock
2833*0c16b537SWarner Losh     @return : nb of bytes read from src (< srcSize ) */
2834*0c16b537SWarner Losh static size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
2835*0c16b537SWarner Losh                           const void* src, size_t srcSize)   /* note : srcSize < BLOCKSIZE */
2836*0c16b537SWarner Losh {
2837*0c16b537SWarner Losh     const BYTE* const istart = (const BYTE*) src;
2838*0c16b537SWarner Losh 
2839*0c16b537SWarner Losh     /* any compressed block with literals segment must be at least this size */
2840*0c16b537SWarner Losh     if (srcSize < MIN_CBLOCK_SIZE) return ERROR(corruption_detected);
2841*0c16b537SWarner Losh 
2842*0c16b537SWarner Losh     switch(*istart & 3)
2843*0c16b537SWarner Losh     {
2844*0c16b537SWarner Losh     /* compressed */
2845*0c16b537SWarner Losh     case 0:
2846*0c16b537SWarner Losh         {
2847*0c16b537SWarner Losh             size_t litSize = BLOCKSIZE;
2848*0c16b537SWarner Losh             const size_t readSize = ZSTD_decompressLiterals(dctx->litBuffer, &litSize, src, srcSize);
2849*0c16b537SWarner Losh             dctx->litPtr = dctx->litBuffer;
2850*0c16b537SWarner Losh             dctx->litSize = litSize;
2851*0c16b537SWarner Losh             memset(dctx->litBuffer + dctx->litSize, 0, 8);
2852*0c16b537SWarner Losh             return readSize;   /* works if it's an error too */
2853*0c16b537SWarner Losh         }
2854*0c16b537SWarner Losh     case IS_RAW:
2855*0c16b537SWarner Losh         {
2856*0c16b537SWarner Losh             const size_t litSize = (MEM_readLE32(istart) & 0xFFFFFF) >> 2;   /* no buffer issue : srcSize >= MIN_CBLOCK_SIZE */
2857*0c16b537SWarner Losh             if (litSize > srcSize-11)   /* risk of reading too far with wildcopy */
2858*0c16b537SWarner Losh             {
2859*0c16b537SWarner Losh                 if (litSize > srcSize-3) return ERROR(corruption_detected);
2860*0c16b537SWarner Losh                 memcpy(dctx->litBuffer, istart, litSize);
2861*0c16b537SWarner Losh                 dctx->litPtr = dctx->litBuffer;
2862*0c16b537SWarner Losh                 dctx->litSize = litSize;
2863*0c16b537SWarner Losh                 memset(dctx->litBuffer + dctx->litSize, 0, 8);
2864*0c16b537SWarner Losh                 return litSize+3;
2865*0c16b537SWarner Losh             }
2866*0c16b537SWarner Losh             /* direct reference into compressed stream */
2867*0c16b537SWarner Losh             dctx->litPtr = istart+3;
2868*0c16b537SWarner Losh             dctx->litSize = litSize;
2869*0c16b537SWarner Losh             return litSize+3;        }
2870*0c16b537SWarner Losh     case IS_RLE:
2871*0c16b537SWarner Losh         {
2872*0c16b537SWarner Losh             const size_t litSize = (MEM_readLE32(istart) & 0xFFFFFF) >> 2;   /* no buffer issue : srcSize >= MIN_CBLOCK_SIZE */
2873*0c16b537SWarner Losh             if (litSize > BLOCKSIZE) return ERROR(corruption_detected);
2874*0c16b537SWarner Losh             memset(dctx->litBuffer, istart[3], litSize + 8);
2875*0c16b537SWarner Losh             dctx->litPtr = dctx->litBuffer;
2876*0c16b537SWarner Losh             dctx->litSize = litSize;
2877*0c16b537SWarner Losh             return 4;
2878*0c16b537SWarner Losh         }
2879*0c16b537SWarner Losh     default:
2880*0c16b537SWarner Losh         return ERROR(corruption_detected);   /* forbidden nominal case */
2881*0c16b537SWarner Losh     }
2882*0c16b537SWarner Losh }
2883*0c16b537SWarner Losh 
2884*0c16b537SWarner Losh 
2885*0c16b537SWarner Losh static size_t ZSTD_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* dumpsLengthPtr,
2886*0c16b537SWarner Losh                          FSE_DTable* DTableLL, FSE_DTable* DTableML, FSE_DTable* DTableOffb,
2887*0c16b537SWarner Losh                          const void* src, size_t srcSize)
2888*0c16b537SWarner Losh {
2889*0c16b537SWarner Losh     const BYTE* const istart = (const BYTE* const)src;
2890*0c16b537SWarner Losh     const BYTE* ip = istart;
2891*0c16b537SWarner Losh     const BYTE* const iend = istart + srcSize;
2892*0c16b537SWarner Losh     U32 LLtype, Offtype, MLtype;
2893*0c16b537SWarner Losh     U32 LLlog, Offlog, MLlog;
2894*0c16b537SWarner Losh     size_t dumpsLength;
2895*0c16b537SWarner Losh 
2896*0c16b537SWarner Losh     /* check */
2897*0c16b537SWarner Losh     if (srcSize < 5) return ERROR(srcSize_wrong);
2898*0c16b537SWarner Losh 
2899*0c16b537SWarner Losh     /* SeqHead */
2900*0c16b537SWarner Losh     *nbSeq = MEM_readLE16(ip); ip+=2;
2901*0c16b537SWarner Losh     LLtype  = *ip >> 6;
2902*0c16b537SWarner Losh     Offtype = (*ip >> 4) & 3;
2903*0c16b537SWarner Losh     MLtype  = (*ip >> 2) & 3;
2904*0c16b537SWarner Losh     if (*ip & 2)
2905*0c16b537SWarner Losh     {
2906*0c16b537SWarner Losh         dumpsLength  = ip[2];
2907*0c16b537SWarner Losh         dumpsLength += ip[1] << 8;
2908*0c16b537SWarner Losh         ip += 3;
2909*0c16b537SWarner Losh     }
2910*0c16b537SWarner Losh     else
2911*0c16b537SWarner Losh     {
2912*0c16b537SWarner Losh         dumpsLength  = ip[1];
2913*0c16b537SWarner Losh         dumpsLength += (ip[0] & 1) << 8;
2914*0c16b537SWarner Losh         ip += 2;
2915*0c16b537SWarner Losh     }
2916*0c16b537SWarner Losh     *dumpsPtr = ip;
2917*0c16b537SWarner Losh     ip += dumpsLength;
2918*0c16b537SWarner Losh     *dumpsLengthPtr = dumpsLength;
2919*0c16b537SWarner Losh 
2920*0c16b537SWarner Losh     /* check */
2921*0c16b537SWarner Losh     if (ip > iend-3) return ERROR(srcSize_wrong); /* min : all 3 are "raw", hence no header, but at least xxLog bits per type */
2922*0c16b537SWarner Losh 
2923*0c16b537SWarner Losh     /* sequences */
2924*0c16b537SWarner Losh     {
2925*0c16b537SWarner Losh         S16 norm[MaxML+1];    /* assumption : MaxML >= MaxLL >= MaxOff */
2926*0c16b537SWarner Losh         size_t headerSize;
2927*0c16b537SWarner Losh 
2928*0c16b537SWarner Losh         /* Build DTables */
2929*0c16b537SWarner Losh         switch(LLtype)
2930*0c16b537SWarner Losh         {
2931*0c16b537SWarner Losh         case bt_rle :
2932*0c16b537SWarner Losh             LLlog = 0;
2933*0c16b537SWarner Losh             FSE_buildDTable_rle(DTableLL, *ip++); break;
2934*0c16b537SWarner Losh         case bt_raw :
2935*0c16b537SWarner Losh             LLlog = LLbits;
2936*0c16b537SWarner Losh             FSE_buildDTable_raw(DTableLL, LLbits); break;
2937*0c16b537SWarner Losh         default :
2938*0c16b537SWarner Losh             {   U32 max = MaxLL;
2939*0c16b537SWarner Losh                 headerSize = FSE_readNCount(norm, &max, &LLlog, ip, iend-ip);
2940*0c16b537SWarner Losh                 if (FSE_isError(headerSize)) return ERROR(GENERIC);
2941*0c16b537SWarner Losh                 if (LLlog > LLFSELog) return ERROR(corruption_detected);
2942*0c16b537SWarner Losh                 ip += headerSize;
2943*0c16b537SWarner Losh                 FSE_buildDTable(DTableLL, norm, max, LLlog);
2944*0c16b537SWarner Losh         }   }
2945*0c16b537SWarner Losh 
2946*0c16b537SWarner Losh         switch(Offtype)
2947*0c16b537SWarner Losh         {
2948*0c16b537SWarner Losh         case bt_rle :
2949*0c16b537SWarner Losh             Offlog = 0;
2950*0c16b537SWarner Losh             if (ip > iend-2) return ERROR(srcSize_wrong);   /* min : "raw", hence no header, but at least xxLog bits */
2951*0c16b537SWarner Losh             FSE_buildDTable_rle(DTableOffb, *ip++ & MaxOff); /* if *ip > MaxOff, data is corrupted */
2952*0c16b537SWarner Losh             break;
2953*0c16b537SWarner Losh         case bt_raw :
2954*0c16b537SWarner Losh             Offlog = Offbits;
2955*0c16b537SWarner Losh             FSE_buildDTable_raw(DTableOffb, Offbits); break;
2956*0c16b537SWarner Losh         default :
2957*0c16b537SWarner Losh             {   U32 max = MaxOff;
2958*0c16b537SWarner Losh                 headerSize = FSE_readNCount(norm, &max, &Offlog, ip, iend-ip);
2959*0c16b537SWarner Losh                 if (FSE_isError(headerSize)) return ERROR(GENERIC);
2960*0c16b537SWarner Losh                 if (Offlog > OffFSELog) return ERROR(corruption_detected);
2961*0c16b537SWarner Losh                 ip += headerSize;
2962*0c16b537SWarner Losh                 FSE_buildDTable(DTableOffb, norm, max, Offlog);
2963*0c16b537SWarner Losh         }   }
2964*0c16b537SWarner Losh 
2965*0c16b537SWarner Losh         switch(MLtype)
2966*0c16b537SWarner Losh         {
2967*0c16b537SWarner Losh         case bt_rle :
2968*0c16b537SWarner Losh             MLlog = 0;
2969*0c16b537SWarner Losh             if (ip > iend-2) return ERROR(srcSize_wrong); /* min : "raw", hence no header, but at least xxLog bits */
2970*0c16b537SWarner Losh             FSE_buildDTable_rle(DTableML, *ip++); break;
2971*0c16b537SWarner Losh         case bt_raw :
2972*0c16b537SWarner Losh             MLlog = MLbits;
2973*0c16b537SWarner Losh             FSE_buildDTable_raw(DTableML, MLbits); break;
2974*0c16b537SWarner Losh         default :
2975*0c16b537SWarner Losh             {   U32 max = MaxML;
2976*0c16b537SWarner Losh                 headerSize = FSE_readNCount(norm, &max, &MLlog, ip, iend-ip);
2977*0c16b537SWarner Losh                 if (FSE_isError(headerSize)) return ERROR(GENERIC);
2978*0c16b537SWarner Losh                 if (MLlog > MLFSELog) return ERROR(corruption_detected);
2979*0c16b537SWarner Losh                 ip += headerSize;
2980*0c16b537SWarner Losh                 FSE_buildDTable(DTableML, norm, max, MLlog);
2981*0c16b537SWarner Losh     }   }   }
2982*0c16b537SWarner Losh 
2983*0c16b537SWarner Losh     return ip-istart;
2984*0c16b537SWarner Losh }
2985*0c16b537SWarner Losh 
2986*0c16b537SWarner Losh 
2987*0c16b537SWarner Losh typedef struct {
2988*0c16b537SWarner Losh     size_t litLength;
2989*0c16b537SWarner Losh     size_t offset;
2990*0c16b537SWarner Losh     size_t matchLength;
2991*0c16b537SWarner Losh } seq_t;
2992*0c16b537SWarner Losh 
2993*0c16b537SWarner Losh typedef struct {
2994*0c16b537SWarner Losh     BIT_DStream_t DStream;
2995*0c16b537SWarner Losh     FSE_DState_t stateLL;
2996*0c16b537SWarner Losh     FSE_DState_t stateOffb;
2997*0c16b537SWarner Losh     FSE_DState_t stateML;
2998*0c16b537SWarner Losh     size_t prevOffset;
2999*0c16b537SWarner Losh     const BYTE* dumps;
3000*0c16b537SWarner Losh     const BYTE* dumpsEnd;
3001*0c16b537SWarner Losh } seqState_t;
3002*0c16b537SWarner Losh 
3003*0c16b537SWarner Losh 
3004*0c16b537SWarner Losh static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState)
3005*0c16b537SWarner Losh {
3006*0c16b537SWarner Losh     size_t litLength;
3007*0c16b537SWarner Losh     size_t prevOffset;
3008*0c16b537SWarner Losh     size_t offset;
3009*0c16b537SWarner Losh     size_t matchLength;
3010*0c16b537SWarner Losh     const BYTE* dumps = seqState->dumps;
3011*0c16b537SWarner Losh     const BYTE* const de = seqState->dumpsEnd;
3012*0c16b537SWarner Losh 
3013*0c16b537SWarner Losh     /* Literal length */
3014*0c16b537SWarner Losh     litLength = FSE_decodeSymbol(&(seqState->stateLL), &(seqState->DStream));
3015*0c16b537SWarner Losh     prevOffset = litLength ? seq->offset : seqState->prevOffset;
3016*0c16b537SWarner Losh     if (litLength == MaxLL) {
3017*0c16b537SWarner Losh         U32 add = *dumps++;
3018*0c16b537SWarner Losh         if (add < 255) litLength += add;
3019*0c16b537SWarner Losh         else {
3020*0c16b537SWarner Losh             litLength = dumps[0] + (dumps[1]<<8) + (dumps[2]<<16);
3021*0c16b537SWarner Losh             dumps += 3;
3022*0c16b537SWarner Losh         }
3023*0c16b537SWarner Losh         if (dumps > de) { litLength = MaxLL+255; }  /* late correction, to avoid using uninitialized memory */
3024*0c16b537SWarner Losh         if (dumps >= de) { dumps = de-1; }  /* late correction, to avoid read overflow (data is now corrupted anyway) */
3025*0c16b537SWarner Losh     }
3026*0c16b537SWarner Losh 
3027*0c16b537SWarner Losh     /* Offset */
3028*0c16b537SWarner Losh     {   static const U32 offsetPrefix[MaxOff+1] = {
3029*0c16b537SWarner Losh                 1 /*fake*/, 1, 2, 4, 8, 16, 32, 64, 128, 256,
3030*0c16b537SWarner Losh                 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144,
3031*0c16b537SWarner Losh                 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, /*fake*/ 1, 1, 1, 1, 1 };
3032*0c16b537SWarner Losh         U32 offsetCode, nbBits;
3033*0c16b537SWarner Losh         offsetCode = FSE_decodeSymbol(&(seqState->stateOffb), &(seqState->DStream));   /* <= maxOff, by table construction */
3034*0c16b537SWarner Losh         if (MEM_32bits()) BIT_reloadDStream(&(seqState->DStream));
3035*0c16b537SWarner Losh         nbBits = offsetCode - 1;
3036*0c16b537SWarner Losh         if (offsetCode==0) nbBits = 0;   /* cmove */
3037*0c16b537SWarner Losh         offset = offsetPrefix[offsetCode] + BIT_readBits(&(seqState->DStream), nbBits);
3038*0c16b537SWarner Losh         if (MEM_32bits()) BIT_reloadDStream(&(seqState->DStream));
3039*0c16b537SWarner Losh         if (offsetCode==0) offset = prevOffset;   /* cmove */
3040*0c16b537SWarner Losh         if (offsetCode | !litLength) seqState->prevOffset = seq->offset;   /* cmove */
3041*0c16b537SWarner Losh     }
3042*0c16b537SWarner Losh 
3043*0c16b537SWarner Losh     /* MatchLength */
3044*0c16b537SWarner Losh     matchLength = FSE_decodeSymbol(&(seqState->stateML), &(seqState->DStream));
3045*0c16b537SWarner Losh     if (matchLength == MaxML) {
3046*0c16b537SWarner Losh         U32 add = *dumps++;
3047*0c16b537SWarner Losh         if (add < 255) matchLength += add;
3048*0c16b537SWarner Losh         else {
3049*0c16b537SWarner Losh             matchLength = dumps[0] + (dumps[1]<<8) + (dumps[2]<<16);
3050*0c16b537SWarner Losh             dumps += 3;
3051*0c16b537SWarner Losh         }
3052*0c16b537SWarner Losh         if (dumps > de) { matchLength = MaxML+255; }  /* late correction, to avoid using uninitialized memory */
3053*0c16b537SWarner Losh         if (dumps >= de) { dumps = de-1; }  /* late correction, to avoid read overflow (data is now corrupted anyway) */
3054*0c16b537SWarner Losh     }
3055*0c16b537SWarner Losh     matchLength += MINMATCH;
3056*0c16b537SWarner Losh 
3057*0c16b537SWarner Losh     /* save result */
3058*0c16b537SWarner Losh     seq->litLength = litLength;
3059*0c16b537SWarner Losh     seq->offset = offset;
3060*0c16b537SWarner Losh     seq->matchLength = matchLength;
3061*0c16b537SWarner Losh     seqState->dumps = dumps;
3062*0c16b537SWarner Losh }
3063*0c16b537SWarner Losh 
3064*0c16b537SWarner Losh 
3065*0c16b537SWarner Losh static size_t ZSTD_execSequence(BYTE* op,
3066*0c16b537SWarner Losh                                 BYTE* const oend, seq_t sequence,
3067*0c16b537SWarner Losh                                 const BYTE** litPtr, const BYTE* const litLimit,
3068*0c16b537SWarner Losh                                 const BYTE* const base, const BYTE* const vBase, const BYTE* const dictEnd)
3069*0c16b537SWarner Losh {
3070*0c16b537SWarner Losh     static const int dec32table[] = { 0, 1, 2, 1, 4, 4, 4, 4 };   /* added */
3071*0c16b537SWarner Losh     static const int dec64table[] = { 8, 8, 8, 7, 8, 9,10,11 };   /* substracted */
3072*0c16b537SWarner Losh     BYTE* const oLitEnd = op + sequence.litLength;
3073*0c16b537SWarner Losh     const size_t sequenceLength = sequence.litLength + sequence.matchLength;
3074*0c16b537SWarner Losh     BYTE* const oMatchEnd = op + sequenceLength;   /* risk : address space overflow (32-bits) */
3075*0c16b537SWarner Losh     BYTE* const oend_8 = oend-8;
3076*0c16b537SWarner Losh     const BYTE* const litEnd = *litPtr + sequence.litLength;
3077*0c16b537SWarner Losh     const BYTE* match = oLitEnd - sequence.offset;
3078*0c16b537SWarner Losh 
3079*0c16b537SWarner Losh     /* check */
3080*0c16b537SWarner Losh     if (oLitEnd > oend_8) return ERROR(dstSize_tooSmall);   /* last match must start at a minimum distance of 8 from oend */
3081*0c16b537SWarner Losh     if (oMatchEnd > oend) return ERROR(dstSize_tooSmall);   /* overwrite beyond dst buffer */
3082*0c16b537SWarner Losh     if (litEnd > litLimit) return ERROR(corruption_detected);   /* risk read beyond lit buffer */
3083*0c16b537SWarner Losh 
3084*0c16b537SWarner Losh     /* copy Literals */
3085*0c16b537SWarner Losh     ZSTD_wildcopy(op, *litPtr, sequence.litLength);   /* note : oLitEnd <= oend-8 : no risk of overwrite beyond oend */
3086*0c16b537SWarner Losh     op = oLitEnd;
3087*0c16b537SWarner Losh     *litPtr = litEnd;   /* update for next sequence */
3088*0c16b537SWarner Losh 
3089*0c16b537SWarner Losh     /* copy Match */
3090*0c16b537SWarner Losh     if (sequence.offset > (size_t)(oLitEnd - base))
3091*0c16b537SWarner Losh     {
3092*0c16b537SWarner Losh         /* offset beyond prefix */
3093*0c16b537SWarner Losh         if (sequence.offset > (size_t)(oLitEnd - vBase))
3094*0c16b537SWarner Losh             return ERROR(corruption_detected);
3095*0c16b537SWarner Losh         match = dictEnd - (base-match);
3096*0c16b537SWarner Losh         if (match + sequence.matchLength <= dictEnd)
3097*0c16b537SWarner Losh         {
3098*0c16b537SWarner Losh             memmove(oLitEnd, match, sequence.matchLength);
3099*0c16b537SWarner Losh             return sequenceLength;
3100*0c16b537SWarner Losh         }
3101*0c16b537SWarner Losh         /* span extDict & currentPrefixSegment */
3102*0c16b537SWarner Losh         {
3103*0c16b537SWarner Losh             size_t length1 = dictEnd - match;
3104*0c16b537SWarner Losh             memmove(oLitEnd, match, length1);
3105*0c16b537SWarner Losh             op = oLitEnd + length1;
3106*0c16b537SWarner Losh             sequence.matchLength -= length1;
3107*0c16b537SWarner Losh             match = base;
3108*0c16b537SWarner Losh             if (op > oend_8 || sequence.matchLength < MINMATCH) {
3109*0c16b537SWarner Losh               while (op < oMatchEnd) *op++ = *match++;
3110*0c16b537SWarner Losh               return sequenceLength;
3111*0c16b537SWarner Losh             }
3112*0c16b537SWarner Losh         }
3113*0c16b537SWarner Losh     }
3114*0c16b537SWarner Losh     /* Requirement: op <= oend_8 */
3115*0c16b537SWarner Losh 
3116*0c16b537SWarner Losh     /* match within prefix */
3117*0c16b537SWarner Losh     if (sequence.offset < 8) {
3118*0c16b537SWarner Losh         /* close range match, overlap */
3119*0c16b537SWarner Losh         const int sub2 = dec64table[sequence.offset];
3120*0c16b537SWarner Losh         op[0] = match[0];
3121*0c16b537SWarner Losh         op[1] = match[1];
3122*0c16b537SWarner Losh         op[2] = match[2];
3123*0c16b537SWarner Losh         op[3] = match[3];
3124*0c16b537SWarner Losh         match += dec32table[sequence.offset];
3125*0c16b537SWarner Losh         ZSTD_copy4(op+4, match);
3126*0c16b537SWarner Losh         match -= sub2;
3127*0c16b537SWarner Losh     } else {
3128*0c16b537SWarner Losh         ZSTD_copy8(op, match);
3129*0c16b537SWarner Losh     }
3130*0c16b537SWarner Losh     op += 8; match += 8;
3131*0c16b537SWarner Losh 
3132*0c16b537SWarner Losh     if (oMatchEnd > oend-(16-MINMATCH))
3133*0c16b537SWarner Losh     {
3134*0c16b537SWarner Losh         if (op < oend_8)
3135*0c16b537SWarner Losh         {
3136*0c16b537SWarner Losh             ZSTD_wildcopy(op, match, oend_8 - op);
3137*0c16b537SWarner Losh             match += oend_8 - op;
3138*0c16b537SWarner Losh             op = oend_8;
3139*0c16b537SWarner Losh         }
3140*0c16b537SWarner Losh         while (op < oMatchEnd) *op++ = *match++;
3141*0c16b537SWarner Losh     }
3142*0c16b537SWarner Losh     else
3143*0c16b537SWarner Losh     {
3144*0c16b537SWarner Losh         ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength-8);   /* works even if matchLength < 8 */
3145*0c16b537SWarner Losh     }
3146*0c16b537SWarner Losh     return sequenceLength;
3147*0c16b537SWarner Losh }
3148*0c16b537SWarner Losh 
3149*0c16b537SWarner Losh 
3150*0c16b537SWarner Losh static size_t ZSTD_decompressSequences(
3151*0c16b537SWarner Losh                                ZSTD_DCtx* dctx,
3152*0c16b537SWarner Losh                                void* dst, size_t maxDstSize,
3153*0c16b537SWarner Losh                          const void* seqStart, size_t seqSize)
3154*0c16b537SWarner Losh {
3155*0c16b537SWarner Losh     const BYTE* ip = (const BYTE*)seqStart;
3156*0c16b537SWarner Losh     const BYTE* const iend = ip + seqSize;
3157*0c16b537SWarner Losh     BYTE* const ostart = (BYTE* const)dst;
3158*0c16b537SWarner Losh     BYTE* op = ostart;
3159*0c16b537SWarner Losh     BYTE* const oend = ostart + maxDstSize;
3160*0c16b537SWarner Losh     size_t errorCode, dumpsLength;
3161*0c16b537SWarner Losh     const BYTE* litPtr = dctx->litPtr;
3162*0c16b537SWarner Losh     const BYTE* const litEnd = litPtr + dctx->litSize;
3163*0c16b537SWarner Losh     int nbSeq;
3164*0c16b537SWarner Losh     const BYTE* dumps;
3165*0c16b537SWarner Losh     U32* DTableLL = dctx->LLTable;
3166*0c16b537SWarner Losh     U32* DTableML = dctx->MLTable;
3167*0c16b537SWarner Losh     U32* DTableOffb = dctx->OffTable;
3168*0c16b537SWarner Losh     const BYTE* const base = (const BYTE*) (dctx->base);
3169*0c16b537SWarner Losh     const BYTE* const vBase = (const BYTE*) (dctx->vBase);
3170*0c16b537SWarner Losh     const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd);
3171*0c16b537SWarner Losh 
3172*0c16b537SWarner Losh     /* Build Decoding Tables */
3173*0c16b537SWarner Losh     errorCode = ZSTD_decodeSeqHeaders(&nbSeq, &dumps, &dumpsLength,
3174*0c16b537SWarner Losh                                       DTableLL, DTableML, DTableOffb,
3175*0c16b537SWarner Losh                                       ip, iend-ip);
3176*0c16b537SWarner Losh     if (ZSTD_isError(errorCode)) return errorCode;
3177*0c16b537SWarner Losh     ip += errorCode;
3178*0c16b537SWarner Losh 
3179*0c16b537SWarner Losh     /* Regen sequences */
3180*0c16b537SWarner Losh     {
3181*0c16b537SWarner Losh         seq_t sequence;
3182*0c16b537SWarner Losh         seqState_t seqState;
3183*0c16b537SWarner Losh 
3184*0c16b537SWarner Losh         memset(&sequence, 0, sizeof(sequence));
3185*0c16b537SWarner Losh         sequence.offset = 4;
3186*0c16b537SWarner Losh         seqState.dumps = dumps;
3187*0c16b537SWarner Losh         seqState.dumpsEnd = dumps + dumpsLength;
3188*0c16b537SWarner Losh         seqState.prevOffset = 4;
3189*0c16b537SWarner Losh         errorCode = BIT_initDStream(&(seqState.DStream), ip, iend-ip);
3190*0c16b537SWarner Losh         if (ERR_isError(errorCode)) return ERROR(corruption_detected);
3191*0c16b537SWarner Losh         FSE_initDState(&(seqState.stateLL), &(seqState.DStream), DTableLL);
3192*0c16b537SWarner Losh         FSE_initDState(&(seqState.stateOffb), &(seqState.DStream), DTableOffb);
3193*0c16b537SWarner Losh         FSE_initDState(&(seqState.stateML), &(seqState.DStream), DTableML);
3194*0c16b537SWarner Losh 
3195*0c16b537SWarner Losh         for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && nbSeq ; )
3196*0c16b537SWarner Losh         {
3197*0c16b537SWarner Losh             size_t oneSeqSize;
3198*0c16b537SWarner Losh             nbSeq--;
3199*0c16b537SWarner Losh             ZSTD_decodeSequence(&sequence, &seqState);
3200*0c16b537SWarner Losh             oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, base, vBase, dictEnd);
3201*0c16b537SWarner Losh             if (ZSTD_isError(oneSeqSize)) return oneSeqSize;
3202*0c16b537SWarner Losh             op += oneSeqSize;
3203*0c16b537SWarner Losh         }
3204*0c16b537SWarner Losh 
3205*0c16b537SWarner Losh         /* check if reached exact end */
3206*0c16b537SWarner Losh         if ( !BIT_endOfDStream(&(seqState.DStream)) ) return ERROR(corruption_detected);   /* DStream should be entirely and exactly consumed; otherwise data is corrupted */
3207*0c16b537SWarner Losh 
3208*0c16b537SWarner Losh         /* last literal segment */
3209*0c16b537SWarner Losh         {
3210*0c16b537SWarner Losh             size_t lastLLSize = litEnd - litPtr;
3211*0c16b537SWarner Losh             if (litPtr > litEnd) return ERROR(corruption_detected);
3212*0c16b537SWarner Losh             if (op+lastLLSize > oend) return ERROR(dstSize_tooSmall);
3213*0c16b537SWarner Losh             if (op != litPtr) memcpy(op, litPtr, lastLLSize);
3214*0c16b537SWarner Losh             op += lastLLSize;
3215*0c16b537SWarner Losh         }
3216*0c16b537SWarner Losh     }
3217*0c16b537SWarner Losh 
3218*0c16b537SWarner Losh     return op-ostart;
3219*0c16b537SWarner Losh }
3220*0c16b537SWarner Losh 
3221*0c16b537SWarner Losh 
3222*0c16b537SWarner Losh static void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst)
3223*0c16b537SWarner Losh {
3224*0c16b537SWarner Losh     if (dst != dctx->previousDstEnd)   /* not contiguous */
3225*0c16b537SWarner Losh     {
3226*0c16b537SWarner Losh         dctx->dictEnd = dctx->previousDstEnd;
3227*0c16b537SWarner Losh         dctx->vBase = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->base));
3228*0c16b537SWarner Losh         dctx->base = dst;
3229*0c16b537SWarner Losh         dctx->previousDstEnd = dst;
3230*0c16b537SWarner Losh     }
3231*0c16b537SWarner Losh }
3232*0c16b537SWarner Losh 
3233*0c16b537SWarner Losh 
3234*0c16b537SWarner Losh static size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
3235*0c16b537SWarner Losh                             void* dst, size_t maxDstSize,
3236*0c16b537SWarner Losh                       const void* src, size_t srcSize)
3237*0c16b537SWarner Losh {
3238*0c16b537SWarner Losh     /* blockType == blockCompressed */
3239*0c16b537SWarner Losh     const BYTE* ip = (const BYTE*)src;
3240*0c16b537SWarner Losh 
3241*0c16b537SWarner Losh     /* Decode literals sub-block */
3242*0c16b537SWarner Losh     size_t litCSize = ZSTD_decodeLiteralsBlock(dctx, src, srcSize);
3243*0c16b537SWarner Losh     if (ZSTD_isError(litCSize)) return litCSize;
3244*0c16b537SWarner Losh     ip += litCSize;
3245*0c16b537SWarner Losh     srcSize -= litCSize;
3246*0c16b537SWarner Losh 
3247*0c16b537SWarner Losh     return ZSTD_decompressSequences(dctx, dst, maxDstSize, ip, srcSize);
3248*0c16b537SWarner Losh }
3249*0c16b537SWarner Losh 
3250*0c16b537SWarner Losh 
3251*0c16b537SWarner Losh static size_t ZSTD_decompress_usingDict(ZSTD_DCtx* ctx,
3252*0c16b537SWarner Losh                                  void* dst, size_t maxDstSize,
3253*0c16b537SWarner Losh                                  const void* src, size_t srcSize,
3254*0c16b537SWarner Losh                                  const void* dict, size_t dictSize)
3255*0c16b537SWarner Losh {
3256*0c16b537SWarner Losh     const BYTE* ip = (const BYTE*)src;
3257*0c16b537SWarner Losh     const BYTE* iend = ip + srcSize;
3258*0c16b537SWarner Losh     BYTE* const ostart = (BYTE* const)dst;
3259*0c16b537SWarner Losh     BYTE* op = ostart;
3260*0c16b537SWarner Losh     BYTE* const oend = ostart + maxDstSize;
3261*0c16b537SWarner Losh     size_t remainingSize = srcSize;
3262*0c16b537SWarner Losh     blockProperties_t blockProperties;
3263*0c16b537SWarner Losh 
3264*0c16b537SWarner Losh     /* init */
3265*0c16b537SWarner Losh     ZSTD_resetDCtx(ctx);
3266*0c16b537SWarner Losh     if (dict)
3267*0c16b537SWarner Losh     {
3268*0c16b537SWarner Losh         ZSTD_decompress_insertDictionary(ctx, dict, dictSize);
3269*0c16b537SWarner Losh         ctx->dictEnd = ctx->previousDstEnd;
3270*0c16b537SWarner Losh         ctx->vBase = (const char*)dst - ((const char*)(ctx->previousDstEnd) - (const char*)(ctx->base));
3271*0c16b537SWarner Losh         ctx->base = dst;
3272*0c16b537SWarner Losh     }
3273*0c16b537SWarner Losh     else
3274*0c16b537SWarner Losh     {
3275*0c16b537SWarner Losh         ctx->vBase = ctx->base = ctx->dictEnd = dst;
3276*0c16b537SWarner Losh     }
3277*0c16b537SWarner Losh 
3278*0c16b537SWarner Losh     /* Frame Header */
3279*0c16b537SWarner Losh     {
3280*0c16b537SWarner Losh         size_t frameHeaderSize;
3281*0c16b537SWarner Losh         if (srcSize < ZSTD_frameHeaderSize_min+ZSTD_blockHeaderSize) return ERROR(srcSize_wrong);
3282*0c16b537SWarner Losh         frameHeaderSize = ZSTD_decodeFrameHeader_Part1(ctx, src, ZSTD_frameHeaderSize_min);
3283*0c16b537SWarner Losh         if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize;
3284*0c16b537SWarner Losh         if (srcSize < frameHeaderSize+ZSTD_blockHeaderSize) return ERROR(srcSize_wrong);
3285*0c16b537SWarner Losh         ip += frameHeaderSize; remainingSize -= frameHeaderSize;
3286*0c16b537SWarner Losh         frameHeaderSize = ZSTD_decodeFrameHeader_Part2(ctx, src, frameHeaderSize);
3287*0c16b537SWarner Losh         if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize;
3288*0c16b537SWarner Losh     }
3289*0c16b537SWarner Losh 
3290*0c16b537SWarner Losh     /* Loop on each block */
3291*0c16b537SWarner Losh     while (1)
3292*0c16b537SWarner Losh     {
3293*0c16b537SWarner Losh         size_t decodedSize=0;
3294*0c16b537SWarner Losh         size_t cBlockSize = ZSTD_getcBlockSize(ip, iend-ip, &blockProperties);
3295*0c16b537SWarner Losh         if (ZSTD_isError(cBlockSize)) return cBlockSize;
3296*0c16b537SWarner Losh 
3297*0c16b537SWarner Losh         ip += ZSTD_blockHeaderSize;
3298*0c16b537SWarner Losh         remainingSize -= ZSTD_blockHeaderSize;
3299*0c16b537SWarner Losh         if (cBlockSize > remainingSize) return ERROR(srcSize_wrong);
3300*0c16b537SWarner Losh 
3301*0c16b537SWarner Losh         switch(blockProperties.blockType)
3302*0c16b537SWarner Losh         {
3303*0c16b537SWarner Losh         case bt_compressed:
3304*0c16b537SWarner Losh             decodedSize = ZSTD_decompressBlock_internal(ctx, op, oend-op, ip, cBlockSize);
3305*0c16b537SWarner Losh             break;
3306*0c16b537SWarner Losh         case bt_raw :
3307*0c16b537SWarner Losh             decodedSize = ZSTD_copyRawBlock(op, oend-op, ip, cBlockSize);
3308*0c16b537SWarner Losh             break;
3309*0c16b537SWarner Losh         case bt_rle :
3310*0c16b537SWarner Losh             return ERROR(GENERIC);   /* not yet supported */
3311*0c16b537SWarner Losh             break;
3312*0c16b537SWarner Losh         case bt_end :
3313*0c16b537SWarner Losh             /* end of frame */
3314*0c16b537SWarner Losh             if (remainingSize) return ERROR(srcSize_wrong);
3315*0c16b537SWarner Losh             break;
3316*0c16b537SWarner Losh         default:
3317*0c16b537SWarner Losh             return ERROR(GENERIC);   /* impossible */
3318*0c16b537SWarner Losh         }
3319*0c16b537SWarner Losh         if (cBlockSize == 0) break;   /* bt_end */
3320*0c16b537SWarner Losh 
3321*0c16b537SWarner Losh         if (ZSTD_isError(decodedSize)) return decodedSize;
3322*0c16b537SWarner Losh         op += decodedSize;
3323*0c16b537SWarner Losh         ip += cBlockSize;
3324*0c16b537SWarner Losh         remainingSize -= cBlockSize;
3325*0c16b537SWarner Losh     }
3326*0c16b537SWarner Losh 
3327*0c16b537SWarner Losh     return op-ostart;
3328*0c16b537SWarner Losh }
3329*0c16b537SWarner Losh 
3330*0c16b537SWarner Losh static size_t ZSTD_findFrameCompressedSize(const void* src, size_t srcSize)
3331*0c16b537SWarner Losh {
3332*0c16b537SWarner Losh     const BYTE* ip = (const BYTE*)src;
3333*0c16b537SWarner Losh     size_t remainingSize = srcSize;
3334*0c16b537SWarner Losh     blockProperties_t blockProperties;
3335*0c16b537SWarner Losh 
3336*0c16b537SWarner Losh     /* Frame Header */
3337*0c16b537SWarner Losh     if (srcSize < ZSTD_frameHeaderSize_min) return ERROR(srcSize_wrong);
3338*0c16b537SWarner Losh     if (MEM_readLE32(src) != ZSTD_MAGICNUMBER) return ERROR(prefix_unknown);
3339*0c16b537SWarner Losh     ip += ZSTD_frameHeaderSize_min; remainingSize -= ZSTD_frameHeaderSize_min;
3340*0c16b537SWarner Losh 
3341*0c16b537SWarner Losh     /* Loop on each block */
3342*0c16b537SWarner Losh     while (1)
3343*0c16b537SWarner Losh     {
3344*0c16b537SWarner Losh         size_t cBlockSize = ZSTD_getcBlockSize(ip, remainingSize, &blockProperties);
3345*0c16b537SWarner Losh         if (ZSTD_isError(cBlockSize)) return cBlockSize;
3346*0c16b537SWarner Losh 
3347*0c16b537SWarner Losh         ip += ZSTD_blockHeaderSize;
3348*0c16b537SWarner Losh         remainingSize -= ZSTD_blockHeaderSize;
3349*0c16b537SWarner Losh         if (cBlockSize > remainingSize) return ERROR(srcSize_wrong);
3350*0c16b537SWarner Losh 
3351*0c16b537SWarner Losh         if (cBlockSize == 0) break;   /* bt_end */
3352*0c16b537SWarner Losh 
3353*0c16b537SWarner Losh         ip += cBlockSize;
3354*0c16b537SWarner Losh         remainingSize -= cBlockSize;
3355*0c16b537SWarner Losh     }
3356*0c16b537SWarner Losh 
3357*0c16b537SWarner Losh     return ip - (const BYTE*)src;
3358*0c16b537SWarner Losh }
3359*0c16b537SWarner Losh 
3360*0c16b537SWarner Losh /* ******************************
3361*0c16b537SWarner Losh *  Streaming Decompression API
3362*0c16b537SWarner Losh ********************************/
3363*0c16b537SWarner Losh static size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx)
3364*0c16b537SWarner Losh {
3365*0c16b537SWarner Losh     return dctx->expected;
3366*0c16b537SWarner Losh }
3367*0c16b537SWarner Losh 
3368*0c16b537SWarner Losh static size_t ZSTD_decompressContinue(ZSTD_DCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
3369*0c16b537SWarner Losh {
3370*0c16b537SWarner Losh     /* Sanity check */
3371*0c16b537SWarner Losh     if (srcSize != ctx->expected) return ERROR(srcSize_wrong);
3372*0c16b537SWarner Losh     ZSTD_checkContinuity(ctx, dst);
3373*0c16b537SWarner Losh 
3374*0c16b537SWarner Losh     /* Decompress : frame header; part 1 */
3375*0c16b537SWarner Losh     switch (ctx->stage)
3376*0c16b537SWarner Losh     {
3377*0c16b537SWarner Losh     case ZSTDds_getFrameHeaderSize :
3378*0c16b537SWarner Losh         /* get frame header size */
3379*0c16b537SWarner Losh         if (srcSize != ZSTD_frameHeaderSize_min) return ERROR(srcSize_wrong);   /* impossible */
3380*0c16b537SWarner Losh         ctx->headerSize = ZSTD_decodeFrameHeader_Part1(ctx, src, ZSTD_frameHeaderSize_min);
3381*0c16b537SWarner Losh         if (ZSTD_isError(ctx->headerSize)) return ctx->headerSize;
3382*0c16b537SWarner Losh         memcpy(ctx->headerBuffer, src, ZSTD_frameHeaderSize_min);
3383*0c16b537SWarner Losh         if (ctx->headerSize > ZSTD_frameHeaderSize_min) return ERROR(GENERIC);   /* impossible */
3384*0c16b537SWarner Losh         ctx->expected = 0;   /* not necessary to copy more */
3385*0c16b537SWarner Losh         /* fallthrough */
3386*0c16b537SWarner Losh     case ZSTDds_decodeFrameHeader:
3387*0c16b537SWarner Losh         /* get frame header */
3388*0c16b537SWarner Losh         {   size_t const result = ZSTD_decodeFrameHeader_Part2(ctx, ctx->headerBuffer, ctx->headerSize);
3389*0c16b537SWarner Losh             if (ZSTD_isError(result)) return result;
3390*0c16b537SWarner Losh             ctx->expected = ZSTD_blockHeaderSize;
3391*0c16b537SWarner Losh             ctx->stage = ZSTDds_decodeBlockHeader;
3392*0c16b537SWarner Losh             return 0;
3393*0c16b537SWarner Losh         }
3394*0c16b537SWarner Losh     case ZSTDds_decodeBlockHeader:
3395*0c16b537SWarner Losh         /* Decode block header */
3396*0c16b537SWarner Losh         {   blockProperties_t bp;
3397*0c16b537SWarner Losh             size_t const blockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &bp);
3398*0c16b537SWarner Losh             if (ZSTD_isError(blockSize)) return blockSize;
3399*0c16b537SWarner Losh             if (bp.blockType == bt_end)
3400*0c16b537SWarner Losh             {
3401*0c16b537SWarner Losh                 ctx->expected = 0;
3402*0c16b537SWarner Losh                 ctx->stage = ZSTDds_getFrameHeaderSize;
3403*0c16b537SWarner Losh             }
3404*0c16b537SWarner Losh             else
3405*0c16b537SWarner Losh             {
3406*0c16b537SWarner Losh                 ctx->expected = blockSize;
3407*0c16b537SWarner Losh                 ctx->bType = bp.blockType;
3408*0c16b537SWarner Losh                 ctx->stage = ZSTDds_decompressBlock;
3409*0c16b537SWarner Losh             }
3410*0c16b537SWarner Losh             return 0;
3411*0c16b537SWarner Losh         }
3412*0c16b537SWarner Losh     case ZSTDds_decompressBlock:
3413*0c16b537SWarner Losh         {
3414*0c16b537SWarner Losh             /* Decompress : block content */
3415*0c16b537SWarner Losh             size_t rSize;
3416*0c16b537SWarner Losh             switch(ctx->bType)
3417*0c16b537SWarner Losh             {
3418*0c16b537SWarner Losh             case bt_compressed:
3419*0c16b537SWarner Losh                 rSize = ZSTD_decompressBlock_internal(ctx, dst, maxDstSize, src, srcSize);
3420*0c16b537SWarner Losh                 break;
3421*0c16b537SWarner Losh             case bt_raw :
3422*0c16b537SWarner Losh                 rSize = ZSTD_copyRawBlock(dst, maxDstSize, src, srcSize);
3423*0c16b537SWarner Losh                 break;
3424*0c16b537SWarner Losh             case bt_rle :
3425*0c16b537SWarner Losh                 return ERROR(GENERIC);   /* not yet handled */
3426*0c16b537SWarner Losh                 break;
3427*0c16b537SWarner Losh             case bt_end :   /* should never happen (filtered at phase 1) */
3428*0c16b537SWarner Losh                 rSize = 0;
3429*0c16b537SWarner Losh                 break;
3430*0c16b537SWarner Losh             default:
3431*0c16b537SWarner Losh                 return ERROR(GENERIC);
3432*0c16b537SWarner Losh             }
3433*0c16b537SWarner Losh             ctx->stage = ZSTDds_decodeBlockHeader;
3434*0c16b537SWarner Losh             ctx->expected = ZSTD_blockHeaderSize;
3435*0c16b537SWarner Losh             ctx->previousDstEnd = (char*)dst + rSize;
3436*0c16b537SWarner Losh             return rSize;
3437*0c16b537SWarner Losh         }
3438*0c16b537SWarner Losh     default:
3439*0c16b537SWarner Losh         return ERROR(GENERIC);   /* impossible */
3440*0c16b537SWarner Losh     }
3441*0c16b537SWarner Losh }
3442*0c16b537SWarner Losh 
3443*0c16b537SWarner Losh 
3444*0c16b537SWarner Losh static void ZSTD_decompress_insertDictionary(ZSTD_DCtx* ctx, const void* dict, size_t dictSize)
3445*0c16b537SWarner Losh {
3446*0c16b537SWarner Losh     ctx->dictEnd = ctx->previousDstEnd;
3447*0c16b537SWarner Losh     ctx->vBase = (const char*)dict - ((const char*)(ctx->previousDstEnd) - (const char*)(ctx->base));
3448*0c16b537SWarner Losh     ctx->base = dict;
3449*0c16b537SWarner Losh     ctx->previousDstEnd = (const char*)dict + dictSize;
3450*0c16b537SWarner Losh }
3451*0c16b537SWarner Losh 
3452*0c16b537SWarner Losh 
3453*0c16b537SWarner Losh 
3454*0c16b537SWarner Losh /*
3455*0c16b537SWarner Losh     Buffered version of Zstd compression library
3456*0c16b537SWarner Losh     Copyright (C) 2015, Yann Collet.
3457*0c16b537SWarner Losh 
3458*0c16b537SWarner Losh     BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
3459*0c16b537SWarner Losh 
3460*0c16b537SWarner Losh     Redistribution and use in source and binary forms, with or without
3461*0c16b537SWarner Losh     modification, are permitted provided that the following conditions are
3462*0c16b537SWarner Losh     met:
3463*0c16b537SWarner Losh     * Redistributions of source code must retain the above copyright
3464*0c16b537SWarner Losh     notice, this list of conditions and the following disclaimer.
3465*0c16b537SWarner Losh     * Redistributions in binary form must reproduce the above
3466*0c16b537SWarner Losh     copyright notice, this list of conditions and the following disclaimer
3467*0c16b537SWarner Losh     in the documentation and/or other materials provided with the
3468*0c16b537SWarner Losh     distribution.
3469*0c16b537SWarner Losh     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3470*0c16b537SWarner Losh     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3471*0c16b537SWarner Losh     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3472*0c16b537SWarner Losh     A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3473*0c16b537SWarner Losh     OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3474*0c16b537SWarner Losh     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3475*0c16b537SWarner Losh     LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3476*0c16b537SWarner Losh     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3477*0c16b537SWarner Losh     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3478*0c16b537SWarner Losh     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3479*0c16b537SWarner Losh     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3480*0c16b537SWarner Losh 
3481*0c16b537SWarner Losh     You can contact the author at :
3482*0c16b537SWarner Losh     - zstd source repository : https://github.com/Cyan4973/zstd
3483*0c16b537SWarner Losh     - ztsd public forum : https://groups.google.com/forum/#!forum/lz4c
3484*0c16b537SWarner Losh */
3485*0c16b537SWarner Losh 
3486*0c16b537SWarner Losh /* The objects defined into this file should be considered experimental.
3487*0c16b537SWarner Losh  * They are not labelled stable, as their prototype may change in the future.
3488*0c16b537SWarner Losh  * You can use them for tests, provide feedback, or if you can endure risk of future changes.
3489*0c16b537SWarner Losh  */
3490*0c16b537SWarner Losh 
3491*0c16b537SWarner Losh /* *************************************
3492*0c16b537SWarner Losh *  Includes
3493*0c16b537SWarner Losh ***************************************/
3494*0c16b537SWarner Losh #include <stdlib.h>
3495*0c16b537SWarner Losh 
3496*0c16b537SWarner Losh 
3497*0c16b537SWarner Losh /** ************************************************
3498*0c16b537SWarner Losh *  Streaming decompression
3499*0c16b537SWarner Losh *
3500*0c16b537SWarner Losh *  A ZBUFF_DCtx object is required to track streaming operation.
3501*0c16b537SWarner Losh *  Use ZBUFF_createDCtx() and ZBUFF_freeDCtx() to create/release resources.
3502*0c16b537SWarner Losh *  Use ZBUFF_decompressInit() to start a new decompression operation.
3503*0c16b537SWarner Losh *  ZBUFF_DCtx objects can be reused multiple times.
3504*0c16b537SWarner Losh *
3505*0c16b537SWarner Losh *  Use ZBUFF_decompressContinue() repetitively to consume your input.
3506*0c16b537SWarner Losh *  *srcSizePtr and *maxDstSizePtr can be any size.
3507*0c16b537SWarner Losh *  The function will report how many bytes were read or written by modifying *srcSizePtr and *maxDstSizePtr.
3508*0c16b537SWarner 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.
3509*0c16b537SWarner 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 .
3510*0c16b537SWarner 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)
3511*0c16b537SWarner Losh *            or 0 when a frame is completely decoded
3512*0c16b537SWarner Losh *            or an error code, which can be tested using ZBUFF_isError().
3513*0c16b537SWarner Losh *
3514*0c16b537SWarner Losh *  Hint : recommended buffer sizes (not compulsory)
3515*0c16b537SWarner 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.
3516*0c16b537SWarner Losh *  input : just follow indications from ZBUFF_decompressContinue() to minimize latency. It should always be <= 128 KB + 3 .
3517*0c16b537SWarner Losh * **************************************************/
3518*0c16b537SWarner Losh 
3519*0c16b537SWarner Losh typedef enum { ZBUFFds_init, ZBUFFds_readHeader, ZBUFFds_loadHeader, ZBUFFds_decodeHeader,
3520*0c16b537SWarner Losh                ZBUFFds_read, ZBUFFds_load, ZBUFFds_flush } ZBUFF_dStage;
3521*0c16b537SWarner Losh 
3522*0c16b537SWarner Losh /* *** Resource management *** */
3523*0c16b537SWarner Losh 
3524*0c16b537SWarner Losh #define ZSTD_frameHeaderSize_max 5   /* too magical, should come from reference */
3525*0c16b537SWarner Losh struct ZBUFFv04_DCtx_s {
3526*0c16b537SWarner Losh     ZSTD_DCtx* zc;
3527*0c16b537SWarner Losh     ZSTD_parameters params;
3528*0c16b537SWarner Losh     char* inBuff;
3529*0c16b537SWarner Losh     size_t inBuffSize;
3530*0c16b537SWarner Losh     size_t inPos;
3531*0c16b537SWarner Losh     char* outBuff;
3532*0c16b537SWarner Losh     size_t outBuffSize;
3533*0c16b537SWarner Losh     size_t outStart;
3534*0c16b537SWarner Losh     size_t outEnd;
3535*0c16b537SWarner Losh     size_t hPos;
3536*0c16b537SWarner Losh     const char* dict;
3537*0c16b537SWarner Losh     size_t dictSize;
3538*0c16b537SWarner Losh     ZBUFF_dStage stage;
3539*0c16b537SWarner Losh     unsigned char headerBuffer[ZSTD_frameHeaderSize_max];
3540*0c16b537SWarner Losh };   /* typedef'd to ZBUFF_DCtx within "zstd_buffered.h" */
3541*0c16b537SWarner Losh 
3542*0c16b537SWarner Losh typedef ZBUFFv04_DCtx ZBUFF_DCtx;
3543*0c16b537SWarner Losh 
3544*0c16b537SWarner Losh 
3545*0c16b537SWarner Losh static ZBUFF_DCtx* ZBUFF_createDCtx(void)
3546*0c16b537SWarner Losh {
3547*0c16b537SWarner Losh     ZBUFF_DCtx* zbc = (ZBUFF_DCtx*)malloc(sizeof(ZBUFF_DCtx));
3548*0c16b537SWarner Losh     if (zbc==NULL) return NULL;
3549*0c16b537SWarner Losh     memset(zbc, 0, sizeof(*zbc));
3550*0c16b537SWarner Losh     zbc->zc = ZSTD_createDCtx();
3551*0c16b537SWarner Losh     zbc->stage = ZBUFFds_init;
3552*0c16b537SWarner Losh     return zbc;
3553*0c16b537SWarner Losh }
3554*0c16b537SWarner Losh 
3555*0c16b537SWarner Losh static size_t ZBUFF_freeDCtx(ZBUFF_DCtx* zbc)
3556*0c16b537SWarner Losh {
3557*0c16b537SWarner Losh     if (zbc==NULL) return 0;   /* support free on null */
3558*0c16b537SWarner Losh     ZSTD_freeDCtx(zbc->zc);
3559*0c16b537SWarner Losh     free(zbc->inBuff);
3560*0c16b537SWarner Losh     free(zbc->outBuff);
3561*0c16b537SWarner Losh     free(zbc);
3562*0c16b537SWarner Losh     return 0;
3563*0c16b537SWarner Losh }
3564*0c16b537SWarner Losh 
3565*0c16b537SWarner Losh 
3566*0c16b537SWarner Losh /* *** Initialization *** */
3567*0c16b537SWarner Losh 
3568*0c16b537SWarner Losh static size_t ZBUFF_decompressInit(ZBUFF_DCtx* zbc)
3569*0c16b537SWarner Losh {
3570*0c16b537SWarner Losh     zbc->stage = ZBUFFds_readHeader;
3571*0c16b537SWarner Losh     zbc->hPos = zbc->inPos = zbc->outStart = zbc->outEnd = zbc->dictSize = 0;
3572*0c16b537SWarner Losh     return ZSTD_resetDCtx(zbc->zc);
3573*0c16b537SWarner Losh }
3574*0c16b537SWarner Losh 
3575*0c16b537SWarner Losh 
3576*0c16b537SWarner Losh static size_t ZBUFF_decompressWithDictionary(ZBUFF_DCtx* zbc, const void* src, size_t srcSize)
3577*0c16b537SWarner Losh {
3578*0c16b537SWarner Losh     zbc->dict = (const char*)src;
3579*0c16b537SWarner Losh     zbc->dictSize = srcSize;
3580*0c16b537SWarner Losh     return 0;
3581*0c16b537SWarner Losh }
3582*0c16b537SWarner Losh 
3583*0c16b537SWarner Losh static size_t ZBUFF_limitCopy(void* dst, size_t maxDstSize, const void* src, size_t srcSize)
3584*0c16b537SWarner Losh {
3585*0c16b537SWarner Losh     size_t length = MIN(maxDstSize, srcSize);
3586*0c16b537SWarner Losh     memcpy(dst, src, length);
3587*0c16b537SWarner Losh     return length;
3588*0c16b537SWarner Losh }
3589*0c16b537SWarner Losh 
3590*0c16b537SWarner Losh /* *** Decompression *** */
3591*0c16b537SWarner Losh 
3592*0c16b537SWarner Losh static size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, void* dst, size_t* maxDstSizePtr, const void* src, size_t* srcSizePtr)
3593*0c16b537SWarner Losh {
3594*0c16b537SWarner Losh     const char* const istart = (const char*)src;
3595*0c16b537SWarner Losh     const char* ip = istart;
3596*0c16b537SWarner Losh     const char* const iend = istart + *srcSizePtr;
3597*0c16b537SWarner Losh     char* const ostart = (char*)dst;
3598*0c16b537SWarner Losh     char* op = ostart;
3599*0c16b537SWarner Losh     char* const oend = ostart + *maxDstSizePtr;
3600*0c16b537SWarner Losh     U32 notDone = 1;
3601*0c16b537SWarner Losh 
3602*0c16b537SWarner Losh     while (notDone)
3603*0c16b537SWarner Losh     {
3604*0c16b537SWarner Losh         switch(zbc->stage)
3605*0c16b537SWarner Losh         {
3606*0c16b537SWarner Losh 
3607*0c16b537SWarner Losh         case ZBUFFds_init :
3608*0c16b537SWarner Losh             return ERROR(init_missing);
3609*0c16b537SWarner Losh 
3610*0c16b537SWarner Losh         case ZBUFFds_readHeader :
3611*0c16b537SWarner Losh             /* read header from src */
3612*0c16b537SWarner Losh             {   size_t const headerSize = ZSTD_getFrameParams(&(zbc->params), src, *srcSizePtr);
3613*0c16b537SWarner Losh                 if (ZSTD_isError(headerSize)) return headerSize;
3614*0c16b537SWarner Losh                 if (headerSize) {
3615*0c16b537SWarner Losh                     /* not enough input to decode header : tell how many bytes would be necessary */
3616*0c16b537SWarner Losh                     memcpy(zbc->headerBuffer+zbc->hPos, src, *srcSizePtr);
3617*0c16b537SWarner Losh                     zbc->hPos += *srcSizePtr;
3618*0c16b537SWarner Losh                     *maxDstSizePtr = 0;
3619*0c16b537SWarner Losh                     zbc->stage = ZBUFFds_loadHeader;
3620*0c16b537SWarner Losh                     return headerSize - zbc->hPos;
3621*0c16b537SWarner Losh                 }
3622*0c16b537SWarner Losh                 zbc->stage = ZBUFFds_decodeHeader;
3623*0c16b537SWarner Losh                 break;
3624*0c16b537SWarner Losh             }
3625*0c16b537SWarner Losh 
3626*0c16b537SWarner Losh         case ZBUFFds_loadHeader:
3627*0c16b537SWarner Losh             /* complete header from src */
3628*0c16b537SWarner Losh             {   size_t headerSize = ZBUFF_limitCopy(
3629*0c16b537SWarner Losh                     zbc->headerBuffer + zbc->hPos, ZSTD_frameHeaderSize_max - zbc->hPos,
3630*0c16b537SWarner Losh                     src, *srcSizePtr);
3631*0c16b537SWarner Losh                 zbc->hPos += headerSize;
3632*0c16b537SWarner Losh                 ip += headerSize;
3633*0c16b537SWarner Losh                 headerSize = ZSTD_getFrameParams(&(zbc->params), zbc->headerBuffer, zbc->hPos);
3634*0c16b537SWarner Losh                 if (ZSTD_isError(headerSize)) return headerSize;
3635*0c16b537SWarner Losh                 if (headerSize) {
3636*0c16b537SWarner Losh                     /* not enough input to decode header : tell how many bytes would be necessary */
3637*0c16b537SWarner Losh                     *maxDstSizePtr = 0;
3638*0c16b537SWarner Losh                     return headerSize - zbc->hPos;
3639*0c16b537SWarner Losh             }   }
3640*0c16b537SWarner Losh             /* intentional fallthrough */
3641*0c16b537SWarner Losh 
3642*0c16b537SWarner Losh         case ZBUFFds_decodeHeader:
3643*0c16b537SWarner Losh                 /* apply header to create / resize buffers */
3644*0c16b537SWarner Losh                 {   size_t const neededOutSize = (size_t)1 << zbc->params.windowLog;
3645*0c16b537SWarner Losh                     size_t const neededInSize = BLOCKSIZE;   /* a block is never > BLOCKSIZE */
3646*0c16b537SWarner Losh                     if (zbc->inBuffSize < neededInSize) {
3647*0c16b537SWarner Losh                         free(zbc->inBuff);
3648*0c16b537SWarner Losh                         zbc->inBuffSize = neededInSize;
3649*0c16b537SWarner Losh                         zbc->inBuff = (char*)malloc(neededInSize);
3650*0c16b537SWarner Losh                         if (zbc->inBuff == NULL) return ERROR(memory_allocation);
3651*0c16b537SWarner Losh                     }
3652*0c16b537SWarner Losh                     if (zbc->outBuffSize < neededOutSize) {
3653*0c16b537SWarner Losh                         free(zbc->outBuff);
3654*0c16b537SWarner Losh                         zbc->outBuffSize = neededOutSize;
3655*0c16b537SWarner Losh                         zbc->outBuff = (char*)malloc(neededOutSize);
3656*0c16b537SWarner Losh                         if (zbc->outBuff == NULL) return ERROR(memory_allocation);
3657*0c16b537SWarner Losh                 }   }
3658*0c16b537SWarner Losh                 if (zbc->dictSize)
3659*0c16b537SWarner Losh                     ZSTD_decompress_insertDictionary(zbc->zc, zbc->dict, zbc->dictSize);
3660*0c16b537SWarner Losh                 if (zbc->hPos) {
3661*0c16b537SWarner Losh                     /* some data already loaded into headerBuffer : transfer into inBuff */
3662*0c16b537SWarner Losh                     memcpy(zbc->inBuff, zbc->headerBuffer, zbc->hPos);
3663*0c16b537SWarner Losh                     zbc->inPos = zbc->hPos;
3664*0c16b537SWarner Losh                     zbc->hPos = 0;
3665*0c16b537SWarner Losh                     zbc->stage = ZBUFFds_load;
3666*0c16b537SWarner Losh                     break;
3667*0c16b537SWarner Losh                 }
3668*0c16b537SWarner Losh                 zbc->stage = ZBUFFds_read;
3669*0c16b537SWarner Losh 		/* fall-through */
3670*0c16b537SWarner Losh         case ZBUFFds_read:
3671*0c16b537SWarner Losh             {
3672*0c16b537SWarner Losh                 size_t neededInSize = ZSTD_nextSrcSizeToDecompress(zbc->zc);
3673*0c16b537SWarner Losh                 if (neededInSize==0)   /* end of frame */
3674*0c16b537SWarner Losh                 {
3675*0c16b537SWarner Losh                     zbc->stage = ZBUFFds_init;
3676*0c16b537SWarner Losh                     notDone = 0;
3677*0c16b537SWarner Losh                     break;
3678*0c16b537SWarner Losh                 }
3679*0c16b537SWarner Losh                 if ((size_t)(iend-ip) >= neededInSize)
3680*0c16b537SWarner Losh                 {
3681*0c16b537SWarner Losh                     /* directly decode from src */
3682*0c16b537SWarner Losh                     size_t decodedSize = ZSTD_decompressContinue(zbc->zc,
3683*0c16b537SWarner Losh                         zbc->outBuff + zbc->outStart, zbc->outBuffSize - zbc->outStart,
3684*0c16b537SWarner Losh                         ip, neededInSize);
3685*0c16b537SWarner Losh                     if (ZSTD_isError(decodedSize)) return decodedSize;
3686*0c16b537SWarner Losh                     ip += neededInSize;
3687*0c16b537SWarner Losh                     if (!decodedSize) break;   /* this was just a header */
3688*0c16b537SWarner Losh                     zbc->outEnd = zbc->outStart +  decodedSize;
3689*0c16b537SWarner Losh                     zbc->stage = ZBUFFds_flush;
3690*0c16b537SWarner Losh                     break;
3691*0c16b537SWarner Losh                 }
3692*0c16b537SWarner Losh                 if (ip==iend) { notDone = 0; break; }   /* no more input */
3693*0c16b537SWarner Losh                 zbc->stage = ZBUFFds_load;
3694*0c16b537SWarner Losh             }
3695*0c16b537SWarner Losh 	    /* fall-through */
3696*0c16b537SWarner Losh         case ZBUFFds_load:
3697*0c16b537SWarner Losh             {
3698*0c16b537SWarner Losh                 size_t neededInSize = ZSTD_nextSrcSizeToDecompress(zbc->zc);
3699*0c16b537SWarner Losh                 size_t toLoad = neededInSize - zbc->inPos;   /* should always be <= remaining space within inBuff */
3700*0c16b537SWarner Losh                 size_t loadedSize;
3701*0c16b537SWarner Losh                 if (toLoad > zbc->inBuffSize - zbc->inPos) return ERROR(corruption_detected);   /* should never happen */
3702*0c16b537SWarner Losh                 loadedSize = ZBUFF_limitCopy(zbc->inBuff + zbc->inPos, toLoad, ip, iend-ip);
3703*0c16b537SWarner Losh                 ip += loadedSize;
3704*0c16b537SWarner Losh                 zbc->inPos += loadedSize;
3705*0c16b537SWarner Losh                 if (loadedSize < toLoad) { notDone = 0; break; }   /* not enough input, wait for more */
3706*0c16b537SWarner Losh                 {
3707*0c16b537SWarner Losh                     size_t decodedSize = ZSTD_decompressContinue(zbc->zc,
3708*0c16b537SWarner Losh                         zbc->outBuff + zbc->outStart, zbc->outBuffSize - zbc->outStart,
3709*0c16b537SWarner Losh                         zbc->inBuff, neededInSize);
3710*0c16b537SWarner Losh                     if (ZSTD_isError(decodedSize)) return decodedSize;
3711*0c16b537SWarner Losh                     zbc->inPos = 0;   /* input is consumed */
3712*0c16b537SWarner Losh                     if (!decodedSize) { zbc->stage = ZBUFFds_read; break; }   /* this was just a header */
3713*0c16b537SWarner Losh                     zbc->outEnd = zbc->outStart +  decodedSize;
3714*0c16b537SWarner Losh                     zbc->stage = ZBUFFds_flush;
3715*0c16b537SWarner Losh                     /* ZBUFFds_flush follows */
3716*0c16b537SWarner Losh                 }
3717*0c16b537SWarner Losh             }
3718*0c16b537SWarner Losh 	    /* fall-through */
3719*0c16b537SWarner Losh         case ZBUFFds_flush:
3720*0c16b537SWarner Losh             {
3721*0c16b537SWarner Losh                 size_t toFlushSize = zbc->outEnd - zbc->outStart;
3722*0c16b537SWarner Losh                 size_t flushedSize = ZBUFF_limitCopy(op, oend-op, zbc->outBuff + zbc->outStart, toFlushSize);
3723*0c16b537SWarner Losh                 op += flushedSize;
3724*0c16b537SWarner Losh                 zbc->outStart += flushedSize;
3725*0c16b537SWarner Losh                 if (flushedSize == toFlushSize)
3726*0c16b537SWarner Losh                 {
3727*0c16b537SWarner Losh                     zbc->stage = ZBUFFds_read;
3728*0c16b537SWarner Losh                     if (zbc->outStart + BLOCKSIZE > zbc->outBuffSize)
3729*0c16b537SWarner Losh                         zbc->outStart = zbc->outEnd = 0;
3730*0c16b537SWarner Losh                     break;
3731*0c16b537SWarner Losh                 }
3732*0c16b537SWarner Losh                 /* cannot flush everything */
3733*0c16b537SWarner Losh                 notDone = 0;
3734*0c16b537SWarner Losh                 break;
3735*0c16b537SWarner Losh             }
3736*0c16b537SWarner Losh         default: return ERROR(GENERIC);   /* impossible */
3737*0c16b537SWarner Losh         }
3738*0c16b537SWarner Losh     }
3739*0c16b537SWarner Losh 
3740*0c16b537SWarner Losh     *srcSizePtr = ip-istart;
3741*0c16b537SWarner Losh     *maxDstSizePtr = op-ostart;
3742*0c16b537SWarner Losh 
3743*0c16b537SWarner Losh     {
3744*0c16b537SWarner Losh         size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zbc->zc);
3745*0c16b537SWarner Losh         if (nextSrcSizeHint > 3) nextSrcSizeHint+= 3;   /* get the next block header while at it */
3746*0c16b537SWarner Losh         nextSrcSizeHint -= zbc->inPos;   /* already loaded*/
3747*0c16b537SWarner Losh         return nextSrcSizeHint;
3748*0c16b537SWarner Losh     }
3749*0c16b537SWarner Losh }
3750*0c16b537SWarner Losh 
3751*0c16b537SWarner Losh 
3752*0c16b537SWarner Losh /* *************************************
3753*0c16b537SWarner Losh *  Tool functions
3754*0c16b537SWarner Losh ***************************************/
3755*0c16b537SWarner Losh unsigned ZBUFFv04_isError(size_t errorCode) { return ERR_isError(errorCode); }
3756*0c16b537SWarner Losh const char* ZBUFFv04_getErrorName(size_t errorCode) { return ERR_getErrorName(errorCode); }
3757*0c16b537SWarner Losh 
3758*0c16b537SWarner Losh size_t ZBUFFv04_recommendedDInSize()  { return BLOCKSIZE + 3; }
3759*0c16b537SWarner Losh size_t ZBUFFv04_recommendedDOutSize() { return BLOCKSIZE; }
3760*0c16b537SWarner Losh 
3761*0c16b537SWarner Losh 
3762*0c16b537SWarner Losh 
3763*0c16b537SWarner Losh /*- ========================================================================= -*/
3764*0c16b537SWarner Losh 
3765*0c16b537SWarner Losh /* final wrapping stage */
3766*0c16b537SWarner Losh 
3767*0c16b537SWarner Losh size_t ZSTDv04_decompressDCtx(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
3768*0c16b537SWarner Losh {
3769*0c16b537SWarner Losh     return ZSTD_decompress_usingDict(dctx, dst, maxDstSize, src, srcSize, NULL, 0);
3770*0c16b537SWarner Losh }
3771*0c16b537SWarner Losh 
3772*0c16b537SWarner Losh size_t ZSTDv04_decompress(void* dst, size_t maxDstSize, const void* src, size_t srcSize)
3773*0c16b537SWarner Losh {
3774*0c16b537SWarner Losh #if defined(ZSTD_HEAPMODE) && (ZSTD_HEAPMODE==1)
3775*0c16b537SWarner Losh     size_t regenSize;
3776*0c16b537SWarner Losh     ZSTD_DCtx* dctx = ZSTD_createDCtx();
3777*0c16b537SWarner Losh     if (dctx==NULL) return ERROR(memory_allocation);
3778*0c16b537SWarner Losh     regenSize = ZSTDv04_decompressDCtx(dctx, dst, maxDstSize, src, srcSize);
3779*0c16b537SWarner Losh     ZSTD_freeDCtx(dctx);
3780*0c16b537SWarner Losh     return regenSize;
3781*0c16b537SWarner Losh #else
3782*0c16b537SWarner Losh     ZSTD_DCtx dctx;
3783*0c16b537SWarner Losh     return ZSTDv04_decompressDCtx(&dctx, dst, maxDstSize, src, srcSize);
3784*0c16b537SWarner Losh #endif
3785*0c16b537SWarner Losh }
3786*0c16b537SWarner Losh 
3787*0c16b537SWarner Losh size_t ZSTDv04_findFrameCompressedSize(const void* src, size_t srcSize)
3788*0c16b537SWarner Losh {
3789*0c16b537SWarner Losh     return ZSTD_findFrameCompressedSize(src, srcSize);
3790*0c16b537SWarner Losh }
3791*0c16b537SWarner Losh 
3792*0c16b537SWarner Losh size_t ZSTDv04_resetDCtx(ZSTDv04_Dctx* dctx) { return ZSTD_resetDCtx(dctx); }
3793*0c16b537SWarner Losh 
3794*0c16b537SWarner Losh size_t ZSTDv04_nextSrcSizeToDecompress(ZSTDv04_Dctx* dctx)
3795*0c16b537SWarner Losh {
3796*0c16b537SWarner Losh     return ZSTD_nextSrcSizeToDecompress(dctx);
3797*0c16b537SWarner Losh }
3798*0c16b537SWarner Losh 
3799*0c16b537SWarner Losh size_t ZSTDv04_decompressContinue(ZSTDv04_Dctx* dctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
3800*0c16b537SWarner Losh {
3801*0c16b537SWarner Losh     return ZSTD_decompressContinue(dctx, dst, maxDstSize, src, srcSize);
3802*0c16b537SWarner Losh }
3803*0c16b537SWarner Losh 
3804*0c16b537SWarner Losh 
3805*0c16b537SWarner Losh 
3806*0c16b537SWarner Losh ZBUFFv04_DCtx* ZBUFFv04_createDCtx(void) { return ZBUFF_createDCtx(); }
3807*0c16b537SWarner Losh size_t      ZBUFFv04_freeDCtx(ZBUFFv04_DCtx* dctx) { return ZBUFF_freeDCtx(dctx); }
3808*0c16b537SWarner Losh 
3809*0c16b537SWarner Losh size_t ZBUFFv04_decompressInit(ZBUFFv04_DCtx* dctx) { return ZBUFF_decompressInit(dctx); }
3810*0c16b537SWarner Losh size_t ZBUFFv04_decompressWithDictionary(ZBUFFv04_DCtx* dctx, const void* src, size_t srcSize)
3811*0c16b537SWarner Losh { return ZBUFF_decompressWithDictionary(dctx, src, srcSize); }
3812*0c16b537SWarner Losh 
3813*0c16b537SWarner Losh size_t ZBUFFv04_decompressContinue(ZBUFFv04_DCtx* dctx, void* dst, size_t* maxDstSizePtr, const void* src, size_t* srcSizePtr)
3814*0c16b537SWarner Losh {
3815*0c16b537SWarner Losh     return ZBUFF_decompressContinue(dctx, dst, maxDstSizePtr, src, srcSizePtr);
3816*0c16b537SWarner Losh }
3817*0c16b537SWarner Losh 
3818*0c16b537SWarner Losh ZSTD_DCtx* ZSTDv04_createDCtx(void) { return ZSTD_createDCtx(); }
3819*0c16b537SWarner Losh size_t ZSTDv04_freeDCtx(ZSTD_DCtx* dctx) { return ZSTD_freeDCtx(dctx); }
3820*0c16b537SWarner Losh 
3821*0c16b537SWarner Losh size_t ZSTDv04_getFrameParams(ZSTD_parameters* params, const void* src, size_t srcSize)
3822*0c16b537SWarner Losh {
3823*0c16b537SWarner Losh     return ZSTD_getFrameParams(params, src, srcSize);
3824*0c16b537SWarner Losh }
3825