1*61145dc2SMartin Matuska // SPDX-License-Identifier: BSD-2-Clause
2eda14cbcSMatt Macy /*
3e92ffd9bSMartin Matuska LZ4 - Fast LZ compression algorithm
4e92ffd9bSMartin Matuska Copyright (C) 2011-present, Yann Collet.
5e92ffd9bSMartin Matuska
6e92ffd9bSMartin Matuska BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
7e92ffd9bSMartin Matuska
8e92ffd9bSMartin Matuska Redistribution and use in source and binary forms, with or without
9e92ffd9bSMartin Matuska modification, are permitted provided that the following conditions are
10e92ffd9bSMartin Matuska met:
11e92ffd9bSMartin Matuska
12e92ffd9bSMartin Matuska * Redistributions of source code must retain the above copyright
13e92ffd9bSMartin Matuska notice, this list of conditions and the following disclaimer.
14e92ffd9bSMartin Matuska * Redistributions in binary form must reproduce the above
15e92ffd9bSMartin Matuska copyright notice, this list of conditions and the following disclaimer
16e92ffd9bSMartin Matuska in the documentation and/or other materials provided with the
17e92ffd9bSMartin Matuska distribution.
18e92ffd9bSMartin Matuska
19e92ffd9bSMartin Matuska THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20e92ffd9bSMartin Matuska "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21e92ffd9bSMartin Matuska LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22e92ffd9bSMartin Matuska A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23e92ffd9bSMartin Matuska OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24e92ffd9bSMartin Matuska SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25e92ffd9bSMartin Matuska LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26e92ffd9bSMartin Matuska DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27e92ffd9bSMartin Matuska THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28e92ffd9bSMartin Matuska (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29e92ffd9bSMartin Matuska OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30e92ffd9bSMartin Matuska
31e92ffd9bSMartin Matuska You can contact the author at :
32e92ffd9bSMartin Matuska - LZ4 homepage : http://www.lz4.org
33e92ffd9bSMartin Matuska - LZ4 source repository : https://github.com/lz4/lz4
34e92ffd9bSMartin Matuska */
35e92ffd9bSMartin Matuska
36e92ffd9bSMartin Matuska /*
37e92ffd9bSMartin Matuska * This file contains unmodified code from lz4 1.9.3's decompressor, plus
38e92ffd9bSMartin Matuska * associated macros and constants.
39eda14cbcSMatt Macy *
40e92ffd9bSMartin Matuska * It also contains a couple of defines from the old lz4.c to make things
41e92ffd9bSMartin Matuska * fit together smoothly.
42eda14cbcSMatt Macy *
43eda14cbcSMatt Macy */
44eda14cbcSMatt Macy
45eda14cbcSMatt Macy #include <sys/zfs_context.h>
46eda14cbcSMatt Macy
47e92ffd9bSMartin Matuska int LZ4_uncompress_unknownOutputSize(const char *source, char *dest,
48eda14cbcSMatt Macy int isize, int maxOutputSize);
49eda14cbcSMatt Macy
50eda14cbcSMatt Macy /*
51eda14cbcSMatt Macy * Tuning parameters
52eda14cbcSMatt Macy */
53eda14cbcSMatt Macy
54eda14cbcSMatt Macy /*
55eda14cbcSMatt Macy * COMPRESSIONLEVEL: Increasing this value improves compression ratio
56eda14cbcSMatt Macy * Lowering this value reduces memory usage. Reduced memory usage
57eda14cbcSMatt Macy * typically improves speed, due to cache effect (ex: L1 32KB for Intel,
58eda14cbcSMatt Macy * L1 64KB for AMD). Memory usage formula : N->2^(N+2) Bytes
59eda14cbcSMatt Macy * (examples : 12 -> 16KB ; 17 -> 512KB)
60eda14cbcSMatt Macy */
61eda14cbcSMatt Macy #define COMPRESSIONLEVEL 12
62eda14cbcSMatt Macy
63eda14cbcSMatt Macy /*
64eda14cbcSMatt Macy * NOTCOMPRESSIBLE_CONFIRMATION: Decreasing this value will make the
65eda14cbcSMatt Macy * algorithm skip faster data segments considered "incompressible".
66eda14cbcSMatt Macy * This may decrease compression ratio dramatically, but will be
67eda14cbcSMatt Macy * faster on incompressible data. Increasing this value will make
68eda14cbcSMatt Macy * the algorithm search more before declaring a segment "incompressible".
69eda14cbcSMatt Macy * This could improve compression a bit, but will be slower on
70eda14cbcSMatt Macy * incompressible data. The default value (6) is recommended.
71eda14cbcSMatt Macy */
72eda14cbcSMatt Macy #define NOTCOMPRESSIBLE_CONFIRMATION 6
73eda14cbcSMatt Macy
74eda14cbcSMatt Macy /*
75eda14cbcSMatt Macy * Little Endian or Big Endian?
76eda14cbcSMatt Macy * Note: overwrite the below #define if you know your architecture endianness.
77eda14cbcSMatt Macy */
78eda14cbcSMatt Macy #if defined(_ZFS_BIG_ENDIAN)
79eda14cbcSMatt Macy #define LZ4_BIG_ENDIAN 1
80eda14cbcSMatt Macy #else
81eda14cbcSMatt Macy /*
82eda14cbcSMatt Macy * Little Endian assumed. PDP Endian and other very rare endian format
83eda14cbcSMatt Macy * are unsupported.
84eda14cbcSMatt Macy */
85eda14cbcSMatt Macy #undef LZ4_BIG_ENDIAN
86eda14cbcSMatt Macy #endif
87eda14cbcSMatt Macy
88e92ffd9bSMartin Matuska /*-************************************
89e92ffd9bSMartin Matuska * CPU Feature Detection
90e92ffd9bSMartin Matuska **************************************/
91e92ffd9bSMartin Matuska /* LZ4_FORCE_MEMORY_ACCESS
92e92ffd9bSMartin Matuska * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.
93e92ffd9bSMartin Matuska * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.
94e92ffd9bSMartin Matuska * The below switch allow to select different access method for improved performance.
95e92ffd9bSMartin Matuska * Method 0 (default) : use `memcpy()`. Safe and portable.
96e92ffd9bSMartin Matuska * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable).
97e92ffd9bSMartin Matuska * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.
98e92ffd9bSMartin Matuska * Method 2 : direct access. This method is portable but violate C standard.
99e92ffd9bSMartin Matuska * It can generate buggy code on targets which assembly generation depends on alignment.
100e92ffd9bSMartin Matuska * But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)
101e92ffd9bSMartin Matuska * See https://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details.
102e92ffd9bSMartin Matuska * Prefer these methods in priority order (0 > 1 > 2)
103eda14cbcSMatt Macy */
104e92ffd9bSMartin Matuska #ifndef LZ4_FORCE_MEMORY_ACCESS /* can be defined externally */
105e92ffd9bSMartin Matuska # if defined(__GNUC__) && \
106e92ffd9bSMartin Matuska ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) \
107e92ffd9bSMartin Matuska || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) )
108e92ffd9bSMartin Matuska # define LZ4_FORCE_MEMORY_ACCESS 2
109e92ffd9bSMartin Matuska # elif (defined(__INTEL_COMPILER) && !defined(_WIN32)) || defined(__GNUC__)
110e92ffd9bSMartin Matuska # define LZ4_FORCE_MEMORY_ACCESS 1
111e92ffd9bSMartin Matuska # endif
112eda14cbcSMatt Macy #endif
113eda14cbcSMatt Macy
114eda14cbcSMatt Macy /*
115e92ffd9bSMartin Matuska * LZ4_FORCE_SW_BITCOUNT
116e92ffd9bSMartin Matuska * Define this parameter if your target system or compiler does not support hardware bit count
117e92ffd9bSMartin Matuska */
118e92ffd9bSMartin Matuska /*
119eda14cbcSMatt Macy * Illumos : we can't use GCC's __builtin_ctz family of builtins in the
120eda14cbcSMatt Macy * kernel
121eda14cbcSMatt Macy * Linux : we can use GCC's __builtin_ctz family of builtins in the
122eda14cbcSMatt Macy * kernel
123eda14cbcSMatt Macy */
124eda14cbcSMatt Macy #undef LZ4_FORCE_SW_BITCOUNT
125e92ffd9bSMartin Matuska #if defined(__sunos__)
126eda14cbcSMatt Macy #define LZ4_FORCE_SW_BITCOUNT
127eda14cbcSMatt Macy #endif
128eda14cbcSMatt Macy
129eda14cbcSMatt Macy /*
130eda14cbcSMatt Macy * Compiler Options
131eda14cbcSMatt Macy */
132eda14cbcSMatt Macy /* Disable restrict */
133eda14cbcSMatt Macy #define restrict
134eda14cbcSMatt Macy
135eda14cbcSMatt Macy /*
136eda14cbcSMatt Macy * Linux : GCC_VERSION is defined as of 3.9-rc1, so undefine it.
137eda14cbcSMatt Macy * torvalds/linux@3f3f8d2f48acfd8ed3b8e6b7377935da57b27b16
138eda14cbcSMatt Macy */
139eda14cbcSMatt Macy #ifdef GCC_VERSION
140eda14cbcSMatt Macy #undef GCC_VERSION
141eda14cbcSMatt Macy #endif
142eda14cbcSMatt Macy
143eda14cbcSMatt Macy #define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
144eda14cbcSMatt Macy
145e92ffd9bSMartin Matuska #ifndef LZ4_FORCE_INLINE
146e92ffd9bSMartin Matuska # ifdef _MSC_VER /* Visual Studio */
147e92ffd9bSMartin Matuska # define LZ4_FORCE_INLINE static __forceinline
148e92ffd9bSMartin Matuska # else
149e92ffd9bSMartin Matuska # if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
150e92ffd9bSMartin Matuska # ifdef __GNUC__
151e92ffd9bSMartin Matuska # define LZ4_FORCE_INLINE static inline __attribute__((always_inline))
152e92ffd9bSMartin Matuska # else
153e92ffd9bSMartin Matuska # define LZ4_FORCE_INLINE static inline
154e92ffd9bSMartin Matuska # endif
155e92ffd9bSMartin Matuska # else
156e92ffd9bSMartin Matuska # define LZ4_FORCE_INLINE static
157e92ffd9bSMartin Matuska # endif /* __STDC_VERSION__ */
158e92ffd9bSMartin Matuska # endif /* _MSC_VER */
159e92ffd9bSMartin Matuska #endif /* LZ4_FORCE_INLINE */
160e92ffd9bSMartin Matuska
161e92ffd9bSMartin Matuska /* LZ4_FORCE_O2 and LZ4_FORCE_INLINE
162e92ffd9bSMartin Matuska * gcc on ppc64le generates an unrolled SIMDized loop for LZ4_wildCopy8,
163e92ffd9bSMartin Matuska * together with a simple 8-byte copy loop as a fall-back path.
164e92ffd9bSMartin Matuska * However, this optimization hurts the decompression speed by >30%,
165e92ffd9bSMartin Matuska * because the execution does not go to the optimized loop
166e92ffd9bSMartin Matuska * for typical compressible data, and all of the preamble checks
167e92ffd9bSMartin Matuska * before going to the fall-back path become useless overhead.
168e92ffd9bSMartin Matuska * This optimization happens only with the -O3 flag, and -O2 generates
169e92ffd9bSMartin Matuska * a simple 8-byte copy loop.
170e92ffd9bSMartin Matuska * With gcc on ppc64le, all of the LZ4_decompress_* and LZ4_wildCopy8
171e92ffd9bSMartin Matuska * functions are annotated with __attribute__((optimize("O2"))),
172e92ffd9bSMartin Matuska * and also LZ4_wildCopy8 is forcibly inlined, so that the O2 attribute
173e92ffd9bSMartin Matuska * of LZ4_wildCopy8 does not affect the compression speed.
174e92ffd9bSMartin Matuska */
175e92ffd9bSMartin Matuska #if defined(__PPC64__) && defined(__LITTLE_ENDIAN__) && defined(__GNUC__) && !defined(__clang__)
176e92ffd9bSMartin Matuska # define LZ4_FORCE_O2 __attribute__((optimize("O2")))
177e92ffd9bSMartin Matuska # undef LZ4_FORCE_INLINE
178e92ffd9bSMartin Matuska # define LZ4_FORCE_INLINE static __inline __attribute__((optimize("O2"),always_inline))
179e92ffd9bSMartin Matuska #else
180e92ffd9bSMartin Matuska # define LZ4_FORCE_O2
181e92ffd9bSMartin Matuska #endif
182e92ffd9bSMartin Matuska
183e92ffd9bSMartin Matuska #ifndef expect
184e92ffd9bSMartin Matuska #if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__)
185eda14cbcSMatt Macy # define expect(expr,value) (__builtin_expect ((expr),(value)) )
186eda14cbcSMatt Macy #else
187eda14cbcSMatt Macy # define expect(expr,value) (expr)
188eda14cbcSMatt Macy #endif
189e92ffd9bSMartin Matuska #endif
190eda14cbcSMatt Macy
191eda14cbcSMatt Macy #ifndef likely
192eda14cbcSMatt Macy #define likely(expr) expect((expr) != 0, 1)
193eda14cbcSMatt Macy #endif
194eda14cbcSMatt Macy
195eda14cbcSMatt Macy #ifndef unlikely
196eda14cbcSMatt Macy #define unlikely(expr) expect((expr) != 0, 0)
197eda14cbcSMatt Macy #endif
198eda14cbcSMatt Macy
199e92ffd9bSMartin Matuska #ifndef _KERNEL
200e92ffd9bSMartin Matuska #include <stdlib.h> /* malloc, calloc, free */
201e92ffd9bSMartin Matuska #include <string.h> /* memset, memcpy */
202eda14cbcSMatt Macy #endif
203e92ffd9bSMartin Matuska #define ALLOC(s) malloc(s)
204e92ffd9bSMartin Matuska #define ALLOC_AND_ZERO(s) calloc(1,s)
205e92ffd9bSMartin Matuska #define FREEMEM(p) free(p)
206eda14cbcSMatt Macy
207e92ffd9bSMartin Matuska #define MEM_INIT(p,v,s) memset((p),(v),(s))
208eda14cbcSMatt Macy
209eda14cbcSMatt Macy
210e92ffd9bSMartin Matuska /*-************************************
211e92ffd9bSMartin Matuska * Common Constants
212e92ffd9bSMartin Matuska **************************************/
213eda14cbcSMatt Macy #define MINMATCH 4
214eda14cbcSMatt Macy
215e92ffd9bSMartin Matuska #define WILDCOPYLENGTH 8
216e92ffd9bSMartin Matuska #define LASTLITERALS 5 /* see ../doc/lz4_Block_format.md#parsing-restrictions */
217e92ffd9bSMartin Matuska #define MFLIMIT 12 /* see ../doc/lz4_Block_format.md#parsing-restrictions */
218e92ffd9bSMartin Matuska #define MATCH_SAFEGUARD_DISTANCE ((2*WILDCOPYLENGTH) - MINMATCH) /* ensure it's possible to write 2 x wildcopyLength without overflowing output buffer */
219e92ffd9bSMartin Matuska #define FASTLOOP_SAFE_DISTANCE 64
220eda14cbcSMatt Macy
221e92ffd9bSMartin Matuska #define KB *(1 <<10)
222e92ffd9bSMartin Matuska #define MB *(1 <<20)
223e92ffd9bSMartin Matuska #define GB *(1U<<30)
224eda14cbcSMatt Macy
225e92ffd9bSMartin Matuska #ifndef LZ4_DISTANCE_MAX /* history window size; can be user-defined at compile time */
226e92ffd9bSMartin Matuska # define LZ4_DISTANCE_MAX 65535 /* set to maximum value by default */
227e92ffd9bSMartin Matuska #endif
228eda14cbcSMatt Macy
229e92ffd9bSMartin Matuska #define LZ4_DISTANCE_ABSOLUTE_MAX 65535
230e92ffd9bSMartin Matuska #if (LZ4_DISTANCE_MAX > LZ4_DISTANCE_ABSOLUTE_MAX) /* max supported by LZ4 format */
231e92ffd9bSMartin Matuska # error "LZ4_DISTANCE_MAX is too big : must be <= 65535"
232e92ffd9bSMartin Matuska #endif
233eda14cbcSMatt Macy
234eda14cbcSMatt Macy #define ML_BITS 4
235eda14cbcSMatt Macy #define ML_MASK ((1U<<ML_BITS)-1)
236eda14cbcSMatt Macy #define RUN_BITS (8-ML_BITS)
237eda14cbcSMatt Macy #define RUN_MASK ((1U<<RUN_BITS)-1)
238eda14cbcSMatt Macy
239e92ffd9bSMartin Matuska #define DEBUGLOG(l, ...) {} /* disabled */
240eda14cbcSMatt Macy
241e92ffd9bSMartin Matuska #ifndef assert
242e92ffd9bSMartin Matuska #define assert ASSERT
243e92ffd9bSMartin Matuska #endif
244e92ffd9bSMartin Matuska
245e92ffd9bSMartin Matuska /*-************************************
246e92ffd9bSMartin Matuska * Types
247e92ffd9bSMartin Matuska **************************************/
248e92ffd9bSMartin Matuska #ifndef _KERNEL
249e92ffd9bSMartin Matuska #include <limits.h>
250e92ffd9bSMartin Matuska #endif
251e92ffd9bSMartin Matuska #if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
252e92ffd9bSMartin Matuska #ifndef _KERNEL
253e92ffd9bSMartin Matuska #include <stdint.h>
254e92ffd9bSMartin Matuska #endif
255e92ffd9bSMartin Matuska typedef uint8_t BYTE;
256e92ffd9bSMartin Matuska typedef uint16_t U16;
257e92ffd9bSMartin Matuska typedef uint32_t U32;
258e92ffd9bSMartin Matuska typedef int32_t S32;
259e92ffd9bSMartin Matuska typedef uint64_t U64;
260e92ffd9bSMartin Matuska typedef uintptr_t uptrval;
261e92ffd9bSMartin Matuska #else
262e92ffd9bSMartin Matuska # if UINT_MAX != 4294967295UL
263e92ffd9bSMartin Matuska # error "LZ4 code (when not C++ or C99) assumes that sizeof(int) == 4"
264e92ffd9bSMartin Matuska # endif
265e92ffd9bSMartin Matuska typedef unsigned char BYTE;
266e92ffd9bSMartin Matuska typedef unsigned short U16;
267e92ffd9bSMartin Matuska typedef unsigned int U32;
268e92ffd9bSMartin Matuska typedef signed int S32;
269e92ffd9bSMartin Matuska typedef unsigned long long U64;
270e92ffd9bSMartin Matuska typedef size_t uptrval; /* generally true, except OpenVMS-64 */
271e92ffd9bSMartin Matuska #endif
272e92ffd9bSMartin Matuska
273e92ffd9bSMartin Matuska #if defined(__x86_64__)
274e92ffd9bSMartin Matuska typedef U64 reg_t; /* 64-bits in x32 mode */
275e92ffd9bSMartin Matuska #else
276e92ffd9bSMartin Matuska typedef size_t reg_t; /* 32-bits in x32 mode */
277e92ffd9bSMartin Matuska #endif
278e92ffd9bSMartin Matuska
279e92ffd9bSMartin Matuska typedef enum {
280e92ffd9bSMartin Matuska notLimited = 0,
281e92ffd9bSMartin Matuska limitedOutput = 1,
282e92ffd9bSMartin Matuska fillOutput = 2
283e92ffd9bSMartin Matuska } limitedOutput_directive;
284e92ffd9bSMartin Matuska
285e92ffd9bSMartin Matuska
286e92ffd9bSMartin Matuska /*-************************************
287e92ffd9bSMartin Matuska * Reading and writing into memory
288e92ffd9bSMartin Matuska **************************************/
289e92ffd9bSMartin Matuska
290e92ffd9bSMartin Matuska /**
291e92ffd9bSMartin Matuska * LZ4 relies on memcpy with a constant size being inlined. In freestanding
292e92ffd9bSMartin Matuska * environments, the compiler can't assume the implementation of memcpy() is
293e92ffd9bSMartin Matuska * standard compliant, so it can't apply its specialized memcpy() inlining
294e92ffd9bSMartin Matuska * logic. When possible, use __builtin_memcpy() to tell the compiler to analyze
295e92ffd9bSMartin Matuska * memcpy() as if it were standard compliant, so it can inline it in freestanding
296e92ffd9bSMartin Matuska * environments. This is needed when decompressing the Linux Kernel, for example.
297eda14cbcSMatt Macy */
298e92ffd9bSMartin Matuska #if defined(__GNUC__) && (__GNUC__ >= 4)
299e92ffd9bSMartin Matuska #define LZ4_memcpy(dst, src, size) __builtin_memcpy(dst, src, size)
300eda14cbcSMatt Macy #else
301e92ffd9bSMartin Matuska #define LZ4_memcpy(dst, src, size) memcpy(dst, src, size)
302eda14cbcSMatt Macy #endif
303eda14cbcSMatt Macy
LZ4_isLittleEndian(void)304e92ffd9bSMartin Matuska static unsigned LZ4_isLittleEndian(void)
305eda14cbcSMatt Macy {
306e92ffd9bSMartin Matuska const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */
307e92ffd9bSMartin Matuska return one.c[0];
308eda14cbcSMatt Macy }
309eda14cbcSMatt Macy
310eda14cbcSMatt Macy
311e92ffd9bSMartin Matuska #if defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==2)
312e92ffd9bSMartin Matuska /* lie to the compiler about data alignment; use with caution */
313e92ffd9bSMartin Matuska
LZ4_read16(const void * memPtr)314e92ffd9bSMartin Matuska static U16 LZ4_read16(const void* memPtr) { return *(const U16*) memPtr; }
315e92ffd9bSMartin Matuska
LZ4_write16(void * memPtr,U16 value)316e92ffd9bSMartin Matuska static void LZ4_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; }
LZ4_write32(void * memPtr,U32 value)317e92ffd9bSMartin Matuska static void LZ4_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; }
318e92ffd9bSMartin Matuska
319e92ffd9bSMartin Matuska #elif defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==1)
320e92ffd9bSMartin Matuska
321e92ffd9bSMartin Matuska /* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
322e92ffd9bSMartin Matuska /* currently only defined for gcc and icc */
323e92ffd9bSMartin Matuska typedef union { U16 u16; U32 u32; reg_t uArch; } __attribute__((packed)) unalign;
324e92ffd9bSMartin Matuska
LZ4_read16(const void * ptr)325e92ffd9bSMartin Matuska static U16 LZ4_read16(const void* ptr) { return ((const unalign*)ptr)->u16; }
326e92ffd9bSMartin Matuska
LZ4_write32(void * memPtr,U32 value)327e92ffd9bSMartin Matuska static void LZ4_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = value; }
328e92ffd9bSMartin Matuska
329e92ffd9bSMartin Matuska #else /* safe and portable access using memcpy() */
330e92ffd9bSMartin Matuska
LZ4_read16(const void * memPtr)331e92ffd9bSMartin Matuska static U16 LZ4_read16(const void* memPtr)
332eda14cbcSMatt Macy {
333e92ffd9bSMartin Matuska U16 val; LZ4_memcpy(&val, memPtr, sizeof(val)); return val;
334eda14cbcSMatt Macy }
335eda14cbcSMatt Macy
LZ4_write32(void * memPtr,U32 value)336e92ffd9bSMartin Matuska static void LZ4_write32(void* memPtr, U32 value)
337eda14cbcSMatt Macy {
338e92ffd9bSMartin Matuska LZ4_memcpy(memPtr, &value, sizeof(value));
339eda14cbcSMatt Macy }
340eda14cbcSMatt Macy
341e92ffd9bSMartin Matuska #endif /* LZ4_FORCE_MEMORY_ACCESS */
342eda14cbcSMatt Macy
LZ4_readLE16(const void * memPtr)343e92ffd9bSMartin Matuska static U16 LZ4_readLE16(const void* memPtr)
344e92ffd9bSMartin Matuska {
345e92ffd9bSMartin Matuska if (LZ4_isLittleEndian()) {
346e92ffd9bSMartin Matuska return LZ4_read16(memPtr);
347e92ffd9bSMartin Matuska } else {
348e92ffd9bSMartin Matuska const BYTE* p = (const BYTE*)memPtr;
349e92ffd9bSMartin Matuska return (U16)((U16)p[0] + (p[1]<<8));
350e92ffd9bSMartin Matuska }
351eda14cbcSMatt Macy }
352eda14cbcSMatt Macy
353e92ffd9bSMartin Matuska /* customized variant of memcpy, which can overwrite up to 8 bytes beyond dstEnd */
354e92ffd9bSMartin Matuska LZ4_FORCE_INLINE
LZ4_wildCopy8(void * dstPtr,const void * srcPtr,void * dstEnd)355e92ffd9bSMartin Matuska void LZ4_wildCopy8(void* dstPtr, const void* srcPtr, void* dstEnd)
356e92ffd9bSMartin Matuska {
357e92ffd9bSMartin Matuska BYTE* d = (BYTE*)dstPtr;
358e92ffd9bSMartin Matuska const BYTE* s = (const BYTE*)srcPtr;
359e92ffd9bSMartin Matuska BYTE* const e = (BYTE*)dstEnd;
360eda14cbcSMatt Macy
361e92ffd9bSMartin Matuska do { LZ4_memcpy(d,s,8); d+=8; s+=8; } while (d<e);
362eda14cbcSMatt Macy }
363e92ffd9bSMartin Matuska
364e92ffd9bSMartin Matuska static const unsigned inc32table[8] = {0, 1, 2, 1, 0, 4, 4, 4};
365e92ffd9bSMartin Matuska static const int dec64table[8] = {0, 0, 0, -1, -4, 1, 2, 3};
366e92ffd9bSMartin Matuska
367e92ffd9bSMartin Matuska
368e92ffd9bSMartin Matuska #ifndef LZ4_FAST_DEC_LOOP
369e92ffd9bSMartin Matuska # if defined __i386__ || defined _M_IX86 || defined __x86_64__ || defined _M_X64
370e92ffd9bSMartin Matuska # define LZ4_FAST_DEC_LOOP 1
371e92ffd9bSMartin Matuska # elif defined(__aarch64__) && !defined(__clang__)
372e92ffd9bSMartin Matuska /* On aarch64, we disable this optimization for clang because on certain
373e92ffd9bSMartin Matuska * mobile chipsets, performance is reduced with clang. For information
374e92ffd9bSMartin Matuska * refer to https://github.com/lz4/lz4/pull/707 */
375e92ffd9bSMartin Matuska # define LZ4_FAST_DEC_LOOP 1
376e92ffd9bSMartin Matuska # else
377e92ffd9bSMartin Matuska # define LZ4_FAST_DEC_LOOP 0
378eda14cbcSMatt Macy # endif
379e92ffd9bSMartin Matuska #endif
380eda14cbcSMatt Macy
381e92ffd9bSMartin Matuska #if LZ4_FAST_DEC_LOOP
382eda14cbcSMatt Macy
383e92ffd9bSMartin Matuska LZ4_FORCE_INLINE void
LZ4_memcpy_using_offset_base(BYTE * dstPtr,const BYTE * srcPtr,BYTE * dstEnd,const size_t offset)384e92ffd9bSMartin Matuska LZ4_memcpy_using_offset_base(BYTE* dstPtr, const BYTE* srcPtr, BYTE* dstEnd, const size_t offset)
385e92ffd9bSMartin Matuska {
386e92ffd9bSMartin Matuska assert(srcPtr + offset == dstPtr);
387e92ffd9bSMartin Matuska if (offset < 8) {
388e92ffd9bSMartin Matuska LZ4_write32(dstPtr, 0); /* silence an msan warning when offset==0 */
389e92ffd9bSMartin Matuska dstPtr[0] = srcPtr[0];
390e92ffd9bSMartin Matuska dstPtr[1] = srcPtr[1];
391e92ffd9bSMartin Matuska dstPtr[2] = srcPtr[2];
392e92ffd9bSMartin Matuska dstPtr[3] = srcPtr[3];
393e92ffd9bSMartin Matuska srcPtr += inc32table[offset];
394e92ffd9bSMartin Matuska LZ4_memcpy(dstPtr+4, srcPtr, 4);
395e92ffd9bSMartin Matuska srcPtr -= dec64table[offset];
396e92ffd9bSMartin Matuska dstPtr += 8;
397e92ffd9bSMartin Matuska } else {
398e92ffd9bSMartin Matuska LZ4_memcpy(dstPtr, srcPtr, 8);
399e92ffd9bSMartin Matuska dstPtr += 8;
400e92ffd9bSMartin Matuska srcPtr += 8;
401e92ffd9bSMartin Matuska }
402e92ffd9bSMartin Matuska
403e92ffd9bSMartin Matuska LZ4_wildCopy8(dstPtr, srcPtr, dstEnd);
404e92ffd9bSMartin Matuska }
405e92ffd9bSMartin Matuska
406e92ffd9bSMartin Matuska /* customized variant of memcpy, which can overwrite up to 32 bytes beyond dstEnd
407e92ffd9bSMartin Matuska * this version copies two times 16 bytes (instead of one time 32 bytes)
408e92ffd9bSMartin Matuska * because it must be compatible with offsets >= 16. */
409e92ffd9bSMartin Matuska LZ4_FORCE_INLINE void
LZ4_wildCopy32(void * dstPtr,const void * srcPtr,void * dstEnd)410e92ffd9bSMartin Matuska LZ4_wildCopy32(void* dstPtr, const void* srcPtr, void* dstEnd)
411e92ffd9bSMartin Matuska {
412e92ffd9bSMartin Matuska BYTE* d = (BYTE*)dstPtr;
413e92ffd9bSMartin Matuska const BYTE* s = (const BYTE*)srcPtr;
414e92ffd9bSMartin Matuska BYTE* const e = (BYTE*)dstEnd;
415e92ffd9bSMartin Matuska
416e92ffd9bSMartin Matuska do { LZ4_memcpy(d,s,16); LZ4_memcpy(d+16,s+16,16); d+=32; s+=32; } while (d<e);
417e92ffd9bSMartin Matuska }
418e92ffd9bSMartin Matuska
419e92ffd9bSMartin Matuska /* LZ4_memcpy_using_offset() presumes :
420e92ffd9bSMartin Matuska * - dstEnd >= dstPtr + MINMATCH
421e92ffd9bSMartin Matuska * - there is at least 8 bytes available to write after dstEnd */
422e92ffd9bSMartin Matuska LZ4_FORCE_INLINE void
LZ4_memcpy_using_offset(BYTE * dstPtr,const BYTE * srcPtr,BYTE * dstEnd,const size_t offset)423e92ffd9bSMartin Matuska LZ4_memcpy_using_offset(BYTE* dstPtr, const BYTE* srcPtr, BYTE* dstEnd, const size_t offset)
424e92ffd9bSMartin Matuska {
425e92ffd9bSMartin Matuska BYTE v[8];
426e92ffd9bSMartin Matuska
427e92ffd9bSMartin Matuska assert(dstEnd >= dstPtr + MINMATCH);
428e92ffd9bSMartin Matuska
429e92ffd9bSMartin Matuska switch(offset) {
430e92ffd9bSMartin Matuska case 1:
431e92ffd9bSMartin Matuska MEM_INIT(v, *srcPtr, 8);
432eda14cbcSMatt Macy break;
433e92ffd9bSMartin Matuska case 2:
434e92ffd9bSMartin Matuska LZ4_memcpy(v, srcPtr, 2);
435e92ffd9bSMartin Matuska LZ4_memcpy(&v[2], srcPtr, 2);
436e92ffd9bSMartin Matuska LZ4_memcpy(&v[4], v, 4);
437e92ffd9bSMartin Matuska break;
438e92ffd9bSMartin Matuska case 4:
439e92ffd9bSMartin Matuska LZ4_memcpy(v, srcPtr, 4);
440e92ffd9bSMartin Matuska LZ4_memcpy(&v[4], srcPtr, 4);
441e92ffd9bSMartin Matuska break;
442e92ffd9bSMartin Matuska default:
443e92ffd9bSMartin Matuska LZ4_memcpy_using_offset_base(dstPtr, srcPtr, dstEnd, offset);
444e92ffd9bSMartin Matuska return;
445eda14cbcSMatt Macy }
446eda14cbcSMatt Macy
447e92ffd9bSMartin Matuska LZ4_memcpy(dstPtr, v, 8);
448e92ffd9bSMartin Matuska dstPtr += 8;
449e92ffd9bSMartin Matuska while (dstPtr < dstEnd) {
450e92ffd9bSMartin Matuska LZ4_memcpy(dstPtr, v, 8);
451e92ffd9bSMartin Matuska dstPtr += 8;
452eda14cbcSMatt Macy }
453eda14cbcSMatt Macy }
454eda14cbcSMatt Macy #endif
455eda14cbcSMatt Macy
456eda14cbcSMatt Macy
457e92ffd9bSMartin Matuska /*-************************************
458e92ffd9bSMartin Matuska * Local Structures and types
459e92ffd9bSMartin Matuska **************************************/
460e92ffd9bSMartin Matuska typedef enum { clearedTable = 0, byPtr, byU32, byU16 } tableType_t;
461eda14cbcSMatt Macy
462e92ffd9bSMartin Matuska /**
463e92ffd9bSMartin Matuska * This enum distinguishes several different modes of accessing previous
464e92ffd9bSMartin Matuska * content in the stream.
465eda14cbcSMatt Macy *
466e92ffd9bSMartin Matuska * - noDict : There is no preceding content.
467e92ffd9bSMartin Matuska * - withPrefix64k : Table entries up to ctx->dictSize before the current blob
468e92ffd9bSMartin Matuska * blob being compressed are valid and refer to the preceding
469e92ffd9bSMartin Matuska * content (of length ctx->dictSize), which is available
470e92ffd9bSMartin Matuska * contiguously preceding in memory the content currently
471e92ffd9bSMartin Matuska * being compressed.
472e92ffd9bSMartin Matuska * - usingExtDict : Like withPrefix64k, but the preceding content is somewhere
473e92ffd9bSMartin Matuska * else in memory, starting at ctx->dictionary with length
474e92ffd9bSMartin Matuska * ctx->dictSize.
475e92ffd9bSMartin Matuska * - usingDictCtx : Like usingExtDict, but everything concerning the preceding
476e92ffd9bSMartin Matuska * content is in a separate context, pointed to by
477e92ffd9bSMartin Matuska * ctx->dictCtx. ctx->dictionary, ctx->dictSize, and table
478e92ffd9bSMartin Matuska * entries in the current context that refer to positions
479e92ffd9bSMartin Matuska * preceding the beginning of the current compression are
480e92ffd9bSMartin Matuska * ignored. Instead, ctx->dictCtx->dictionary and ctx->dictCtx
481e92ffd9bSMartin Matuska * ->dictSize describe the location and size of the preceding
482e92ffd9bSMartin Matuska * content, and matches are found by looking in the ctx
483e92ffd9bSMartin Matuska * ->dictCtx->hashTable.
484eda14cbcSMatt Macy */
485e92ffd9bSMartin Matuska typedef enum { noDict = 0, withPrefix64k, usingExtDict, usingDictCtx } dict_directive;
486e92ffd9bSMartin Matuska typedef enum { noDictIssue = 0, dictSmall } dictIssue_directive;
487eda14cbcSMatt Macy
488e92ffd9bSMartin Matuska /*-*******************************
489e92ffd9bSMartin Matuska * Decompression functions
490e92ffd9bSMartin Matuska ********************************/
491eda14cbcSMatt Macy
492e92ffd9bSMartin Matuska typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive;
493e92ffd9bSMartin Matuska typedef enum { decode_full_block = 0, partial_decode = 1 } earlyEnd_directive;
494e92ffd9bSMartin Matuska
495e92ffd9bSMartin Matuska typedef enum { loop_error = -2, initial_error = -1, ok = 0 } variable_length_error;
496e92ffd9bSMartin Matuska
497e92ffd9bSMartin Matuska LZ4_FORCE_INLINE unsigned
read_variable_length(const BYTE ** ip,const BYTE * lencheck,int loop_check,int initial_check,variable_length_error * error)498e92ffd9bSMartin Matuska read_variable_length(const BYTE**ip, const BYTE* lencheck,
499e92ffd9bSMartin Matuska int loop_check, int initial_check,
500e92ffd9bSMartin Matuska variable_length_error* error)
501eda14cbcSMatt Macy {
502e92ffd9bSMartin Matuska U32 length = 0;
503e92ffd9bSMartin Matuska U32 s;
504e92ffd9bSMartin Matuska if (initial_check && unlikely((*ip) >= lencheck)) { /* overflow detection */
505e92ffd9bSMartin Matuska *error = initial_error;
506e92ffd9bSMartin Matuska return length;
507e92ffd9bSMartin Matuska }
508e92ffd9bSMartin Matuska do {
509e92ffd9bSMartin Matuska s = **ip;
510e92ffd9bSMartin Matuska (*ip)++;
511e92ffd9bSMartin Matuska length += s;
512e92ffd9bSMartin Matuska if (loop_check && unlikely((*ip) >= lencheck)) { /* overflow detection */
513e92ffd9bSMartin Matuska *error = loop_error;
514e92ffd9bSMartin Matuska return length;
515e92ffd9bSMartin Matuska }
516e92ffd9bSMartin Matuska } while (s==255);
517eda14cbcSMatt Macy
518e92ffd9bSMartin Matuska return length;
519e92ffd9bSMartin Matuska }
520e92ffd9bSMartin Matuska
521e92ffd9bSMartin Matuska #define LZ4_STATIC_ASSERT(c) ASSERT(c)
522e92ffd9bSMartin Matuska
523e92ffd9bSMartin Matuska
524e92ffd9bSMartin Matuska /*! LZ4_decompress_generic() :
525e92ffd9bSMartin Matuska * This generic decompression function covers all use cases.
526e92ffd9bSMartin Matuska * It shall be instantiated several times, using different sets of directives.
527e92ffd9bSMartin Matuska * Note that it is important for performance that this function really get inlined,
528e92ffd9bSMartin Matuska * in order to remove useless branches during compilation optimization.
529e92ffd9bSMartin Matuska */
530e92ffd9bSMartin Matuska LZ4_FORCE_INLINE int
LZ4_decompress_generic(const char * const src,char * const dst,int srcSize,int outputSize,endCondition_directive endOnInput,earlyEnd_directive partialDecoding,dict_directive dict,const BYTE * const lowPrefix,const BYTE * const dictStart,const size_t dictSize)531e92ffd9bSMartin Matuska LZ4_decompress_generic(
532e92ffd9bSMartin Matuska const char* const src,
533e92ffd9bSMartin Matuska char* const dst,
534e92ffd9bSMartin Matuska int srcSize,
535e92ffd9bSMartin Matuska int outputSize, /* If endOnInput==endOnInputSize, this value is `dstCapacity` */
536e92ffd9bSMartin Matuska
537e92ffd9bSMartin Matuska endCondition_directive endOnInput, /* endOnOutputSize, endOnInputSize */
538e92ffd9bSMartin Matuska earlyEnd_directive partialDecoding, /* full, partial */
539e92ffd9bSMartin Matuska dict_directive dict, /* noDict, withPrefix64k, usingExtDict */
540e92ffd9bSMartin Matuska const BYTE* const lowPrefix, /* always <= dst, == dst when no prefix */
541e92ffd9bSMartin Matuska const BYTE* const dictStart, /* only if dict==usingExtDict */
542e92ffd9bSMartin Matuska const size_t dictSize /* note : = 0 if noDict */
543e92ffd9bSMartin Matuska )
544e92ffd9bSMartin Matuska {
545e92ffd9bSMartin Matuska if ((src == NULL) || (outputSize < 0)) { return -1; }
546e92ffd9bSMartin Matuska
547e92ffd9bSMartin Matuska { const BYTE* ip = (const BYTE*) src;
548e92ffd9bSMartin Matuska const BYTE* const iend = ip + srcSize;
549e92ffd9bSMartin Matuska
550e92ffd9bSMartin Matuska BYTE* op = (BYTE*) dst;
551e92ffd9bSMartin Matuska BYTE* const oend = op + outputSize;
552eda14cbcSMatt Macy BYTE* cpy;
553eda14cbcSMatt Macy
554e92ffd9bSMartin Matuska const BYTE* const dictEnd = (dictStart == NULL) ? NULL : dictStart + dictSize;
555e92ffd9bSMartin Matuska
556e92ffd9bSMartin Matuska const int safeDecode = (endOnInput==endOnInputSize);
557e92ffd9bSMartin Matuska const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB)));
558e92ffd9bSMartin Matuska
559e92ffd9bSMartin Matuska
560e92ffd9bSMartin Matuska /* Set up the "end" pointers for the shortcut. */
561e92ffd9bSMartin Matuska const BYTE* const shortiend = iend - (endOnInput ? 14 : 8) /*maxLL*/ - 2 /*offset*/;
562e92ffd9bSMartin Matuska const BYTE* const shortoend = oend - (endOnInput ? 14 : 8) /*maxLL*/ - 18 /*maxML*/;
563e92ffd9bSMartin Matuska
564e92ffd9bSMartin Matuska const BYTE* match;
565e92ffd9bSMartin Matuska size_t offset;
566eda14cbcSMatt Macy unsigned token;
567eda14cbcSMatt Macy size_t length;
568eda14cbcSMatt Macy
569e92ffd9bSMartin Matuska
570e92ffd9bSMartin Matuska DEBUGLOG(5, "LZ4_decompress_generic (srcSize:%i, dstSize:%i)", srcSize, outputSize);
571e92ffd9bSMartin Matuska
572e92ffd9bSMartin Matuska /* Special cases */
573e92ffd9bSMartin Matuska assert(lowPrefix <= op);
574e92ffd9bSMartin Matuska if ((endOnInput) && (unlikely(outputSize==0))) {
575e92ffd9bSMartin Matuska /* Empty output buffer */
576e92ffd9bSMartin Matuska if (partialDecoding) return 0;
577e92ffd9bSMartin Matuska return ((srcSize==1) && (*ip==0)) ? 0 : -1;
578e92ffd9bSMartin Matuska }
579e92ffd9bSMartin Matuska if ((!endOnInput) && (unlikely(outputSize==0))) { return (*ip==0 ? 1 : -1); }
580e92ffd9bSMartin Matuska if ((endOnInput) && unlikely(srcSize==0)) { return -1; }
581e92ffd9bSMartin Matuska
582e92ffd9bSMartin Matuska /* Currently the fast loop shows a regression on qualcomm arm chips. */
583e92ffd9bSMartin Matuska #if LZ4_FAST_DEC_LOOP
584e92ffd9bSMartin Matuska if ((oend - op) < FASTLOOP_SAFE_DISTANCE) {
585e92ffd9bSMartin Matuska DEBUGLOG(6, "skip fast decode loop");
586e92ffd9bSMartin Matuska goto safe_decode;
587e92ffd9bSMartin Matuska }
588e92ffd9bSMartin Matuska
589e92ffd9bSMartin Matuska /* Fast loop : decode sequences as long as output < iend-FASTLOOP_SAFE_DISTANCE */
590e92ffd9bSMartin Matuska while (1) {
591e92ffd9bSMartin Matuska /* Main fastloop assertion: We can always wildcopy FASTLOOP_SAFE_DISTANCE */
592e92ffd9bSMartin Matuska assert(oend - op >= FASTLOOP_SAFE_DISTANCE);
593e92ffd9bSMartin Matuska if (endOnInput) { assert(ip < iend); }
594eda14cbcSMatt Macy token = *ip++;
595e92ffd9bSMartin Matuska length = token >> ML_BITS; /* literal length */
596e92ffd9bSMartin Matuska
597e92ffd9bSMartin Matuska assert(!endOnInput || ip <= iend); /* ip < iend before the increment */
598e92ffd9bSMartin Matuska
599e92ffd9bSMartin Matuska /* decode literal length */
600e92ffd9bSMartin Matuska if (length == RUN_MASK) {
601e92ffd9bSMartin Matuska variable_length_error error = ok;
602e92ffd9bSMartin Matuska length += read_variable_length(&ip, iend-RUN_MASK, (int)endOnInput, (int)endOnInput, &error);
603e92ffd9bSMartin Matuska if (error == initial_error) { goto _output_error; }
604e92ffd9bSMartin Matuska if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)(op))) { goto _output_error; } /* overflow detection */
605e92ffd9bSMartin Matuska if ((safeDecode) && unlikely((uptrval)(ip)+length<(uptrval)(ip))) { goto _output_error; } /* overflow detection */
606e92ffd9bSMartin Matuska
607eda14cbcSMatt Macy /* copy literals */
608eda14cbcSMatt Macy cpy = op+length;
609e92ffd9bSMartin Matuska LZ4_STATIC_ASSERT(MFLIMIT >= WILDCOPYLENGTH);
610e92ffd9bSMartin Matuska if (endOnInput) { /* LZ4_decompress_safe() */
611e92ffd9bSMartin Matuska if ((cpy>oend-32) || (ip+length>iend-32)) { goto safe_literal_copy; }
612e92ffd9bSMartin Matuska LZ4_wildCopy32(op, ip, cpy);
613e92ffd9bSMartin Matuska } else { /* LZ4_decompress_fast() */
614e92ffd9bSMartin Matuska if (cpy>oend-8) { goto safe_literal_copy; }
615e92ffd9bSMartin Matuska LZ4_wildCopy8(op, ip, cpy); /* LZ4_decompress_fast() cannot copy more than 8 bytes at a time :
616e92ffd9bSMartin Matuska * it doesn't know input length, and only relies on end-of-block properties */
617eda14cbcSMatt Macy }
618e92ffd9bSMartin Matuska ip += length; op = cpy;
619e92ffd9bSMartin Matuska } else {
620e92ffd9bSMartin Matuska cpy = op+length;
621e92ffd9bSMartin Matuska if (endOnInput) { /* LZ4_decompress_safe() */
622e92ffd9bSMartin Matuska DEBUGLOG(7, "copy %u bytes in a 16-bytes stripe", (unsigned)length);
623e92ffd9bSMartin Matuska /* We don't need to check oend, since we check it once for each loop below */
624e92ffd9bSMartin Matuska if (ip > iend-(16 + 1/*max lit + offset + nextToken*/)) { goto safe_literal_copy; }
625e92ffd9bSMartin Matuska /* Literals can only be 14, but hope compilers optimize if we copy by a register size */
626e92ffd9bSMartin Matuska LZ4_memcpy(op, ip, 16);
627e92ffd9bSMartin Matuska } else { /* LZ4_decompress_fast() */
628e92ffd9bSMartin Matuska /* LZ4_decompress_fast() cannot copy more than 8 bytes at a time :
629e92ffd9bSMartin Matuska * it doesn't know input length, and relies on end-of-block properties */
630e92ffd9bSMartin Matuska LZ4_memcpy(op, ip, 8);
631e92ffd9bSMartin Matuska if (length > 8) { LZ4_memcpy(op+8, ip+8, 8); }
632e92ffd9bSMartin Matuska }
633e92ffd9bSMartin Matuska ip += length; op = cpy;
634e92ffd9bSMartin Matuska }
635eda14cbcSMatt Macy
636eda14cbcSMatt Macy /* get offset */
637e92ffd9bSMartin Matuska offset = LZ4_readLE16(ip); ip+=2;
638e92ffd9bSMartin Matuska match = op - offset;
639e92ffd9bSMartin Matuska assert(match <= op);
640eda14cbcSMatt Macy
641eda14cbcSMatt Macy /* get matchlength */
642e92ffd9bSMartin Matuska length = token & ML_MASK;
643e92ffd9bSMartin Matuska
644e92ffd9bSMartin Matuska if (length == ML_MASK) {
645e92ffd9bSMartin Matuska variable_length_error error = ok;
646e92ffd9bSMartin Matuska if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) { goto _output_error; } /* Error : offset outside buffers */
647e92ffd9bSMartin Matuska length += read_variable_length(&ip, iend - LASTLITERALS + 1, (int)endOnInput, 0, &error);
648e92ffd9bSMartin Matuska if (error != ok) { goto _output_error; }
649e92ffd9bSMartin Matuska if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)op)) { goto _output_error; } /* overflow detection */
650e92ffd9bSMartin Matuska length += MINMATCH;
651e92ffd9bSMartin Matuska if (op + length >= oend - FASTLOOP_SAFE_DISTANCE) {
652e92ffd9bSMartin Matuska goto safe_match_copy;
653e92ffd9bSMartin Matuska }
654e92ffd9bSMartin Matuska } else {
655e92ffd9bSMartin Matuska length += MINMATCH;
656e92ffd9bSMartin Matuska if (op + length >= oend - FASTLOOP_SAFE_DISTANCE) {
657e92ffd9bSMartin Matuska goto safe_match_copy;
658e92ffd9bSMartin Matuska }
659e92ffd9bSMartin Matuska
660e92ffd9bSMartin Matuska /* Fastpath check: Avoids a branch in LZ4_wildCopy32 if true */
661e92ffd9bSMartin Matuska if ((dict == withPrefix64k) || (match >= lowPrefix)) {
662e92ffd9bSMartin Matuska if (offset >= 8) {
663e92ffd9bSMartin Matuska assert(match >= lowPrefix);
664e92ffd9bSMartin Matuska assert(match <= op);
665e92ffd9bSMartin Matuska assert(op + 18 <= oend);
666e92ffd9bSMartin Matuska
667e92ffd9bSMartin Matuska LZ4_memcpy(op, match, 8);
668e92ffd9bSMartin Matuska LZ4_memcpy(op+8, match+8, 8);
669e92ffd9bSMartin Matuska LZ4_memcpy(op+16, match+16, 2);
670e92ffd9bSMartin Matuska op += length;
671eda14cbcSMatt Macy continue;
672e92ffd9bSMartin Matuska } } }
673e92ffd9bSMartin Matuska
674e92ffd9bSMartin Matuska if (checkOffset && (unlikely(match + dictSize < lowPrefix))) { goto _output_error; } /* Error : offset outside buffers */
675e92ffd9bSMartin Matuska /* match starting within external dictionary */
676e92ffd9bSMartin Matuska if ((dict==usingExtDict) && (match < lowPrefix)) {
677e92ffd9bSMartin Matuska if (unlikely(op+length > oend-LASTLITERALS)) {
678e92ffd9bSMartin Matuska if (partialDecoding) {
679e92ffd9bSMartin Matuska DEBUGLOG(7, "partialDecoding: dictionary match, close to dstEnd");
680e92ffd9bSMartin Matuska length = MIN(length, (size_t)(oend-op));
681e92ffd9bSMartin Matuska } else {
682e92ffd9bSMartin Matuska goto _output_error; /* end-of-block condition violated */
683e92ffd9bSMartin Matuska } }
684e92ffd9bSMartin Matuska
685e92ffd9bSMartin Matuska if (length <= (size_t)(lowPrefix-match)) {
686e92ffd9bSMartin Matuska /* match fits entirely within external dictionary : just copy */
687e92ffd9bSMartin Matuska memmove(op, dictEnd - (lowPrefix-match), length);
688e92ffd9bSMartin Matuska op += length;
689e92ffd9bSMartin Matuska } else {
690e92ffd9bSMartin Matuska /* match stretches into both external dictionary and current block */
691e92ffd9bSMartin Matuska size_t const copySize = (size_t)(lowPrefix - match);
692e92ffd9bSMartin Matuska size_t const restSize = length - copySize;
693e92ffd9bSMartin Matuska LZ4_memcpy(op, dictEnd - copySize, copySize);
694e92ffd9bSMartin Matuska op += copySize;
695e92ffd9bSMartin Matuska if (restSize > (size_t)(op - lowPrefix)) { /* overlap copy */
696e92ffd9bSMartin Matuska BYTE* const endOfMatch = op + restSize;
697e92ffd9bSMartin Matuska const BYTE* copyFrom = lowPrefix;
698e92ffd9bSMartin Matuska while (op < endOfMatch) { *op++ = *copyFrom++; }
699e92ffd9bSMartin Matuska } else {
700e92ffd9bSMartin Matuska LZ4_memcpy(op, lowPrefix, restSize);
701e92ffd9bSMartin Matuska op += restSize;
702e92ffd9bSMartin Matuska } }
703e92ffd9bSMartin Matuska continue;
704e92ffd9bSMartin Matuska }
705e92ffd9bSMartin Matuska
706e92ffd9bSMartin Matuska /* copy match within block */
707e92ffd9bSMartin Matuska cpy = op + length;
708e92ffd9bSMartin Matuska
709e92ffd9bSMartin Matuska assert((op <= oend) && (oend-op >= 32));
710e92ffd9bSMartin Matuska if (unlikely(offset<16)) {
711e92ffd9bSMartin Matuska LZ4_memcpy_using_offset(op, match, cpy, offset);
712e92ffd9bSMartin Matuska } else {
713e92ffd9bSMartin Matuska LZ4_wildCopy32(op, match, cpy);
714e92ffd9bSMartin Matuska }
715e92ffd9bSMartin Matuska
716e92ffd9bSMartin Matuska op = cpy; /* wildcopy correction */
717e92ffd9bSMartin Matuska }
718e92ffd9bSMartin Matuska safe_decode:
719e92ffd9bSMartin Matuska #endif
720e92ffd9bSMartin Matuska
721e92ffd9bSMartin Matuska /* Main Loop : decode remaining sequences where output < FASTLOOP_SAFE_DISTANCE */
722e92ffd9bSMartin Matuska while (1) {
723e92ffd9bSMartin Matuska token = *ip++;
724e92ffd9bSMartin Matuska length = token >> ML_BITS; /* literal length */
725e92ffd9bSMartin Matuska
726e92ffd9bSMartin Matuska assert(!endOnInput || ip <= iend); /* ip < iend before the increment */
727e92ffd9bSMartin Matuska
728e92ffd9bSMartin Matuska /* A two-stage shortcut for the most common case:
729e92ffd9bSMartin Matuska * 1) If the literal length is 0..14, and there is enough space,
730e92ffd9bSMartin Matuska * enter the shortcut and copy 16 bytes on behalf of the literals
731e92ffd9bSMartin Matuska * (in the fast mode, only 8 bytes can be safely copied this way).
732e92ffd9bSMartin Matuska * 2) Further if the match length is 4..18, copy 18 bytes in a similar
733e92ffd9bSMartin Matuska * manner; but we ensure that there's enough space in the output for
734e92ffd9bSMartin Matuska * those 18 bytes earlier, upon entering the shortcut (in other words,
735e92ffd9bSMartin Matuska * there is a combined check for both stages).
736e92ffd9bSMartin Matuska */
737e92ffd9bSMartin Matuska if ( (endOnInput ? length != RUN_MASK : length <= 8)
738e92ffd9bSMartin Matuska /* strictly "less than" on input, to re-enter the loop with at least one byte */
739e92ffd9bSMartin Matuska && likely((endOnInput ? ip < shortiend : 1) & (op <= shortoend)) ) {
740e92ffd9bSMartin Matuska /* Copy the literals */
741e92ffd9bSMartin Matuska LZ4_memcpy(op, ip, endOnInput ? 16 : 8);
742e92ffd9bSMartin Matuska op += length; ip += length;
743e92ffd9bSMartin Matuska
744e92ffd9bSMartin Matuska /* The second stage: prepare for match copying, decode full info.
745e92ffd9bSMartin Matuska * If it doesn't work out, the info won't be wasted. */
746e92ffd9bSMartin Matuska length = token & ML_MASK; /* match length */
747e92ffd9bSMartin Matuska offset = LZ4_readLE16(ip); ip += 2;
748e92ffd9bSMartin Matuska match = op - offset;
749e92ffd9bSMartin Matuska assert(match <= op); /* check overflow */
750e92ffd9bSMartin Matuska
751e92ffd9bSMartin Matuska /* Do not deal with overlapping matches. */
752e92ffd9bSMartin Matuska if ( (length != ML_MASK)
753e92ffd9bSMartin Matuska && (offset >= 8)
754e92ffd9bSMartin Matuska && (dict==withPrefix64k || match >= lowPrefix) ) {
755e92ffd9bSMartin Matuska /* Copy the match. */
756e92ffd9bSMartin Matuska LZ4_memcpy(op + 0, match + 0, 8);
757e92ffd9bSMartin Matuska LZ4_memcpy(op + 8, match + 8, 8);
758e92ffd9bSMartin Matuska LZ4_memcpy(op +16, match +16, 2);
759e92ffd9bSMartin Matuska op += length + MINMATCH;
760e92ffd9bSMartin Matuska /* Both stages worked, load the next token. */
761e92ffd9bSMartin Matuska continue;
762e92ffd9bSMartin Matuska }
763e92ffd9bSMartin Matuska
764e92ffd9bSMartin Matuska /* The second stage didn't work out, but the info is ready.
765e92ffd9bSMartin Matuska * Propel it right to the point of match copying. */
766e92ffd9bSMartin Matuska goto _copy_match;
767e92ffd9bSMartin Matuska }
768e92ffd9bSMartin Matuska
769e92ffd9bSMartin Matuska /* decode literal length */
770e92ffd9bSMartin Matuska if (length == RUN_MASK) {
771e92ffd9bSMartin Matuska variable_length_error error = ok;
772e92ffd9bSMartin Matuska length += read_variable_length(&ip, iend-RUN_MASK, (int)endOnInput, (int)endOnInput, &error);
773e92ffd9bSMartin Matuska if (error == initial_error) { goto _output_error; }
774e92ffd9bSMartin Matuska if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)(op))) { goto _output_error; } /* overflow detection */
775e92ffd9bSMartin Matuska if ((safeDecode) && unlikely((uptrval)(ip)+length<(uptrval)(ip))) { goto _output_error; } /* overflow detection */
776e92ffd9bSMartin Matuska }
777e92ffd9bSMartin Matuska
778e92ffd9bSMartin Matuska /* copy literals */
779e92ffd9bSMartin Matuska cpy = op+length;
780e92ffd9bSMartin Matuska #if LZ4_FAST_DEC_LOOP
781e92ffd9bSMartin Matuska safe_literal_copy:
782e92ffd9bSMartin Matuska #endif
783e92ffd9bSMartin Matuska LZ4_STATIC_ASSERT(MFLIMIT >= WILDCOPYLENGTH);
784e92ffd9bSMartin Matuska if ( ((endOnInput) && ((cpy>oend-MFLIMIT) || (ip+length>iend-(2+1+LASTLITERALS))) )
785e92ffd9bSMartin Matuska || ((!endOnInput) && (cpy>oend-WILDCOPYLENGTH)) )
786e92ffd9bSMartin Matuska {
787e92ffd9bSMartin Matuska /* We've either hit the input parsing restriction or the output parsing restriction.
788e92ffd9bSMartin Matuska * In the normal scenario, decoding a full block, it must be the last sequence,
789e92ffd9bSMartin Matuska * otherwise it's an error (invalid input or dimensions).
790e92ffd9bSMartin Matuska * In partialDecoding scenario, it's necessary to ensure there is no buffer overflow.
791e92ffd9bSMartin Matuska */
792e92ffd9bSMartin Matuska if (partialDecoding) {
793e92ffd9bSMartin Matuska /* Since we are partial decoding we may be in this block because of the output parsing
794e92ffd9bSMartin Matuska * restriction, which is not valid since the output buffer is allowed to be undersized.
795e92ffd9bSMartin Matuska */
796e92ffd9bSMartin Matuska assert(endOnInput);
797e92ffd9bSMartin Matuska DEBUGLOG(7, "partialDecoding: copying literals, close to input or output end")
798e92ffd9bSMartin Matuska DEBUGLOG(7, "partialDecoding: literal length = %u", (unsigned)length);
799e92ffd9bSMartin Matuska DEBUGLOG(7, "partialDecoding: remaining space in dstBuffer : %i", (int)(oend - op));
800e92ffd9bSMartin Matuska DEBUGLOG(7, "partialDecoding: remaining space in srcBuffer : %i", (int)(iend - ip));
801e92ffd9bSMartin Matuska /* Finishing in the middle of a literals segment,
802e92ffd9bSMartin Matuska * due to lack of input.
803e92ffd9bSMartin Matuska */
804e92ffd9bSMartin Matuska if (ip+length > iend) {
805e92ffd9bSMartin Matuska length = (size_t)(iend-ip);
806e92ffd9bSMartin Matuska cpy = op + length;
807e92ffd9bSMartin Matuska }
808e92ffd9bSMartin Matuska /* Finishing in the middle of a literals segment,
809e92ffd9bSMartin Matuska * due to lack of output space.
810e92ffd9bSMartin Matuska */
811e92ffd9bSMartin Matuska if (cpy > oend) {
812e92ffd9bSMartin Matuska cpy = oend;
813e92ffd9bSMartin Matuska assert(op<=oend);
814e92ffd9bSMartin Matuska length = (size_t)(oend-op);
815e92ffd9bSMartin Matuska }
816e92ffd9bSMartin Matuska } else {
817e92ffd9bSMartin Matuska /* We must be on the last sequence because of the parsing limitations so check
818e92ffd9bSMartin Matuska * that we exactly regenerate the original size (must be exact when !endOnInput).
819e92ffd9bSMartin Matuska */
820e92ffd9bSMartin Matuska if ((!endOnInput) && (cpy != oend)) { goto _output_error; }
821e92ffd9bSMartin Matuska /* We must be on the last sequence (or invalid) because of the parsing limitations
822e92ffd9bSMartin Matuska * so check that we exactly consume the input and don't overrun the output buffer.
823e92ffd9bSMartin Matuska */
824e92ffd9bSMartin Matuska if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) {
825e92ffd9bSMartin Matuska DEBUGLOG(6, "should have been last run of literals")
826e92ffd9bSMartin Matuska DEBUGLOG(6, "ip(%p) + length(%i) = %p != iend (%p)", ip, (int)length, ip+length, iend);
827e92ffd9bSMartin Matuska DEBUGLOG(6, "or cpy(%p) > oend(%p)", cpy, oend);
828e92ffd9bSMartin Matuska goto _output_error;
829e92ffd9bSMartin Matuska }
830e92ffd9bSMartin Matuska }
831e92ffd9bSMartin Matuska memmove(op, ip, length); /* supports overlapping memory regions; only matters for in-place decompression scenarios */
832e92ffd9bSMartin Matuska ip += length;
833e92ffd9bSMartin Matuska op += length;
834e92ffd9bSMartin Matuska /* Necessarily EOF when !partialDecoding.
835e92ffd9bSMartin Matuska * When partialDecoding, it is EOF if we've either
836e92ffd9bSMartin Matuska * filled the output buffer or
837e92ffd9bSMartin Matuska * can't proceed with reading an offset for following match.
838e92ffd9bSMartin Matuska */
839e92ffd9bSMartin Matuska if (!partialDecoding || (cpy == oend) || (ip >= (iend-2))) {
840eda14cbcSMatt Macy break;
841eda14cbcSMatt Macy }
842eda14cbcSMatt Macy } else {
843e92ffd9bSMartin Matuska LZ4_wildCopy8(op, ip, cpy); /* may overwrite up to WILDCOPYLENGTH beyond cpy */
844e92ffd9bSMartin Matuska ip += length; op = cpy;
845eda14cbcSMatt Macy }
846e92ffd9bSMartin Matuska
847e92ffd9bSMartin Matuska /* get offset */
848e92ffd9bSMartin Matuska offset = LZ4_readLE16(ip); ip+=2;
849e92ffd9bSMartin Matuska match = op - offset;
850e92ffd9bSMartin Matuska
851e92ffd9bSMartin Matuska /* get matchlength */
852e92ffd9bSMartin Matuska length = token & ML_MASK;
853e92ffd9bSMartin Matuska
854e92ffd9bSMartin Matuska _copy_match:
855e92ffd9bSMartin Matuska if (length == ML_MASK) {
856e92ffd9bSMartin Matuska variable_length_error error = ok;
857e92ffd9bSMartin Matuska length += read_variable_length(&ip, iend - LASTLITERALS + 1, (int)endOnInput, 0, &error);
858e92ffd9bSMartin Matuska if (error != ok) goto _output_error;
859e92ffd9bSMartin Matuska if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)op)) goto _output_error; /* overflow detection */
860e92ffd9bSMartin Matuska }
861e92ffd9bSMartin Matuska length += MINMATCH;
862e92ffd9bSMartin Matuska
863e92ffd9bSMartin Matuska #if LZ4_FAST_DEC_LOOP
864e92ffd9bSMartin Matuska safe_match_copy:
865eda14cbcSMatt Macy #endif
866e92ffd9bSMartin Matuska if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) goto _output_error; /* Error : offset outside buffers */
867e92ffd9bSMartin Matuska /* match starting within external dictionary */
868e92ffd9bSMartin Matuska if ((dict==usingExtDict) && (match < lowPrefix)) {
869e92ffd9bSMartin Matuska if (unlikely(op+length > oend-LASTLITERALS)) {
870e92ffd9bSMartin Matuska if (partialDecoding) length = MIN(length, (size_t)(oend-op));
871e92ffd9bSMartin Matuska else goto _output_error; /* doesn't respect parsing restriction */
872e92ffd9bSMartin Matuska }
873e92ffd9bSMartin Matuska
874e92ffd9bSMartin Matuska if (length <= (size_t)(lowPrefix-match)) {
875e92ffd9bSMartin Matuska /* match fits entirely within external dictionary : just copy */
876e92ffd9bSMartin Matuska memmove(op, dictEnd - (lowPrefix-match), length);
877e92ffd9bSMartin Matuska op += length;
878e92ffd9bSMartin Matuska } else {
879e92ffd9bSMartin Matuska /* match stretches into both external dictionary and current block */
880e92ffd9bSMartin Matuska size_t const copySize = (size_t)(lowPrefix - match);
881e92ffd9bSMartin Matuska size_t const restSize = length - copySize;
882e92ffd9bSMartin Matuska LZ4_memcpy(op, dictEnd - copySize, copySize);
883e92ffd9bSMartin Matuska op += copySize;
884e92ffd9bSMartin Matuska if (restSize > (size_t)(op - lowPrefix)) { /* overlap copy */
885e92ffd9bSMartin Matuska BYTE* const endOfMatch = op + restSize;
886e92ffd9bSMartin Matuska const BYTE* copyFrom = lowPrefix;
887e92ffd9bSMartin Matuska while (op < endOfMatch) *op++ = *copyFrom++;
888e92ffd9bSMartin Matuska } else {
889e92ffd9bSMartin Matuska LZ4_memcpy(op, lowPrefix, restSize);
890e92ffd9bSMartin Matuska op += restSize;
891e92ffd9bSMartin Matuska } }
892eda14cbcSMatt Macy continue;
893eda14cbcSMatt Macy }
894e92ffd9bSMartin Matuska assert(match >= lowPrefix);
895e92ffd9bSMartin Matuska
896e92ffd9bSMartin Matuska /* copy match within block */
897e92ffd9bSMartin Matuska cpy = op + length;
898e92ffd9bSMartin Matuska
899e92ffd9bSMartin Matuska /* partialDecoding : may end anywhere within the block */
900e92ffd9bSMartin Matuska assert(op<=oend);
901e92ffd9bSMartin Matuska if (partialDecoding && (cpy > oend-MATCH_SAFEGUARD_DISTANCE)) {
902e92ffd9bSMartin Matuska size_t const mlen = MIN(length, (size_t)(oend-op));
903e92ffd9bSMartin Matuska const BYTE* const matchEnd = match + mlen;
904e92ffd9bSMartin Matuska BYTE* const copyEnd = op + mlen;
905e92ffd9bSMartin Matuska if (matchEnd > op) { /* overlap copy */
906e92ffd9bSMartin Matuska while (op < copyEnd) { *op++ = *match++; }
907e92ffd9bSMartin Matuska } else {
908e92ffd9bSMartin Matuska LZ4_memcpy(op, match, mlen);
909e92ffd9bSMartin Matuska }
910e92ffd9bSMartin Matuska op = copyEnd;
911e92ffd9bSMartin Matuska if (op == oend) { break; }
912e92ffd9bSMartin Matuska continue;
913e92ffd9bSMartin Matuska }
914e92ffd9bSMartin Matuska
915e92ffd9bSMartin Matuska if (unlikely(offset<8)) {
916e92ffd9bSMartin Matuska LZ4_write32(op, 0); /* silence msan warning when offset==0 */
917e92ffd9bSMartin Matuska op[0] = match[0];
918e92ffd9bSMartin Matuska op[1] = match[1];
919e92ffd9bSMartin Matuska op[2] = match[2];
920e92ffd9bSMartin Matuska op[3] = match[3];
921e92ffd9bSMartin Matuska match += inc32table[offset];
922e92ffd9bSMartin Matuska LZ4_memcpy(op+4, match, 4);
923e92ffd9bSMartin Matuska match -= dec64table[offset];
924e92ffd9bSMartin Matuska } else {
925e92ffd9bSMartin Matuska LZ4_memcpy(op, match, 8);
926e92ffd9bSMartin Matuska match += 8;
927e92ffd9bSMartin Matuska }
928e92ffd9bSMartin Matuska op += 8;
929e92ffd9bSMartin Matuska
930e92ffd9bSMartin Matuska if (unlikely(cpy > oend-MATCH_SAFEGUARD_DISTANCE)) {
931e92ffd9bSMartin Matuska BYTE* const oCopyLimit = oend - (WILDCOPYLENGTH-1);
932e92ffd9bSMartin Matuska if (cpy > oend-LASTLITERALS) { goto _output_error; } /* Error : last LASTLITERALS bytes must be literals (uncompressed) */
933e92ffd9bSMartin Matuska if (op < oCopyLimit) {
934e92ffd9bSMartin Matuska LZ4_wildCopy8(op, match, oCopyLimit);
935e92ffd9bSMartin Matuska match += oCopyLimit - op;
936e92ffd9bSMartin Matuska op = oCopyLimit;
937e92ffd9bSMartin Matuska }
938e92ffd9bSMartin Matuska while (op < cpy) { *op++ = *match++; }
939e92ffd9bSMartin Matuska } else {
940e92ffd9bSMartin Matuska LZ4_memcpy(op, match, 8);
941e92ffd9bSMartin Matuska if (length > 16) { LZ4_wildCopy8(op+8, match+8, cpy); }
942e92ffd9bSMartin Matuska }
943e92ffd9bSMartin Matuska op = cpy; /* wildcopy correction */
944eda14cbcSMatt Macy }
945eda14cbcSMatt Macy
946eda14cbcSMatt Macy /* end of decoding */
947e92ffd9bSMartin Matuska if (endOnInput) {
948e92ffd9bSMartin Matuska DEBUGLOG(5, "decoded %i bytes", (int) (((char*)op)-dst));
949e92ffd9bSMartin Matuska return (int) (((char*)op)-dst); /* Nb of output bytes decoded */
950e92ffd9bSMartin Matuska } else {
951e92ffd9bSMartin Matuska return (int) (((const char*)ip)-src); /* Nb of input bytes read */
952e92ffd9bSMartin Matuska }
953eda14cbcSMatt Macy
954e92ffd9bSMartin Matuska /* Overflow error detected */
955eda14cbcSMatt Macy _output_error:
956e92ffd9bSMartin Matuska return (int) (-(((const char*)ip)-src))-1;
957e92ffd9bSMartin Matuska }
958eda14cbcSMatt Macy }
959eda14cbcSMatt Macy
960aebc9683SMateusz Guzik /*
961e92ffd9bSMartin Matuska * LZ4_uncompress_unknownOutputSize() :
962e92ffd9bSMartin Matuska * isize : is the input size, therefore the compressed size
963e92ffd9bSMartin Matuska * maxOutputSize : is the size of the destination buffer (which must be
964e92ffd9bSMartin Matuska * already allocated)
965e92ffd9bSMartin Matuska * return : the number of bytes decoded in the destination buffer
966e92ffd9bSMartin Matuska * (necessarily <= maxOutputSize). If the source stream is
967e92ffd9bSMartin Matuska * malformed, the function will stop decoding and return a
968e92ffd9bSMartin Matuska * negative result, indicating the byte position of the faulty
969e92ffd9bSMartin Matuska * instruction. This function never writes beyond dest +
970e92ffd9bSMartin Matuska * maxOutputSize, and is therefore protected against malicious
971e92ffd9bSMartin Matuska * data packets.
972e92ffd9bSMartin Matuska * note : Destination buffer must be already allocated.
973e92ffd9bSMartin Matuska * This version is slightly slower than real_LZ4_uncompress()
974e92ffd9bSMartin Matuska *
975aebc9683SMateusz Guzik */
976aebc9683SMateusz Guzik
977e92ffd9bSMartin Matuska /*
978e92ffd9bSMartin Matuska * Note: In upstream code, LZ4_uncompress_unknownOutputSize is now a legacy
979e92ffd9bSMartin Matuska * wrapper for LZ4_decompress_safe which is a wrapper for
980e92ffd9bSMartin Matuska * LZ4_decompress_generic; this wrapper flattens that, rather than
981e92ffd9bSMartin Matuska * rewriting the callers.
982e92ffd9bSMartin Matuska */
LZ4_uncompress_unknownOutputSize(const char * source,char * dest,int compressedSize,int maxDecompressedSize)983e92ffd9bSMartin Matuska int LZ4_uncompress_unknownOutputSize(const char* source, char* dest, int compressedSize, int maxDecompressedSize)
984eda14cbcSMatt Macy {
985e92ffd9bSMartin Matuska return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize,
986e92ffd9bSMartin Matuska endOnInputSize, decode_full_block, noDict,
987e92ffd9bSMartin Matuska (BYTE*)dest, NULL, 0);
988eda14cbcSMatt Macy }
989