diff --git a/lib/legacy/zstd_v05.c b/lib/legacy/zstd_v05.c index 7a3af4214..16bac3b22 100644 --- a/lib/legacy/zstd_v05.c +++ b/lib/legacy/zstd_v05.c @@ -2,4004 +2,18 @@ * Copyright (c) Yann Collet, Meta Platforms, Inc. and affiliates. * All rights reserved. * - * This source code is licensed under both the BSD-style license (found in the + * This source code is licensed under both the BSD-style license found in the * LICENSE file in the root directory of this source tree) and the GPLv2 (found * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. + * You may select, at your option, one or both licenses. */ - -/*- Dependencies -*/ +#include /* size_t */ #include "zstd_v05.h" +#include "../common/compiler.h" #include "../common/error_private.h" - -/* ****************************************************************** - mem.h - low-level memory access routines - Copyright (C) 2013-2015, Yann Collet. - - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - FSEv05 source repository : https://github.com/Cyan4973/FiniteStateEntropy - - Public forum : https://groups.google.com/forum/#!forum/lz4c -****************************************************************** */ -#ifndef MEM_H_MODULE -#define MEM_H_MODULE - -#if defined (__cplusplus) -extern "C" { -#endif - -/*-**************************************** -* Dependencies -******************************************/ -#include /* size_t, ptrdiff_t */ -#include /* memcpy */ - - -/*-**************************************** -* Compiler specifics -******************************************/ -#if defined(__GNUC__) -# define MEM_STATIC static __attribute__((unused)) -#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) -# define MEM_STATIC static inline -#elif defined(_MSC_VER) -# define MEM_STATIC static __inline -#else -# define MEM_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */ -#endif - - -/*-************************************************************** -* Basic Types -*****************************************************************/ -#if defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) -# if defined(_AIX) -# include -# else -# include /* intptr_t */ -# endif - typedef uint8_t BYTE; - typedef uint16_t U16; - typedef int16_t S16; - typedef uint32_t U32; - typedef int32_t S32; - typedef uint64_t U64; - typedef int64_t S64; -#else - typedef unsigned char BYTE; - typedef unsigned short U16; - typedef signed short S16; - typedef unsigned int U32; - typedef signed int S32; - typedef unsigned long long U64; - typedef signed long long S64; -#endif - - -/*-************************************************************** -* Memory I/O -*****************************************************************/ - -MEM_STATIC unsigned MEM_32bits(void) { return sizeof(void*)==4; } -MEM_STATIC unsigned MEM_64bits(void) { return sizeof(void*)==8; } - -MEM_STATIC unsigned MEM_isLittleEndian(void) -{ - const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ - return one.c[0]; -} - -MEM_STATIC U16 MEM_read16(const void* memPtr) -{ - U16 val; memcpy(&val, memPtr, sizeof(val)); return val; -} - -MEM_STATIC U32 MEM_read32(const void* memPtr) -{ - U32 val; memcpy(&val, memPtr, sizeof(val)); return val; -} - -MEM_STATIC U64 MEM_read64(const void* memPtr) -{ - U64 val; memcpy(&val, memPtr, sizeof(val)); return val; -} - -MEM_STATIC void MEM_write16(void* memPtr, U16 value) -{ - memcpy(memPtr, &value, sizeof(value)); -} - -MEM_STATIC void MEM_write32(void* memPtr, U32 value) -{ - memcpy(memPtr, &value, sizeof(value)); -} - -MEM_STATIC void MEM_write64(void* memPtr, U64 value) -{ - memcpy(memPtr, &value, sizeof(value)); -} - -MEM_STATIC U16 MEM_readLE16(const void* memPtr) -{ - if (MEM_isLittleEndian()) - return MEM_read16(memPtr); - else { - const BYTE* p = (const BYTE*)memPtr; - return (U16)(p[0] + (p[1]<<8)); - } -} - -MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val) -{ - if (MEM_isLittleEndian()) { - MEM_write16(memPtr, val); - } else { - BYTE* p = (BYTE*)memPtr; - p[0] = (BYTE)val; - p[1] = (BYTE)(val>>8); - } -} - -MEM_STATIC U32 MEM_readLE32(const void* memPtr) -{ - if (MEM_isLittleEndian()) - return MEM_read32(memPtr); - else { - const BYTE* p = (const BYTE*)memPtr; - return (U32)((U32)p[0] + ((U32)p[1]<<8) + ((U32)p[2]<<16) + ((U32)p[3]<<24)); - } -} - - -MEM_STATIC U64 MEM_readLE64(const void* memPtr) -{ - if (MEM_isLittleEndian()) - return MEM_read64(memPtr); - else { - const BYTE* p = (const BYTE*)memPtr; - return (U64)((U64)p[0] + ((U64)p[1]<<8) + ((U64)p[2]<<16) + ((U64)p[3]<<24) - + ((U64)p[4]<<32) + ((U64)p[5]<<40) + ((U64)p[6]<<48) + ((U64)p[7]<<56)); - } -} - - -MEM_STATIC size_t MEM_readLEST(const void* memPtr) -{ - if (MEM_32bits()) - return (size_t)MEM_readLE32(memPtr); - else - return (size_t)MEM_readLE64(memPtr); -} - - -#if defined (__cplusplus) -} -#endif - -#endif /* MEM_H_MODULE */ - -/* - zstd - standard compression library - Header File for static linking only - Copyright (C) 2014-2016, Yann Collet. - - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - zstd homepage : https://facebook.github.io/zstd -*/ -#ifndef ZSTD_STATIC_H -#define ZSTD_STATIC_H - -/* The prototypes defined within this file are considered experimental. - * They should not be used in the context DLL as they may change in the future. - * Prefer static linking if you need them, to control breaking version changes issues. - */ - -#if defined (__cplusplus) -extern "C" { -#endif - - - -/*-************************************* -* Types -***************************************/ -#define ZSTDv05_WINDOWLOG_ABSOLUTEMIN 11 - - -/*-************************************* -* Advanced functions -***************************************/ -/*- Advanced Decompression functions -*/ - -/*! ZSTDv05_decompress_usingPreparedDCtx() : -* Same as ZSTDv05_decompress_usingDict, but using a reference context `preparedDCtx`, where dictionary has been loaded. -* It avoids reloading the dictionary each time. -* `preparedDCtx` must have been properly initialized using ZSTDv05_decompressBegin_usingDict(). -* Requires 2 contexts : 1 for reference, which will not be modified, and 1 to run the decompression operation */ -size_t ZSTDv05_decompress_usingPreparedDCtx( - ZSTDv05_DCtx* dctx, const ZSTDv05_DCtx* preparedDCtx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize); - - -/* ************************************** -* Streaming functions (direct mode) -****************************************/ -size_t ZSTDv05_decompressBegin(ZSTDv05_DCtx* dctx); - -/* - Streaming decompression, direct mode (bufferless) - - A ZSTDv05_DCtx object is required to track streaming operations. - Use ZSTDv05_createDCtx() / ZSTDv05_freeDCtx() to manage it. - A ZSTDv05_DCtx object can be re-used multiple times. - - First typical operation is to retrieve frame parameters, using ZSTDv05_getFrameParams(). - This operation is independent, and just needs enough input data to properly decode the frame header. - Objective is to retrieve *params.windowlog, to know minimum amount of memory required during decoding. - Result : 0 when successful, it means the ZSTDv05_parameters structure has been filled. - >0 : means there is not enough data into src. Provides the expected size to successfully decode header. - errorCode, which can be tested using ZSTDv05_isError() - - Start decompression, with ZSTDv05_decompressBegin() or ZSTDv05_decompressBegin_usingDict() - Alternatively, you can copy a prepared context, using ZSTDv05_copyDCtx() - - Then use ZSTDv05_nextSrcSizeToDecompress() and ZSTDv05_decompressContinue() alternatively. - ZSTDv05_nextSrcSizeToDecompress() tells how much bytes to provide as 'srcSize' to ZSTDv05_decompressContinue(). - ZSTDv05_decompressContinue() requires this exact amount of bytes, or it will fail. - ZSTDv05_decompressContinue() needs previous data blocks during decompression, up to (1 << windowlog). - They should preferably be located contiguously, prior to current block. Alternatively, a round buffer is also possible. - - @result of ZSTDv05_decompressContinue() is the number of bytes regenerated within 'dst'. - It can be zero, which is not an error; it just means ZSTDv05_decompressContinue() has decoded some header. - - A frame is fully decoded when ZSTDv05_nextSrcSizeToDecompress() returns zero. - Context can then be reset to start a new decompression. -*/ - - -/* ************************************** -* Block functions -****************************************/ -/*! Block functions produce and decode raw zstd blocks, without frame metadata. - User will have to take in charge required information to regenerate data, such as block sizes. - - A few rules to respect : - - Uncompressed block size must be <= 128 KB - - Compressing or decompressing requires a context structure - + Use ZSTDv05_createCCtx() and ZSTDv05_createDCtx() - - It is necessary to init context before starting - + compression : ZSTDv05_compressBegin() - + decompression : ZSTDv05_decompressBegin() - + variants _usingDict() are also allowed - + copyCCtx() and copyDCtx() work too - - When a block is considered not compressible enough, ZSTDv05_compressBlock() result will be zero. - In which case, nothing is produced into `dst`. - + User must test for such outcome and deal directly with uncompressed data - + ZSTDv05_decompressBlock() doesn't accept uncompressed data as input !! -*/ - -size_t ZSTDv05_decompressBlock(ZSTDv05_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); - - - - -#if defined (__cplusplus) -} -#endif - -#endif /* ZSTDv05_STATIC_H */ - - -/* - zstd_internal - common functions to include - Header File for include - Copyright (C) 2014-2016, Yann Collet. - - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - zstd source repository : https://github.com/Cyan4973/zstd -*/ -#ifndef ZSTD_CCOMMON_H_MODULE -#define ZSTD_CCOMMON_H_MODULE - - - -/*-************************************* -* Common macros -***************************************/ -#define MIN(a,b) ((a)<(b) ? (a) : (b)) -#define MAX(a,b) ((a)>(b) ? (a) : (b)) - - -/*-************************************* -* Common constants -***************************************/ -#define ZSTDv05_DICT_MAGIC 0xEC30A435 - -#define KB *(1 <<10) -#define MB *(1 <<20) -#define GB *(1U<<30) - -#define BLOCKSIZE (128 KB) /* define, for static allocation */ - -static const size_t ZSTDv05_blockHeaderSize = 3; -static const size_t ZSTDv05_frameHeaderSize_min = 5; -#define ZSTDv05_frameHeaderSize_max 5 /* define, for static allocation */ - -#define BITv057 128 -#define BITv056 64 -#define BITv055 32 -#define BITv054 16 -#define BITv051 2 -#define BITv050 1 - -#define IS_HUFv05 0 -#define IS_PCH 1 -#define IS_RAW 2 -#define IS_RLE 3 - -#define MINMATCH 4 -#define REPCODE_STARTVALUE 1 - -#define Litbits 8 -#define MLbits 7 -#define LLbits 6 -#define Offbits 5 -#define MaxLit ((1< /* size_t, ptrdiff_t */ - - -/*-**************************************** -* FSEv05 simple functions -******************************************/ -size_t FSEv05_decompress(void* dst, size_t maxDstSize, - const void* cSrc, size_t cSrcSize); -/*! -FSEv05_decompress(): - Decompress FSEv05 data from buffer 'cSrc', of size 'cSrcSize', - into already allocated destination buffer 'dst', of size 'maxDstSize'. - return : size of regenerated data (<= maxDstSize) - or an error code, which can be tested using FSEv05_isError() - - ** Important ** : FSEv05_decompress() doesn't decompress non-compressible nor RLE data !!! - Why ? : making this distinction requires a header. - Header management is intentionally delegated to the user layer, which can better manage special cases. -*/ - - -/* ***************************************** -* Tool functions -******************************************/ -/* Error Management */ -unsigned FSEv05_isError(size_t code); /* tells if a return value is an error code */ -const char* FSEv05_getErrorName(size_t code); /* provides error code string (useful for debugging) */ - - - - -/* ***************************************** -* FSEv05 detailed API -******************************************/ -/* *** DECOMPRESSION *** */ - -/*! -FSEv05_readNCount(): - Read compactly saved 'normalizedCounter' from 'rBuffer'. - return : size read from 'rBuffer' - or an errorCode, which can be tested using FSEv05_isError() - maxSymbolValuePtr[0] and tableLogPtr[0] will also be updated with their respective values */ -size_t FSEv05_readNCount (short* normalizedCounter, unsigned* maxSymbolValuePtr, unsigned* tableLogPtr, const void* rBuffer, size_t rBuffSize); - -/*! -Constructor and Destructor of type FSEv05_DTable - Note that its size depends on 'tableLog' */ -typedef unsigned FSEv05_DTable; /* don't allocate that. It's just a way to be more restrictive than void* */ -FSEv05_DTable* FSEv05_createDTable(unsigned tableLog); -void FSEv05_freeDTable(FSEv05_DTable* dt); - -/*! -FSEv05_buildDTable(): - Builds 'dt', which must be already allocated, using FSEv05_createDTable() - @return : 0, - or an errorCode, which can be tested using FSEv05_isError() */ -size_t FSEv05_buildDTable (FSEv05_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog); - -/*! -FSEv05_decompress_usingDTable(): - Decompress compressed source @cSrc of size @cSrcSize using `dt` - into `dst` which must be already allocated. - @return : size of regenerated data (necessarily <= @dstCapacity) - or an errorCode, which can be tested using FSEv05_isError() */ -size_t FSEv05_decompress_usingDTable(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, const FSEv05_DTable* dt); - - - -#if defined (__cplusplus) -} -#endif - -#endif /* FSEv05_H */ -/* ****************************************************************** - bitstream - Part of FSEv05 library - header file (to include) - Copyright (C) 2013-2016, Yann Collet. - - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - Source repository : https://github.com/Cyan4973/FiniteStateEntropy -****************************************************************** */ -#ifndef BITv05STREAM_H_MODULE -#define BITv05STREAM_H_MODULE - -#if defined (__cplusplus) -extern "C" { -#endif - - -/* -* This API consists of small unitary functions, which highly benefit from being inlined. -* Since link-time-optimization is not available for all compilers, -* these functions are defined into a .h to be included. -*/ - - - -/*-******************************************** -* bitStream decoding API (read backward) -**********************************************/ -typedef struct -{ - size_t bitContainer; - unsigned bitsConsumed; - const char* ptr; - const char* start; -} BITv05_DStream_t; - -typedef enum { BITv05_DStream_unfinished = 0, - BITv05_DStream_endOfBuffer = 1, - BITv05_DStream_completed = 2, - BITv05_DStream_overflow = 3 } BITv05_DStream_status; /* result of BITv05_reloadDStream() */ - /* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */ - -MEM_STATIC size_t BITv05_initDStream(BITv05_DStream_t* bitD, const void* srcBuffer, size_t srcSize); -MEM_STATIC size_t BITv05_readBits(BITv05_DStream_t* bitD, unsigned nbBits); -MEM_STATIC BITv05_DStream_status BITv05_reloadDStream(BITv05_DStream_t* bitD); -MEM_STATIC unsigned BITv05_endOfDStream(const BITv05_DStream_t* bitD); - - -/*-**************************************** -* unsafe API -******************************************/ -MEM_STATIC size_t BITv05_readBitsFast(BITv05_DStream_t* bitD, unsigned nbBits); -/* faster, but works only if nbBits >= 1 */ - - - -/*-************************************************************** -* Helper functions -****************************************************************/ -MEM_STATIC unsigned BITv05_highbit32 (U32 val) -{ -# if defined(_MSC_VER) /* Visual */ - unsigned long r; - return _BitScanReverse(&r, val) ? (unsigned)r : 0; -# elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */ - return __builtin_clz (val) ^ 31; -# else /* Software version */ - 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 }; - U32 v = val; - unsigned r; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - r = DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27]; - return r; -# endif -} - - - -/*-******************************************************** -* bitStream decoding -**********************************************************/ -/*!BITv05_initDStream -* Initialize a BITv05_DStream_t. -* @bitD : a pointer to an already allocated BITv05_DStream_t structure -* @srcBuffer must point at the beginning of a bitStream -* @srcSize must be the exact size of the bitStream -* @result : size of stream (== srcSize) or an errorCode if a problem is detected -*/ -MEM_STATIC size_t BITv05_initDStream(BITv05_DStream_t* bitD, const void* srcBuffer, size_t srcSize) -{ - if (srcSize < 1) { memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); } - - if (srcSize >= sizeof(size_t)) { /* normal case */ - U32 contain32; - bitD->start = (const char*)srcBuffer; - bitD->ptr = (const char*)srcBuffer + srcSize - sizeof(size_t); - bitD->bitContainer = MEM_readLEST(bitD->ptr); - contain32 = ((const BYTE*)srcBuffer)[srcSize-1]; - if (contain32 == 0) return ERROR(GENERIC); /* endMark not present */ - bitD->bitsConsumed = 8 - BITv05_highbit32(contain32); - } else { - U32 contain32; - bitD->start = (const char*)srcBuffer; - bitD->ptr = bitD->start; - bitD->bitContainer = *(const BYTE*)(bitD->start); - switch(srcSize) - { - case 7: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[6]) << (sizeof(size_t)*8 - 16);/* fall-through */ - case 6: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[5]) << (sizeof(size_t)*8 - 24);/* fall-through */ - case 5: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[4]) << (sizeof(size_t)*8 - 32);/* fall-through */ - case 4: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[3]) << 24; /* fall-through */ - case 3: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[2]) << 16; /* fall-through */ - case 2: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[1]) << 8; /* fall-through */ - default: break; - } - contain32 = ((const BYTE*)srcBuffer)[srcSize-1]; - if (contain32 == 0) return ERROR(GENERIC); /* endMark not present */ - bitD->bitsConsumed = 8 - BITv05_highbit32(contain32); - bitD->bitsConsumed += (U32)(sizeof(size_t) - srcSize)*8; - } - - return srcSize; -} - -MEM_STATIC size_t BITv05_lookBits(BITv05_DStream_t* bitD, U32 nbBits) -{ - const U32 bitMask = sizeof(bitD->bitContainer)*8 - 1; - return ((bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> 1) >> ((bitMask-nbBits) & bitMask); -} - -/*! BITv05_lookBitsFast : -* unsafe version; only works if nbBits >= 1 */ -MEM_STATIC size_t BITv05_lookBitsFast(BITv05_DStream_t* bitD, U32 nbBits) -{ - const U32 bitMask = sizeof(bitD->bitContainer)*8 - 1; - return (bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> (((bitMask+1)-nbBits) & bitMask); -} - -MEM_STATIC void BITv05_skipBits(BITv05_DStream_t* bitD, U32 nbBits) -{ - bitD->bitsConsumed += nbBits; -} - -MEM_STATIC size_t BITv05_readBits(BITv05_DStream_t* bitD, unsigned nbBits) -{ - size_t value = BITv05_lookBits(bitD, nbBits); - BITv05_skipBits(bitD, nbBits); - return value; -} - -/*!BITv05_readBitsFast : -* unsafe version; only works if nbBits >= 1 */ -MEM_STATIC size_t BITv05_readBitsFast(BITv05_DStream_t* bitD, unsigned nbBits) -{ - size_t value = BITv05_lookBitsFast(bitD, nbBits); - BITv05_skipBits(bitD, nbBits); - return value; -} - -MEM_STATIC BITv05_DStream_status BITv05_reloadDStream(BITv05_DStream_t* bitD) -{ - if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* should never happen */ - return BITv05_DStream_overflow; - - if (bitD->ptr >= bitD->start + sizeof(bitD->bitContainer)) { - bitD->ptr -= bitD->bitsConsumed >> 3; - bitD->bitsConsumed &= 7; - bitD->bitContainer = MEM_readLEST(bitD->ptr); - return BITv05_DStream_unfinished; - } - if (bitD->ptr == bitD->start) { - if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BITv05_DStream_endOfBuffer; - return BITv05_DStream_completed; - } - { - U32 nbBytes = bitD->bitsConsumed >> 3; - BITv05_DStream_status result = BITv05_DStream_unfinished; - if (bitD->ptr - nbBytes < bitD->start) { - nbBytes = (U32)(bitD->ptr - bitD->start); /* ptr > start */ - result = BITv05_DStream_endOfBuffer; - } - bitD->ptr -= nbBytes; - bitD->bitsConsumed -= nbBytes*8; - bitD->bitContainer = MEM_readLEST(bitD->ptr); /* reminder : srcSize > sizeof(bitD) */ - return result; - } -} - -/*! BITv05_endOfDStream -* @return Tells if DStream has reached its exact end -*/ -MEM_STATIC unsigned BITv05_endOfDStream(const BITv05_DStream_t* DStream) -{ - return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer)*8)); -} - -#if defined (__cplusplus) -} -#endif - -#endif /* BITv05STREAM_H_MODULE */ -/* ****************************************************************** - FSEv05 : Finite State Entropy coder - header file for static linking (only) - Copyright (C) 2013-2015, Yann Collet - - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - Source repository : https://github.com/Cyan4973/FiniteStateEntropy - - Public forum : https://groups.google.com/forum/#!forum/lz4c -****************************************************************** */ -#ifndef FSEv05_STATIC_H -#define FSEv05_STATIC_H - -#if defined (__cplusplus) -extern "C" { -#endif - - - -/* ***************************************** -* Static allocation -*******************************************/ -/* It is possible to statically allocate FSEv05 CTable/DTable as a table of unsigned using below macros */ -#define FSEv05_DTABLE_SIZE_U32(maxTableLog) (1 + (1<= 1 (otherwise, result will be corrupted) */ - - -/* ***************************************** -* Implementation of inlined functions -*******************************************/ -/* decompression */ - -typedef struct { - U16 tableLog; - U16 fastMode; -} FSEv05_DTableHeader; /* sizeof U32 */ - -typedef struct -{ - unsigned short newState; - unsigned char symbol; - unsigned char nbBits; -} FSEv05_decode_t; /* size == U32 */ - -MEM_STATIC void FSEv05_initDState(FSEv05_DState_t* DStatePtr, BITv05_DStream_t* bitD, const FSEv05_DTable* dt) -{ - const void* ptr = dt; - const FSEv05_DTableHeader* const DTableH = (const FSEv05_DTableHeader*)ptr; - DStatePtr->state = BITv05_readBits(bitD, DTableH->tableLog); - BITv05_reloadDStream(bitD); - DStatePtr->table = dt + 1; -} - -MEM_STATIC BYTE FSEv05_peakSymbol(FSEv05_DState_t* DStatePtr) -{ - const FSEv05_decode_t DInfo = ((const FSEv05_decode_t*)(DStatePtr->table))[DStatePtr->state]; - return DInfo.symbol; -} - -MEM_STATIC BYTE FSEv05_decodeSymbol(FSEv05_DState_t* DStatePtr, BITv05_DStream_t* bitD) -{ - const FSEv05_decode_t DInfo = ((const FSEv05_decode_t*)(DStatePtr->table))[DStatePtr->state]; - const U32 nbBits = DInfo.nbBits; - BYTE symbol = DInfo.symbol; - size_t lowBits = BITv05_readBits(bitD, nbBits); - - DStatePtr->state = DInfo.newState + lowBits; - return symbol; -} - -MEM_STATIC BYTE FSEv05_decodeSymbolFast(FSEv05_DState_t* DStatePtr, BITv05_DStream_t* bitD) -{ - const FSEv05_decode_t DInfo = ((const FSEv05_decode_t*)(DStatePtr->table))[DStatePtr->state]; - const U32 nbBits = DInfo.nbBits; - BYTE symbol = DInfo.symbol; - size_t lowBits = BITv05_readBitsFast(bitD, nbBits); - - DStatePtr->state = DInfo.newState + lowBits; - return symbol; -} - -MEM_STATIC unsigned FSEv05_endOfDState(const FSEv05_DState_t* DStatePtr) -{ - return DStatePtr->state == 0; -} - - -#if defined (__cplusplus) -} -#endif - -#endif /* FSEv05_STATIC_H */ -/* ****************************************************************** - FSEv05 : Finite State Entropy coder - Copyright (C) 2013-2015, Yann Collet. - - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - FSEv05 source repository : https://github.com/Cyan4973/FiniteStateEntropy - - Public forum : https://groups.google.com/forum/#!forum/lz4c -****************************************************************** */ - -#ifndef FSEv05_COMMONDEFS_ONLY - -/* ************************************************************** -* Tuning parameters -****************************************************************/ -/*!MEMORY_USAGE : -* Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) -* Increasing memory usage improves compression ratio -* Reduced memory usage can improve speed, due to cache effect -* Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */ -#define FSEv05_MAX_MEMORY_USAGE 14 -#define FSEv05_DEFAULT_MEMORY_USAGE 13 - -/*!FSEv05_MAX_SYMBOL_VALUE : -* Maximum symbol value authorized. -* Required for proper stack allocation */ -#define FSEv05_MAX_SYMBOL_VALUE 255 - - -/* ************************************************************** -* template functions type & suffix -****************************************************************/ -#define FSEv05_FUNCTION_TYPE BYTE -#define FSEv05_FUNCTION_EXTENSION -#define FSEv05_DECODE_TYPE FSEv05_decode_t - - -#endif /* !FSEv05_COMMONDEFS_ONLY */ - -/* ************************************************************** -* Compiler specifics -****************************************************************/ -#ifdef _MSC_VER /* Visual Studio */ -# define FORCE_INLINE static __forceinline -# include /* For Visual 2005 */ -# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -# pragma warning(disable : 4214) /* disable: C4214: non-int bitfields */ -#else -# if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ -# ifdef __GNUC__ -# define FORCE_INLINE static inline __attribute__((always_inline)) -# else -# define FORCE_INLINE static inline -# endif -# else -# define FORCE_INLINE static -# endif /* __STDC_VERSION__ */ -#endif - - -/* ************************************************************** -* Includes -****************************************************************/ -#include /* malloc, free, qsort */ -#include /* memcpy, memset */ -#include /* printf (debug) */ - - - -/* *************************************************************** -* Constants -*****************************************************************/ -#define FSEv05_MAX_TABLELOG (FSEv05_MAX_MEMORY_USAGE-2) -#define FSEv05_MAX_TABLESIZE (1U< FSEv05_TABLELOG_ABSOLUTE_MAX -#error "FSEv05_MAX_TABLELOG > FSEv05_TABLELOG_ABSOLUTE_MAX is not supported" -#endif - - -/* ************************************************************** -* Error Management -****************************************************************/ -#define FSEv05_STATIC_ASSERT(c) { enum { FSEv05_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */ - - -/* ************************************************************** -* Complex types -****************************************************************/ -typedef unsigned DTable_max_t[FSEv05_DTABLE_SIZE_U32(FSEv05_MAX_TABLELOG)]; - - -/* ************************************************************** -* Templates -****************************************************************/ -/* - designed to be included - for type-specific functions (template emulation in C) - Objective is to write these functions only once, for improved maintenance -*/ - -/* safety checks */ -#ifndef FSEv05_FUNCTION_EXTENSION -# error "FSEv05_FUNCTION_EXTENSION must be defined" -#endif -#ifndef FSEv05_FUNCTION_TYPE -# error "FSEv05_FUNCTION_TYPE must be defined" -#endif - -/* Function names */ -#define FSEv05_CAT(X,Y) X##Y -#define FSEv05_FUNCTION_NAME(X,Y) FSEv05_CAT(X,Y) -#define FSEv05_TYPE_NAME(X,Y) FSEv05_CAT(X,Y) - - -/* Function templates */ -static U32 FSEv05_tableStep(U32 tableSize) { return (tableSize>>1) + (tableSize>>3) + 3; } - - - -FSEv05_DTable* FSEv05_createDTable (unsigned tableLog) -{ - if (tableLog > FSEv05_TABLELOG_ABSOLUTE_MAX) tableLog = FSEv05_TABLELOG_ABSOLUTE_MAX; - return (FSEv05_DTable*)malloc( FSEv05_DTABLE_SIZE_U32(tableLog) * sizeof (U32) ); -} - -void FSEv05_freeDTable (FSEv05_DTable* dt) -{ - free(dt); -} - -size_t FSEv05_buildDTable(FSEv05_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog) -{ - FSEv05_DTableHeader DTableH; - void* const tdPtr = dt+1; /* because dt is unsigned, 32-bits aligned on 32-bits */ - FSEv05_DECODE_TYPE* const tableDecode = (FSEv05_DECODE_TYPE*) (tdPtr); - const U32 tableSize = 1 << tableLog; - const U32 tableMask = tableSize-1; - const U32 step = FSEv05_tableStep(tableSize); - U16 symbolNext[FSEv05_MAX_SYMBOL_VALUE+1]; - U32 position = 0; - U32 highThreshold = tableSize-1; - const S16 largeLimit= (S16)(1 << (tableLog-1)); - U32 noLarge = 1; - U32 s; - - /* Sanity Checks */ - if (maxSymbolValue > FSEv05_MAX_SYMBOL_VALUE) return ERROR(maxSymbolValue_tooLarge); - if (tableLog > FSEv05_MAX_TABLELOG) return ERROR(tableLog_tooLarge); - - /* Init, lay down lowprob symbols */ - memset(tableDecode, 0, sizeof(FSEv05_FUNCTION_TYPE) * (maxSymbolValue+1) ); /* useless init, but keep static analyzer happy, and we don't need to performance optimize legacy decoders */ - DTableH.tableLog = (U16)tableLog; - for (s=0; s<=maxSymbolValue; s++) { - if (normalizedCounter[s]==-1) { - tableDecode[highThreshold--].symbol = (FSEv05_FUNCTION_TYPE)s; - symbolNext[s] = 1; - } else { - if (normalizedCounter[s] >= largeLimit) noLarge=0; - symbolNext[s] = normalizedCounter[s]; - } } - - /* Spread symbols */ - for (s=0; s<=maxSymbolValue; s++) { - int i; - for (i=0; i highThreshold) position = (position + step) & tableMask; /* lowprob area */ - } } - - if (position!=0) return ERROR(GENERIC); /* position must reach all cells once, otherwise normalizedCounter is incorrect */ - - /* Build Decoding table */ - { - U32 i; - for (i=0; i FSEv05_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge); - bitStream >>= 4; - bitCount = 4; - *tableLogPtr = nbBits; - remaining = (1<1) && (charnum<=*maxSVPtr)) { - if (previous0) { - unsigned n0 = charnum; - while ((bitStream & 0xFFFF) == 0xFFFF) { - n0+=24; - if (ip < iend-5) { - ip+=2; - bitStream = MEM_readLE32(ip) >> bitCount; - } else { - bitStream >>= 16; - bitCount+=16; - } } - while ((bitStream & 3) == 3) { - n0+=3; - bitStream>>=2; - bitCount+=2; - } - n0 += bitStream & 3; - bitCount += 2; - if (n0 > *maxSVPtr) return ERROR(maxSymbolValue_tooSmall); - while (charnum < n0) normalizedCounter[charnum++] = 0; - if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { - ip += bitCount>>3; - bitCount &= 7; - bitStream = MEM_readLE32(ip) >> bitCount; - } - else - bitStream >>= 2; - } - { - const short max = (short)((2*threshold-1)-remaining); - short count; - - if ((bitStream & (threshold-1)) < (U32)max) { - count = (short)(bitStream & (threshold-1)); - bitCount += nbBits-1; - } else { - count = (short)(bitStream & (2*threshold-1)); - if (count >= threshold) count -= max; - bitCount += nbBits; - } - - count--; /* extra accuracy */ - remaining -= FSEv05_abs(count); - normalizedCounter[charnum++] = count; - previous0 = !count; - while (remaining < threshold) { - nbBits--; - threshold >>= 1; - } - - if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { - ip += bitCount>>3; - bitCount &= 7; - } else { - bitCount -= (int)(8 * (iend - 4 - ip)); - ip = iend - 4; - } - bitStream = MEM_readLE32(ip) >> (bitCount & 31); - } } - if (remaining != 1) return ERROR(GENERIC); - *maxSVPtr = charnum-1; - - ip += (bitCount+7)>>3; - if ((size_t)(ip-istart) > hbSize) return ERROR(srcSize_wrong); - return ip-istart; -} - - - -/*-******************************************************* -* Decompression (Byte symbols) -*********************************************************/ -size_t FSEv05_buildDTable_rle (FSEv05_DTable* dt, BYTE symbolValue) -{ - void* ptr = dt; - FSEv05_DTableHeader* const DTableH = (FSEv05_DTableHeader*)ptr; - void* dPtr = dt + 1; - FSEv05_decode_t* const cell = (FSEv05_decode_t*)dPtr; - - DTableH->tableLog = 0; - DTableH->fastMode = 0; - - cell->newState = 0; - cell->symbol = symbolValue; - cell->nbBits = 0; - - return 0; -} - - -size_t FSEv05_buildDTable_raw (FSEv05_DTable* dt, unsigned nbBits) -{ - void* ptr = dt; - FSEv05_DTableHeader* const DTableH = (FSEv05_DTableHeader*)ptr; - void* dPtr = dt + 1; - FSEv05_decode_t* const dinfo = (FSEv05_decode_t*)dPtr; - const unsigned tableSize = 1 << nbBits; - const unsigned tableMask = tableSize - 1; - const unsigned maxSymbolValue = tableMask; - unsigned s; - - /* Sanity checks */ - if (nbBits < 1) return ERROR(GENERIC); /* min size */ - - /* Build Decoding Table */ - DTableH->tableLog = (U16)nbBits; - DTableH->fastMode = 1; - for (s=0; s<=maxSymbolValue; s++) { - dinfo[s].newState = 0; - dinfo[s].symbol = (BYTE)s; - dinfo[s].nbBits = (BYTE)nbBits; - } - - return 0; -} - -FORCE_INLINE size_t FSEv05_decompress_usingDTable_generic( - void* dst, size_t maxDstSize, - const void* cSrc, size_t cSrcSize, - const FSEv05_DTable* dt, const unsigned fast) -{ - BYTE* const ostart = (BYTE*) dst; - BYTE* op = ostart; - BYTE* const omax = op + maxDstSize; - BYTE* const olimit = omax-3; - - BITv05_DStream_t bitD; - FSEv05_DState_t state1; - FSEv05_DState_t state2; - size_t errorCode; - - /* Init */ - errorCode = BITv05_initDStream(&bitD, cSrc, cSrcSize); /* replaced last arg by maxCompressed Size */ - if (FSEv05_isError(errorCode)) return errorCode; - - FSEv05_initDState(&state1, &bitD, dt); - FSEv05_initDState(&state2, &bitD, dt); - -#define FSEv05_GETSYMBOL(statePtr) fast ? FSEv05_decodeSymbolFast(statePtr, &bitD) : FSEv05_decodeSymbol(statePtr, &bitD) - - /* 4 symbols per loop */ - for ( ; (BITv05_reloadDStream(&bitD)==BITv05_DStream_unfinished) && (op sizeof(bitD.bitContainer)*8) /* This test must be static */ - BITv05_reloadDStream(&bitD); - - op[1] = FSEv05_GETSYMBOL(&state2); - - if (FSEv05_MAX_TABLELOG*4+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */ - { if (BITv05_reloadDStream(&bitD) > BITv05_DStream_unfinished) { op+=2; break; } } - - op[2] = FSEv05_GETSYMBOL(&state1); - - if (FSEv05_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */ - BITv05_reloadDStream(&bitD); - - op[3] = FSEv05_GETSYMBOL(&state2); - } - - /* tail */ - /* note : BITv05_reloadDStream(&bitD) >= FSEv05_DStream_partiallyFilled; Ends at exactly BITv05_DStream_completed */ - while (1) { - if ( (BITv05_reloadDStream(&bitD)>BITv05_DStream_completed) || (op==omax) || (BITv05_endOfDStream(&bitD) && (fast || FSEv05_endOfDState(&state1))) ) - break; - - *op++ = FSEv05_GETSYMBOL(&state1); - - if ( (BITv05_reloadDStream(&bitD)>BITv05_DStream_completed) || (op==omax) || (BITv05_endOfDStream(&bitD) && (fast || FSEv05_endOfDState(&state2))) ) - break; - - *op++ = FSEv05_GETSYMBOL(&state2); - } - - /* end ? */ - if (BITv05_endOfDStream(&bitD) && FSEv05_endOfDState(&state1) && FSEv05_endOfDState(&state2)) - return op-ostart; - - if (op==omax) return ERROR(dstSize_tooSmall); /* dst buffer is full, but cSrc unfinished */ - - return ERROR(corruption_detected); -} - - -size_t FSEv05_decompress_usingDTable(void* dst, size_t originalSize, - const void* cSrc, size_t cSrcSize, - const FSEv05_DTable* dt) -{ - const void* ptr = dt; - const FSEv05_DTableHeader* DTableH = (const FSEv05_DTableHeader*)ptr; - const U32 fastMode = DTableH->fastMode; - - /* select fast mode (static) */ - if (fastMode) return FSEv05_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 1); - return FSEv05_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 0); -} - - -size_t FSEv05_decompress(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize) -{ - const BYTE* const istart = (const BYTE*)cSrc; - const BYTE* ip = istart; - short counting[FSEv05_MAX_SYMBOL_VALUE+1]; - DTable_max_t dt; /* Static analyzer seems unable to understand this table will be properly initialized later */ - unsigned tableLog; - unsigned maxSymbolValue = FSEv05_MAX_SYMBOL_VALUE; - size_t errorCode; - - if (cSrcSize<2) return ERROR(srcSize_wrong); /* too small input size */ - - /* normal FSEv05 decoding mode */ - errorCode = FSEv05_readNCount (counting, &maxSymbolValue, &tableLog, istart, cSrcSize); - if (FSEv05_isError(errorCode)) return errorCode; - if (errorCode >= cSrcSize) return ERROR(srcSize_wrong); /* too small input size */ - ip += errorCode; - cSrcSize -= errorCode; - - errorCode = FSEv05_buildDTable (dt, counting, maxSymbolValue, tableLog); - if (FSEv05_isError(errorCode)) return errorCode; - - /* always return, even if it is an error code */ - return FSEv05_decompress_usingDTable (dst, maxDstSize, ip, cSrcSize, dt); -} - - - -#endif /* FSEv05_COMMONDEFS_ONLY */ -/* ****************************************************************** - Huff0 : Huffman coder, part of New Generation Entropy library - header file - Copyright (C) 2013-2016, Yann Collet. - - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - Source repository : https://github.com/Cyan4973/FiniteStateEntropy -****************************************************************** */ -#ifndef HUFF0_H -#define HUFF0_H - -#if defined (__cplusplus) -extern "C" { -#endif - - - -/* **************************************** -* Huff0 simple functions -******************************************/ -size_t HUFv05_decompress(void* dst, size_t dstSize, - const void* cSrc, size_t cSrcSize); -/*! -HUFv05_decompress(): - Decompress Huff0 data from buffer 'cSrc', of size 'cSrcSize', - into already allocated destination buffer 'dst', of size 'dstSize'. - @dstSize : must be the **exact** size of original (uncompressed) data. - Note : in contrast with FSEv05, HUFv05_decompress can regenerate - RLE (cSrcSize==1) and uncompressed (cSrcSize==dstSize) data, - because it knows size to regenerate. - @return : size of regenerated data (== dstSize) - or an error code, which can be tested using HUFv05_isError() -*/ - - -/* **************************************** -* Tool functions -******************************************/ -/* Error Management */ -unsigned HUFv05_isError(size_t code); /* tells if a return value is an error code */ -const char* HUFv05_getErrorName(size_t code); /* provides error code string (useful for debugging) */ - - -#if defined (__cplusplus) -} -#endif - -#endif /* HUF0_H */ -/* ****************************************************************** - Huff0 : Huffman codec, part of New Generation Entropy library - header file, for static linking only - Copyright (C) 2013-2016, Yann Collet - - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - Source repository : https://github.com/Cyan4973/FiniteStateEntropy -****************************************************************** */ -#ifndef HUF0_STATIC_H -#define HUF0_STATIC_H - -#if defined (__cplusplus) -extern "C" { -#endif - - - -/* **************************************** -* Static allocation -******************************************/ -/* static allocation of Huff0's DTable */ -#define HUFv05_DTABLE_SIZE(maxTableLog) (1 + (1<= 199901L) /* C99 */) -/* inline is defined */ -#elif defined(_MSC_VER) -# define inline __inline -#else -# define inline /* disable inline */ -#endif - - -#ifdef _MSC_VER /* Visual Studio */ -# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -#endif - - -/* ************************************************************** -* Includes -****************************************************************/ -#include /* malloc, free, qsort */ -#include /* memcpy, memset */ -#include /* printf (debug) */ - - -/* ************************************************************** -* Constants -****************************************************************/ -#define HUFv05_ABSOLUTEMAX_TABLELOG 16 /* absolute limit of HUFv05_MAX_TABLELOG. Beyond that value, code does not work */ -#define HUFv05_MAX_TABLELOG 12 /* max configured tableLog (for static allocation); can be modified up to HUFv05_ABSOLUTEMAX_TABLELOG */ -#define HUFv05_DEFAULT_TABLELOG HUFv05_MAX_TABLELOG /* tableLog by default, when not specified */ -#define HUFv05_MAX_SYMBOL_VALUE 255 -#if (HUFv05_MAX_TABLELOG > HUFv05_ABSOLUTEMAX_TABLELOG) -# error "HUFv05_MAX_TABLELOG is too large !" -#endif - - -/* ************************************************************** -* Error Management -****************************************************************/ -unsigned HUFv05_isError(size_t code) { return ERR_isError(code); } -const char* HUFv05_getErrorName(size_t code) { return ERR_getErrorName(code); } -#define HUFv05_STATIC_ASSERT(c) { enum { HUFv05_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */ - - -/* ******************************************************* -* Huff0 : Huffman block decompression -*********************************************************/ -typedef struct { BYTE byte; BYTE nbBits; } HUFv05_DEltX2; /* single-symbol decoding */ - -typedef struct { U16 sequence; BYTE nbBits; BYTE length; } HUFv05_DEltX4; /* double-symbols decoding */ - -typedef struct { BYTE symbol; BYTE weight; } sortedSymbol_t; - -/*! HUFv05_readStats - Read compact Huffman tree, saved by HUFv05_writeCTable - @huffWeight : destination buffer - @return : size read from `src` -*/ -static size_t HUFv05_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, - U32* nbSymbolsPtr, U32* tableLogPtr, - const void* src, size_t srcSize) -{ - U32 weightTotal; - U32 tableLog; - const BYTE* ip = (const BYTE*) src; - size_t iSize; - size_t oSize; - U32 n; - - if (!srcSize) return ERROR(srcSize_wrong); - iSize = ip[0]; - /* memset(huffWeight, 0, hwSize); */ /* is not necessary, even though some analyzer complain ... */ - - if (iSize >= 128) { /* special header */ - if (iSize >= (242)) { /* RLE */ - static int l[14] = { 1, 2, 3, 4, 7, 8, 15, 16, 31, 32, 63, 64, 127, 128 }; - oSize = l[iSize-242]; - memset(huffWeight, 1, hwSize); - iSize = 0; - } - else { /* Incompressible */ - oSize = iSize - 127; - iSize = ((oSize+1)/2); - if (iSize+1 > srcSize) return ERROR(srcSize_wrong); - if (oSize >= hwSize) return ERROR(corruption_detected); - ip += 1; - for (n=0; n> 4; - huffWeight[n+1] = ip[n/2] & 15; - } } } - else { /* header compressed with FSEv05 (normal case) */ - if (iSize+1 > srcSize) return ERROR(srcSize_wrong); - oSize = FSEv05_decompress(huffWeight, hwSize-1, ip+1, iSize); /* max (hwSize-1) values decoded, as last one is implied */ - if (FSEv05_isError(oSize)) return oSize; - } - - /* collect weight stats */ - memset(rankStats, 0, (HUFv05_ABSOLUTEMAX_TABLELOG + 1) * sizeof(U32)); - weightTotal = 0; - for (n=0; n= HUFv05_ABSOLUTEMAX_TABLELOG) return ERROR(corruption_detected); - rankStats[huffWeight[n]]++; - weightTotal += (1 << huffWeight[n]) >> 1; - } - if (weightTotal == 0) return ERROR(corruption_detected); - - /* get last non-null symbol weight (implied, total must be 2^n) */ - tableLog = BITv05_highbit32(weightTotal) + 1; - if (tableLog > HUFv05_ABSOLUTEMAX_TABLELOG) return ERROR(corruption_detected); - { /* determine last weight */ - U32 total = 1 << tableLog; - U32 rest = total - weightTotal; - U32 verif = 1 << BITv05_highbit32(rest); - U32 lastWeight = BITv05_highbit32(rest) + 1; - if (verif != rest) return ERROR(corruption_detected); /* last value must be a clean power of 2 */ - huffWeight[oSize] = (BYTE)lastWeight; - rankStats[lastWeight]++; - } - - /* check tree construction validity */ - if ((rankStats[1] < 2) || (rankStats[1] & 1)) return ERROR(corruption_detected); /* by construction : at least 2 elts of rank 1, must be even */ - - /* results */ - *nbSymbolsPtr = (U32)(oSize+1); - *tableLogPtr = tableLog; - return iSize+1; -} - - -/*-***************************/ -/* single-symbol decoding */ -/*-***************************/ - -size_t HUFv05_readDTableX2 (U16* DTable, const void* src, size_t srcSize) -{ - BYTE huffWeight[HUFv05_MAX_SYMBOL_VALUE + 1]; - U32 rankVal[HUFv05_ABSOLUTEMAX_TABLELOG + 1]; /* large enough for values from 0 to 16 */ - U32 tableLog = 0; - size_t iSize; - U32 nbSymbols = 0; - U32 n; - U32 nextRankStart; - void* const dtPtr = DTable + 1; - HUFv05_DEltX2* const dt = (HUFv05_DEltX2*)dtPtr; - - HUFv05_STATIC_ASSERT(sizeof(HUFv05_DEltX2) == sizeof(U16)); /* if compilation fails here, assertion is false */ - /* memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */ - - iSize = HUFv05_readStats(huffWeight, HUFv05_MAX_SYMBOL_VALUE + 1, rankVal, &nbSymbols, &tableLog, src, srcSize); - if (HUFv05_isError(iSize)) return iSize; - - /* check result */ - if (tableLog > DTable[0]) return ERROR(tableLog_tooLarge); /* DTable is too small */ - DTable[0] = (U16)tableLog; /* maybe should separate sizeof allocated DTable, from used size of DTable, in case of re-use */ - - /* Prepare ranks */ - nextRankStart = 0; - for (n=1; n<=tableLog; n++) { - U32 current = nextRankStart; - nextRankStart += (rankVal[n] << (n-1)); - rankVal[n] = current; - } - - /* fill DTable */ - for (n=0; n> 1; - U32 i; - HUFv05_DEltX2 D; - D.byte = (BYTE)n; D.nbBits = (BYTE)(tableLog + 1 - w); - for (i = rankVal[w]; i < rankVal[w] + length; i++) - dt[i] = D; - rankVal[w] += length; - } - - return iSize; -} - -static BYTE HUFv05_decodeSymbolX2(BITv05_DStream_t* Dstream, const HUFv05_DEltX2* dt, const U32 dtLog) -{ - const size_t val = BITv05_lookBitsFast(Dstream, dtLog); /* note : dtLog >= 1 */ - const BYTE c = dt[val].byte; - BITv05_skipBits(Dstream, dt[val].nbBits); - return c; -} - -#define HUFv05_DECODE_SYMBOLX2_0(ptr, DStreamPtr) \ - *ptr++ = HUFv05_decodeSymbolX2(DStreamPtr, dt, dtLog) - -#define HUFv05_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \ - if (MEM_64bits() || (HUFv05_MAX_TABLELOG<=12)) \ - HUFv05_DECODE_SYMBOLX2_0(ptr, DStreamPtr) - -#define HUFv05_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \ - if (MEM_64bits()) \ - HUFv05_DECODE_SYMBOLX2_0(ptr, DStreamPtr) - -static inline size_t HUFv05_decodeStreamX2(BYTE* p, BITv05_DStream_t* const bitDPtr, BYTE* const pEnd, const HUFv05_DEltX2* const dt, const U32 dtLog) -{ - BYTE* const pStart = p; - - /* up to 4 symbols at a time */ - while ((BITv05_reloadDStream(bitDPtr) == BITv05_DStream_unfinished) && (p <= pEnd-4)) { - HUFv05_DECODE_SYMBOLX2_2(p, bitDPtr); - HUFv05_DECODE_SYMBOLX2_1(p, bitDPtr); - HUFv05_DECODE_SYMBOLX2_2(p, bitDPtr); - HUFv05_DECODE_SYMBOLX2_0(p, bitDPtr); - } - - /* closer to the end */ - while ((BITv05_reloadDStream(bitDPtr) == BITv05_DStream_unfinished) && (p < pEnd)) - HUFv05_DECODE_SYMBOLX2_0(p, bitDPtr); - - /* no more data to retrieve from bitstream, hence no need to reload */ - while (p < pEnd) - HUFv05_DECODE_SYMBOLX2_0(p, bitDPtr); - - return pEnd-pStart; -} - -size_t HUFv05_decompress1X2_usingDTable( - void* dst, size_t dstSize, - const void* cSrc, size_t cSrcSize, - const U16* DTable) -{ - BYTE* op = (BYTE*)dst; - BYTE* const oend = op + dstSize; - const U32 dtLog = DTable[0]; - const void* dtPtr = DTable; - const HUFv05_DEltX2* const dt = ((const HUFv05_DEltX2*)dtPtr)+1; - BITv05_DStream_t bitD; - - if (dstSize <= cSrcSize) return ERROR(dstSize_tooSmall); - { size_t const errorCode = BITv05_initDStream(&bitD, cSrc, cSrcSize); - if (HUFv05_isError(errorCode)) return errorCode; } - - HUFv05_decodeStreamX2(op, &bitD, oend, dt, dtLog); - - /* check */ - if (!BITv05_endOfDStream(&bitD)) return ERROR(corruption_detected); - - return dstSize; -} - -size_t HUFv05_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) -{ - HUFv05_CREATE_STATIC_DTABLEX2(DTable, HUFv05_MAX_TABLELOG); - const BYTE* ip = (const BYTE*) cSrc; - size_t errorCode; - - errorCode = HUFv05_readDTableX2 (DTable, cSrc, cSrcSize); - if (HUFv05_isError(errorCode)) return errorCode; - if (errorCode >= cSrcSize) return ERROR(srcSize_wrong); - ip += errorCode; - cSrcSize -= errorCode; - - return HUFv05_decompress1X2_usingDTable (dst, dstSize, ip, cSrcSize, DTable); -} - - -size_t HUFv05_decompress4X2_usingDTable( - void* dst, size_t dstSize, - const void* cSrc, size_t cSrcSize, - const U16* DTable) -{ - /* Check */ - if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */ - { - const BYTE* const istart = (const BYTE*) cSrc; - BYTE* const ostart = (BYTE*) dst; - BYTE* const oend = ostart + dstSize; - const void* const dtPtr = DTable; - const HUFv05_DEltX2* const dt = ((const HUFv05_DEltX2*)dtPtr) +1; - const U32 dtLog = DTable[0]; - size_t errorCode; - - /* Init */ - BITv05_DStream_t bitD1; - BITv05_DStream_t bitD2; - BITv05_DStream_t bitD3; - BITv05_DStream_t bitD4; - const size_t length1 = MEM_readLE16(istart); - const size_t length2 = MEM_readLE16(istart+2); - const size_t length3 = MEM_readLE16(istart+4); - size_t length4; - const BYTE* const istart1 = istart + 6; /* jumpTable */ - const BYTE* const istart2 = istart1 + length1; - const BYTE* const istart3 = istart2 + length2; - const BYTE* const istart4 = istart3 + length3; - const size_t segmentSize = (dstSize+3) / 4; - BYTE* const opStart2 = ostart + segmentSize; - BYTE* const opStart3 = opStart2 + segmentSize; - BYTE* const opStart4 = opStart3 + segmentSize; - BYTE* op1 = ostart; - BYTE* op2 = opStart2; - BYTE* op3 = opStart3; - BYTE* op4 = opStart4; - U32 endSignal; - - length4 = cSrcSize - (length1 + length2 + length3 + 6); - if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */ - errorCode = BITv05_initDStream(&bitD1, istart1, length1); - if (HUFv05_isError(errorCode)) return errorCode; - errorCode = BITv05_initDStream(&bitD2, istart2, length2); - if (HUFv05_isError(errorCode)) return errorCode; - errorCode = BITv05_initDStream(&bitD3, istart3, length3); - if (HUFv05_isError(errorCode)) return errorCode; - errorCode = BITv05_initDStream(&bitD4, istart4, length4); - if (HUFv05_isError(errorCode)) return errorCode; - - /* 16-32 symbols per loop (4-8 symbols per stream) */ - endSignal = BITv05_reloadDStream(&bitD1) | BITv05_reloadDStream(&bitD2) | BITv05_reloadDStream(&bitD3) | BITv05_reloadDStream(&bitD4); - for ( ; (endSignal==BITv05_DStream_unfinished) && (op4<(oend-7)) ; ) { - HUFv05_DECODE_SYMBOLX2_2(op1, &bitD1); - HUFv05_DECODE_SYMBOLX2_2(op2, &bitD2); - HUFv05_DECODE_SYMBOLX2_2(op3, &bitD3); - HUFv05_DECODE_SYMBOLX2_2(op4, &bitD4); - HUFv05_DECODE_SYMBOLX2_1(op1, &bitD1); - HUFv05_DECODE_SYMBOLX2_1(op2, &bitD2); - HUFv05_DECODE_SYMBOLX2_1(op3, &bitD3); - HUFv05_DECODE_SYMBOLX2_1(op4, &bitD4); - HUFv05_DECODE_SYMBOLX2_2(op1, &bitD1); - HUFv05_DECODE_SYMBOLX2_2(op2, &bitD2); - HUFv05_DECODE_SYMBOLX2_2(op3, &bitD3); - HUFv05_DECODE_SYMBOLX2_2(op4, &bitD4); - HUFv05_DECODE_SYMBOLX2_0(op1, &bitD1); - HUFv05_DECODE_SYMBOLX2_0(op2, &bitD2); - HUFv05_DECODE_SYMBOLX2_0(op3, &bitD3); - HUFv05_DECODE_SYMBOLX2_0(op4, &bitD4); - endSignal = BITv05_reloadDStream(&bitD1) | BITv05_reloadDStream(&bitD2) | BITv05_reloadDStream(&bitD3) | BITv05_reloadDStream(&bitD4); - } - - /* check corruption */ - if (op1 > opStart2) return ERROR(corruption_detected); - if (op2 > opStart3) return ERROR(corruption_detected); - if (op3 > opStart4) return ERROR(corruption_detected); - /* note : op4 supposed already verified within main loop */ - - /* finish bitStreams one by one */ - HUFv05_decodeStreamX2(op1, &bitD1, opStart2, dt, dtLog); - HUFv05_decodeStreamX2(op2, &bitD2, opStart3, dt, dtLog); - HUFv05_decodeStreamX2(op3, &bitD3, opStart4, dt, dtLog); - HUFv05_decodeStreamX2(op4, &bitD4, oend, dt, dtLog); - - /* check */ - endSignal = BITv05_endOfDStream(&bitD1) & BITv05_endOfDStream(&bitD2) & BITv05_endOfDStream(&bitD3) & BITv05_endOfDStream(&bitD4); - if (!endSignal) return ERROR(corruption_detected); - - /* decoded size */ - return dstSize; - } -} - - -size_t HUFv05_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) -{ - HUFv05_CREATE_STATIC_DTABLEX2(DTable, HUFv05_MAX_TABLELOG); - const BYTE* ip = (const BYTE*) cSrc; - size_t errorCode; - - errorCode = HUFv05_readDTableX2 (DTable, cSrc, cSrcSize); - if (HUFv05_isError(errorCode)) return errorCode; - if (errorCode >= cSrcSize) return ERROR(srcSize_wrong); - ip += errorCode; - cSrcSize -= errorCode; - - return HUFv05_decompress4X2_usingDTable (dst, dstSize, ip, cSrcSize, DTable); -} - - -/* *************************/ -/* double-symbols decoding */ -/* *************************/ - -static void HUFv05_fillDTableX4Level2(HUFv05_DEltX4* DTable, U32 sizeLog, const U32 consumed, - const U32* rankValOrigin, const int minWeight, - const sortedSymbol_t* sortedSymbols, const U32 sortedListSize, - U32 nbBitsBaseline, U16 baseSeq) -{ - HUFv05_DEltX4 DElt; - U32 rankVal[HUFv05_ABSOLUTEMAX_TABLELOG + 1]; - U32 s; - - /* get pre-calculated rankVal */ - memcpy(rankVal, rankValOrigin, sizeof(rankVal)); - - /* fill skipped values */ - if (minWeight>1) { - U32 i, skipSize = rankVal[minWeight]; - MEM_writeLE16(&(DElt.sequence), baseSeq); - DElt.nbBits = (BYTE)(consumed); - DElt.length = 1; - for (i = 0; i < skipSize; i++) - DTable[i] = DElt; - } - - /* fill DTable */ - for (s=0; s= 1 */ - - rankVal[weight] += length; - } -} - -typedef U32 rankVal_t[HUFv05_ABSOLUTEMAX_TABLELOG][HUFv05_ABSOLUTEMAX_TABLELOG + 1]; - -static void HUFv05_fillDTableX4(HUFv05_DEltX4* DTable, const U32 targetLog, - const sortedSymbol_t* sortedList, const U32 sortedListSize, - const U32* rankStart, rankVal_t rankValOrigin, const U32 maxWeight, - const U32 nbBitsBaseline) -{ - U32 rankVal[HUFv05_ABSOLUTEMAX_TABLELOG + 1]; - const int scaleLog = nbBitsBaseline - targetLog; /* note : targetLog >= srcLog, hence scaleLog <= 1 */ - const U32 minBits = nbBitsBaseline - maxWeight; - U32 s; - - memcpy(rankVal, rankValOrigin, sizeof(rankVal)); - - /* fill DTable */ - for (s=0; s= minBits) { /* enough room for a second symbol */ - U32 sortedRank; - int minWeight = nbBits + scaleLog; - if (minWeight < 1) minWeight = 1; - sortedRank = rankStart[minWeight]; - HUFv05_fillDTableX4Level2(DTable+start, targetLog-nbBits, nbBits, - rankValOrigin[nbBits], minWeight, - sortedList+sortedRank, sortedListSize-sortedRank, - nbBitsBaseline, symbol); - } else { - U32 i; - const U32 end = start + length; - HUFv05_DEltX4 DElt; - - MEM_writeLE16(&(DElt.sequence), symbol); - DElt.nbBits = (BYTE)(nbBits); - DElt.length = 1; - for (i = start; i < end; i++) - DTable[i] = DElt; - } - rankVal[weight] += length; - } -} - -size_t HUFv05_readDTableX4 (unsigned* DTable, const void* src, size_t srcSize) -{ - BYTE weightList[HUFv05_MAX_SYMBOL_VALUE + 1]; - sortedSymbol_t sortedSymbol[HUFv05_MAX_SYMBOL_VALUE + 1]; - U32 rankStats[HUFv05_ABSOLUTEMAX_TABLELOG + 1] = { 0 }; - U32 rankStart0[HUFv05_ABSOLUTEMAX_TABLELOG + 2] = { 0 }; - U32* const rankStart = rankStart0+1; - rankVal_t rankVal; - U32 tableLog, maxW, sizeOfSort, nbSymbols; - const U32 memLog = DTable[0]; - size_t iSize; - void* dtPtr = DTable; - HUFv05_DEltX4* const dt = ((HUFv05_DEltX4*)dtPtr) + 1; - - HUFv05_STATIC_ASSERT(sizeof(HUFv05_DEltX4) == sizeof(unsigned)); /* if compilation fails here, assertion is false */ - if (memLog > HUFv05_ABSOLUTEMAX_TABLELOG) return ERROR(tableLog_tooLarge); - /* memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */ - - iSize = HUFv05_readStats(weightList, HUFv05_MAX_SYMBOL_VALUE + 1, rankStats, &nbSymbols, &tableLog, src, srcSize); - if (HUFv05_isError(iSize)) return iSize; - - /* check result */ - if (tableLog > memLog) return ERROR(tableLog_tooLarge); /* DTable can't fit code depth */ - - /* find maxWeight */ - for (maxW = tableLog; rankStats[maxW]==0; maxW--) {} /* necessarily finds a solution before 0 */ - - /* Get start index of each weight */ - { - U32 w, nextRankStart = 0; - for (w=1; w<=maxW; w++) { - U32 current = nextRankStart; - nextRankStart += rankStats[w]; - rankStart[w] = current; - } - rankStart[0] = nextRankStart; /* put all 0w symbols at the end of sorted list*/ - sizeOfSort = nextRankStart; - } - - /* sort symbols by weight */ - { - U32 s; - for (s=0; s> consumed; - } } } - - HUFv05_fillDTableX4(dt, memLog, - sortedSymbol, sizeOfSort, - rankStart0, rankVal, maxW, - tableLog+1); - - return iSize; -} - - -static U32 HUFv05_decodeSymbolX4(void* op, BITv05_DStream_t* DStream, const HUFv05_DEltX4* dt, const U32 dtLog) -{ - const size_t val = BITv05_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */ - memcpy(op, dt+val, 2); - BITv05_skipBits(DStream, dt[val].nbBits); - return dt[val].length; -} - -static U32 HUFv05_decodeLastSymbolX4(void* op, BITv05_DStream_t* DStream, const HUFv05_DEltX4* dt, const U32 dtLog) -{ - const size_t val = BITv05_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */ - memcpy(op, dt+val, 1); - if (dt[val].length==1) BITv05_skipBits(DStream, dt[val].nbBits); - else { - if (DStream->bitsConsumed < (sizeof(DStream->bitContainer)*8)) { - BITv05_skipBits(DStream, dt[val].nbBits); - if (DStream->bitsConsumed > (sizeof(DStream->bitContainer)*8)) - 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 */ - } } - return 1; -} - - -#define HUFv05_DECODE_SYMBOLX4_0(ptr, DStreamPtr) \ - ptr += HUFv05_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog) - -#define HUFv05_DECODE_SYMBOLX4_1(ptr, DStreamPtr) \ - if (MEM_64bits() || (HUFv05_MAX_TABLELOG<=12)) \ - ptr += HUFv05_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog) - -#define HUFv05_DECODE_SYMBOLX4_2(ptr, DStreamPtr) \ - if (MEM_64bits()) \ - ptr += HUFv05_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog) - -static inline size_t HUFv05_decodeStreamX4(BYTE* p, BITv05_DStream_t* bitDPtr, BYTE* const pEnd, const HUFv05_DEltX4* const dt, const U32 dtLog) -{ - BYTE* const pStart = p; - - /* up to 8 symbols at a time */ - while ((BITv05_reloadDStream(bitDPtr) == BITv05_DStream_unfinished) && (p < pEnd-7)) { - HUFv05_DECODE_SYMBOLX4_2(p, bitDPtr); - HUFv05_DECODE_SYMBOLX4_1(p, bitDPtr); - HUFv05_DECODE_SYMBOLX4_2(p, bitDPtr); - HUFv05_DECODE_SYMBOLX4_0(p, bitDPtr); - } - - /* closer to the end */ - while ((BITv05_reloadDStream(bitDPtr) == BITv05_DStream_unfinished) && (p <= pEnd-2)) - HUFv05_DECODE_SYMBOLX4_0(p, bitDPtr); - - while (p <= pEnd-2) - HUFv05_DECODE_SYMBOLX4_0(p, bitDPtr); /* no need to reload : reached the end of DStream */ - - if (p < pEnd) - p += HUFv05_decodeLastSymbolX4(p, bitDPtr, dt, dtLog); - - return p-pStart; -} - - -size_t HUFv05_decompress1X4_usingDTable( - void* dst, size_t dstSize, - const void* cSrc, size_t cSrcSize, - const unsigned* DTable) -{ - const BYTE* const istart = (const BYTE*) cSrc; - BYTE* const ostart = (BYTE*) dst; - BYTE* const oend = ostart + dstSize; - - const U32 dtLog = DTable[0]; - const void* const dtPtr = DTable; - const HUFv05_DEltX4* const dt = ((const HUFv05_DEltX4*)dtPtr) +1; - size_t errorCode; - - /* Init */ - BITv05_DStream_t bitD; - errorCode = BITv05_initDStream(&bitD, istart, cSrcSize); - if (HUFv05_isError(errorCode)) return errorCode; - - /* finish bitStreams one by one */ - HUFv05_decodeStreamX4(ostart, &bitD, oend, dt, dtLog); - - /* check */ - if (!BITv05_endOfDStream(&bitD)) return ERROR(corruption_detected); - - /* decoded size */ - return dstSize; -} - -size_t HUFv05_decompress1X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) -{ - HUFv05_CREATE_STATIC_DTABLEX4(DTable, HUFv05_MAX_TABLELOG); - const BYTE* ip = (const BYTE*) cSrc; - - size_t hSize = HUFv05_readDTableX4 (DTable, cSrc, cSrcSize); - if (HUFv05_isError(hSize)) return hSize; - if (hSize >= cSrcSize) return ERROR(srcSize_wrong); - ip += hSize; - cSrcSize -= hSize; - - return HUFv05_decompress1X4_usingDTable (dst, dstSize, ip, cSrcSize, DTable); -} - -size_t HUFv05_decompress4X4_usingDTable( - void* dst, size_t dstSize, - const void* cSrc, size_t cSrcSize, - const unsigned* DTable) -{ - if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */ - - { - const BYTE* const istart = (const BYTE*) cSrc; - BYTE* const ostart = (BYTE*) dst; - BYTE* const oend = ostart + dstSize; - const void* const dtPtr = DTable; - const HUFv05_DEltX4* const dt = ((const HUFv05_DEltX4*)dtPtr) +1; - const U32 dtLog = DTable[0]; - size_t errorCode; - - /* Init */ - BITv05_DStream_t bitD1; - BITv05_DStream_t bitD2; - BITv05_DStream_t bitD3; - BITv05_DStream_t bitD4; - const size_t length1 = MEM_readLE16(istart); - const size_t length2 = MEM_readLE16(istart+2); - const size_t length3 = MEM_readLE16(istart+4); - size_t length4; - const BYTE* const istart1 = istart + 6; /* jumpTable */ - const BYTE* const istart2 = istart1 + length1; - const BYTE* const istart3 = istart2 + length2; - const BYTE* const istart4 = istart3 + length3; - const size_t segmentSize = (dstSize+3) / 4; - BYTE* const opStart2 = ostart + segmentSize; - BYTE* const opStart3 = opStart2 + segmentSize; - BYTE* const opStart4 = opStart3 + segmentSize; - BYTE* op1 = ostart; - BYTE* op2 = opStart2; - BYTE* op3 = opStart3; - BYTE* op4 = opStart4; - U32 endSignal; - - length4 = cSrcSize - (length1 + length2 + length3 + 6); - if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */ - errorCode = BITv05_initDStream(&bitD1, istart1, length1); - if (HUFv05_isError(errorCode)) return errorCode; - errorCode = BITv05_initDStream(&bitD2, istart2, length2); - if (HUFv05_isError(errorCode)) return errorCode; - errorCode = BITv05_initDStream(&bitD3, istart3, length3); - if (HUFv05_isError(errorCode)) return errorCode; - errorCode = BITv05_initDStream(&bitD4, istart4, length4); - if (HUFv05_isError(errorCode)) return errorCode; - - /* 16-32 symbols per loop (4-8 symbols per stream) */ - endSignal = BITv05_reloadDStream(&bitD1) | BITv05_reloadDStream(&bitD2) | BITv05_reloadDStream(&bitD3) | BITv05_reloadDStream(&bitD4); - for ( ; (endSignal==BITv05_DStream_unfinished) && (op4<(oend-7)) ; ) { - HUFv05_DECODE_SYMBOLX4_2(op1, &bitD1); - HUFv05_DECODE_SYMBOLX4_2(op2, &bitD2); - HUFv05_DECODE_SYMBOLX4_2(op3, &bitD3); - HUFv05_DECODE_SYMBOLX4_2(op4, &bitD4); - HUFv05_DECODE_SYMBOLX4_1(op1, &bitD1); - HUFv05_DECODE_SYMBOLX4_1(op2, &bitD2); - HUFv05_DECODE_SYMBOLX4_1(op3, &bitD3); - HUFv05_DECODE_SYMBOLX4_1(op4, &bitD4); - HUFv05_DECODE_SYMBOLX4_2(op1, &bitD1); - HUFv05_DECODE_SYMBOLX4_2(op2, &bitD2); - HUFv05_DECODE_SYMBOLX4_2(op3, &bitD3); - HUFv05_DECODE_SYMBOLX4_2(op4, &bitD4); - HUFv05_DECODE_SYMBOLX4_0(op1, &bitD1); - HUFv05_DECODE_SYMBOLX4_0(op2, &bitD2); - HUFv05_DECODE_SYMBOLX4_0(op3, &bitD3); - HUFv05_DECODE_SYMBOLX4_0(op4, &bitD4); - - endSignal = BITv05_reloadDStream(&bitD1) | BITv05_reloadDStream(&bitD2) | BITv05_reloadDStream(&bitD3) | BITv05_reloadDStream(&bitD4); - } - - /* check corruption */ - if (op1 > opStart2) return ERROR(corruption_detected); - if (op2 > opStart3) return ERROR(corruption_detected); - if (op3 > opStart4) return ERROR(corruption_detected); - /* note : op4 supposed already verified within main loop */ - - /* finish bitStreams one by one */ - HUFv05_decodeStreamX4(op1, &bitD1, opStart2, dt, dtLog); - HUFv05_decodeStreamX4(op2, &bitD2, opStart3, dt, dtLog); - HUFv05_decodeStreamX4(op3, &bitD3, opStart4, dt, dtLog); - HUFv05_decodeStreamX4(op4, &bitD4, oend, dt, dtLog); - - /* check */ - endSignal = BITv05_endOfDStream(&bitD1) & BITv05_endOfDStream(&bitD2) & BITv05_endOfDStream(&bitD3) & BITv05_endOfDStream(&bitD4); - if (!endSignal) return ERROR(corruption_detected); - - /* decoded size */ - return dstSize; - } -} - - -size_t HUFv05_decompress4X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) -{ - HUFv05_CREATE_STATIC_DTABLEX4(DTable, HUFv05_MAX_TABLELOG); - const BYTE* ip = (const BYTE*) cSrc; - - size_t hSize = HUFv05_readDTableX4 (DTable, cSrc, cSrcSize); - if (HUFv05_isError(hSize)) return hSize; - if (hSize >= cSrcSize) return ERROR(srcSize_wrong); - ip += hSize; - cSrcSize -= hSize; - - return HUFv05_decompress4X4_usingDTable (dst, dstSize, ip, cSrcSize, DTable); -} - - -/* ********************************/ -/* Generic decompression selector */ -/* ********************************/ - -typedef struct { U32 tableTime; U32 decode256Time; } algo_time_t; -static const algo_time_t algoTime[16 /* Quantization */][3 /* single, double, quad */] = -{ - /* single, double, quad */ - {{0,0}, {1,1}, {2,2}}, /* Q==0 : impossible */ - {{0,0}, {1,1}, {2,2}}, /* Q==1 : impossible */ - {{ 38,130}, {1313, 74}, {2151, 38}}, /* Q == 2 : 12-18% */ - {{ 448,128}, {1353, 74}, {2238, 41}}, /* Q == 3 : 18-25% */ - {{ 556,128}, {1353, 74}, {2238, 47}}, /* Q == 4 : 25-32% */ - {{ 714,128}, {1418, 74}, {2436, 53}}, /* Q == 5 : 32-38% */ - {{ 883,128}, {1437, 74}, {2464, 61}}, /* Q == 6 : 38-44% */ - {{ 897,128}, {1515, 75}, {2622, 68}}, /* Q == 7 : 44-50% */ - {{ 926,128}, {1613, 75}, {2730, 75}}, /* Q == 8 : 50-56% */ - {{ 947,128}, {1729, 77}, {3359, 77}}, /* Q == 9 : 56-62% */ - {{1107,128}, {2083, 81}, {4006, 84}}, /* Q ==10 : 62-69% */ - {{1177,128}, {2379, 87}, {4785, 88}}, /* Q ==11 : 69-75% */ - {{1242,128}, {2415, 93}, {5155, 84}}, /* Q ==12 : 75-81% */ - {{1349,128}, {2644,106}, {5260,106}}, /* Q ==13 : 81-87% */ - {{1455,128}, {2422,124}, {4174,124}}, /* Q ==14 : 87-93% */ - {{ 722,128}, {1891,145}, {1936,146}}, /* Q ==15 : 93-99% */ -}; - -typedef size_t (*decompressionAlgo)(void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); - -size_t HUFv05_decompress (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) -{ - static const decompressionAlgo decompress[3] = { HUFv05_decompress4X2, HUFv05_decompress4X4, NULL }; - /* estimate decompression time */ - U32 Q; - const U32 D256 = (U32)(dstSize >> 8); - U32 Dtime[3]; - U32 algoNb = 0; - int n; - - /* validation checks */ - if (dstSize == 0) return ERROR(dstSize_tooSmall); - if (cSrcSize >= dstSize) return ERROR(corruption_detected); /* invalid, or not compressed, but not compressed already dealt with */ - if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */ - - /* decoder timing evaluation */ - Q = (U32)(cSrcSize * 16 / dstSize); /* Q < 16 since dstSize > cSrcSize */ - for (n=0; n<3; n++) - Dtime[n] = algoTime[Q][n].tableTime + (algoTime[Q][n].decode256Time * D256); - - Dtime[1] += Dtime[1] >> 4; Dtime[2] += Dtime[2] >> 3; /* advantage to algorithms using less memory, for cache eviction */ - - if (Dtime[1] < Dtime[0]) algoNb = 1; - - return decompress[algoNb](dst, dstSize, cSrc, cSrcSize); - - /* return HUFv05_decompress4X2(dst, dstSize, cSrc, cSrcSize); */ /* multi-streams single-symbol decoding */ - /* return HUFv05_decompress4X4(dst, dstSize, cSrc, cSrcSize); */ /* multi-streams double-symbols decoding */ - /* return HUFv05_decompress4X6(dst, dstSize, cSrc, cSrcSize); */ /* multi-streams quad-symbols decoding */ -} -/* - zstd - standard compression library - Copyright (C) 2014-2016, Yann Collet. - - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - zstd source repository : https://github.com/Cyan4973/zstd -*/ - -/* *************************************************************** -* Tuning parameters -*****************************************************************/ -/*! - * HEAPMODE : - * Select how default decompression function ZSTDv05_decompress() will allocate memory, - * in memory stack (0), or in memory heap (1, requires malloc()) - */ -#ifndef ZSTDv05_HEAPMODE -# define ZSTDv05_HEAPMODE 1 -#endif - - -/*-******************************************************* -* Dependencies -*********************************************************/ -#include /* calloc */ -#include /* memcpy, memmove */ -#include /* debug only : printf */ - - -/*-******************************************************* -* Compiler specifics -*********************************************************/ -#ifdef _MSC_VER /* Visual Studio */ -# include /* For Visual 2005 */ -# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -# pragma warning(disable : 4324) /* disable: C4324: padded structure */ -#endif - - -/*-************************************* -* Local types -***************************************/ -typedef struct -{ - blockType_t blockType; - U32 origSize; -} blockProperties_t; - - -/* ******************************************************* -* Memory operations -**********************************************************/ -static void ZSTDv05_copy4(void* dst, const void* src) { memcpy(dst, src, 4); } - - -/* ************************************* -* Error Management -***************************************/ -/*! ZSTDv05_isError() : -* tells if a return value is an error code */ -unsigned ZSTDv05_isError(size_t code) { return ERR_isError(code); } - - -/*! ZSTDv05_getErrorName() : -* provides error code string (useful for debugging) */ -const char* ZSTDv05_getErrorName(size_t code) { return ERR_getErrorName(code); } - - -/* ************************************************************* -* Context management -***************************************************************/ -typedef enum { ZSTDv05ds_getFrameHeaderSize, ZSTDv05ds_decodeFrameHeader, - ZSTDv05ds_decodeBlockHeader, ZSTDv05ds_decompressBlock } ZSTDv05_dStage; - -struct ZSTDv05_DCtx_s -{ - FSEv05_DTable LLTable[FSEv05_DTABLE_SIZE_U32(LLFSEv05Log)]; - FSEv05_DTable OffTable[FSEv05_DTABLE_SIZE_U32(OffFSEv05Log)]; - FSEv05_DTable MLTable[FSEv05_DTABLE_SIZE_U32(MLFSEv05Log)]; - unsigned hufTableX4[HUFv05_DTABLE_SIZE(ZSTD_HUFFDTABLE_CAPACITY_LOG)]; - const void* previousDstEnd; - const void* base; - const void* vBase; - const void* dictEnd; - size_t expected; - size_t headerSize; - ZSTDv05_parameters params; - blockType_t bType; /* used in ZSTDv05_decompressContinue(), to transfer blockType between header decoding and block decoding stages */ - ZSTDv05_dStage stage; - U32 flagStaticTables; - const BYTE* litPtr; - size_t litSize; - BYTE litBuffer[BLOCKSIZE + WILDCOPY_OVERLENGTH]; - BYTE headerBuffer[ZSTDv05_frameHeaderSize_max]; -}; /* typedef'd to ZSTDv05_DCtx within "zstd_static.h" */ - -size_t ZSTDv05_sizeofDCtx (void); /* Hidden declaration */ -size_t ZSTDv05_sizeofDCtx (void) { return sizeof(ZSTDv05_DCtx); } - -size_t ZSTDv05_decompressBegin(ZSTDv05_DCtx* dctx) -{ - dctx->expected = ZSTDv05_frameHeaderSize_min; - dctx->stage = ZSTDv05ds_getFrameHeaderSize; - dctx->previousDstEnd = NULL; - dctx->base = NULL; - dctx->vBase = NULL; - dctx->dictEnd = NULL; - dctx->hufTableX4[0] = ZSTD_HUFFDTABLE_CAPACITY_LOG; - dctx->flagStaticTables = 0; - return 0; -} - -ZSTDv05_DCtx* ZSTDv05_createDCtx(void) -{ - ZSTDv05_DCtx* dctx = (ZSTDv05_DCtx*)malloc(sizeof(ZSTDv05_DCtx)); - if (dctx==NULL) return NULL; - ZSTDv05_decompressBegin(dctx); - return dctx; -} - -size_t ZSTDv05_freeDCtx(ZSTDv05_DCtx* dctx) -{ - free(dctx); - return 0; /* reserved as a potential error code in the future */ -} - -void ZSTDv05_copyDCtx(ZSTDv05_DCtx* dstDCtx, const ZSTDv05_DCtx* srcDCtx) -{ - memcpy(dstDCtx, srcDCtx, - sizeof(ZSTDv05_DCtx) - (BLOCKSIZE+WILDCOPY_OVERLENGTH + ZSTDv05_frameHeaderSize_max)); /* no need to copy workspace */ -} - - -/* ************************************************************* -* Decompression section -***************************************************************/ - -/* Frame format description - Frame Header - [ Block Header - Block ] - Frame End - 1) Frame Header - - 4 bytes - Magic Number : ZSTDv05_MAGICNUMBER (defined within zstd_internal.h) - - 1 byte - Window Descriptor - 2) Block Header - - 3 bytes, starting with a 2-bits descriptor - Uncompressed, Compressed, Frame End, unused - 3) Block - See Block Format Description - 4) Frame End - - 3 bytes, compatible with Block Header -*/ - -/* Block format description - - Block = Literal Section - Sequences Section - Prerequisite : size of (compressed) block, maximum size of regenerated data - - 1) Literal Section - - 1.1) Header : 1-5 bytes - flags: 2 bits - 00 compressed by Huff0 - 01 unused - 10 is Raw (uncompressed) - 11 is Rle - Note : using 01 => Huff0 with precomputed table ? - Note : delta map ? => compressed ? - - 1.1.1) Huff0-compressed literal block : 3-5 bytes - srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream - srcSize < 1 KB => 3 bytes (2-2-10-10) - srcSize < 16KB => 4 bytes (2-2-14-14) - else => 5 bytes (2-2-18-18) - big endian convention - - 1.1.2) Raw (uncompressed) literal block header : 1-3 bytes - size : 5 bits: (IS_RAW<<6) + (0<<4) + size - 12 bits: (IS_RAW<<6) + (2<<4) + (size>>8) - size&255 - 20 bits: (IS_RAW<<6) + (3<<4) + (size>>16) - size>>8&255 - size&255 - - 1.1.3) Rle (repeated single byte) literal block header : 1-3 bytes - size : 5 bits: (IS_RLE<<6) + (0<<4) + size - 12 bits: (IS_RLE<<6) + (2<<4) + (size>>8) - size&255 - 20 bits: (IS_RLE<<6) + (3<<4) + (size>>16) - size>>8&255 - size&255 - - 1.1.4) Huff0-compressed literal block, using precomputed CTables : 3-5 bytes - srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream - srcSize < 1 KB => 3 bytes (2-2-10-10) - srcSize < 16KB => 4 bytes (2-2-14-14) - else => 5 bytes (2-2-18-18) - big endian convention - - 1- CTable available (stored into workspace ?) - 2- Small input (fast heuristic ? Full comparison ? depend on clevel ?) - - - 1.2) Literal block content - - 1.2.1) Huff0 block, using sizes from header - See Huff0 format - - 1.2.2) Huff0 block, using prepared table - - 1.2.3) Raw content - - 1.2.4) single byte - - - 2) Sequences section - TO DO -*/ - - -/** ZSTDv05_decodeFrameHeader_Part1() : -* decode the 1st part of the Frame Header, which tells Frame Header size. -* srcSize must be == ZSTDv05_frameHeaderSize_min. -* @return : the full size of the Frame Header */ -static size_t ZSTDv05_decodeFrameHeader_Part1(ZSTDv05_DCtx* zc, const void* src, size_t srcSize) -{ - U32 magicNumber; - if (srcSize != ZSTDv05_frameHeaderSize_min) - return ERROR(srcSize_wrong); - magicNumber = MEM_readLE32(src); - if (magicNumber != ZSTDv05_MAGICNUMBER) return ERROR(prefix_unknown); - zc->headerSize = ZSTDv05_frameHeaderSize_min; - return zc->headerSize; -} - - -size_t ZSTDv05_getFrameParams(ZSTDv05_parameters* params, const void* src, size_t srcSize) -{ - U32 magicNumber; - if (srcSize < ZSTDv05_frameHeaderSize_min) return ZSTDv05_frameHeaderSize_max; - magicNumber = MEM_readLE32(src); - if (magicNumber != ZSTDv05_MAGICNUMBER) return ERROR(prefix_unknown); - memset(params, 0, sizeof(*params)); - params->windowLog = (((const BYTE*)src)[4] & 15) + ZSTDv05_WINDOWLOG_ABSOLUTEMIN; - if ((((const BYTE*)src)[4] >> 4) != 0) return ERROR(frameParameter_unsupported); /* reserved bits */ - return 0; -} - -/** ZSTDv05_decodeFrameHeader_Part2() : -* decode the full Frame Header. -* srcSize must be the size provided by ZSTDv05_decodeFrameHeader_Part1(). -* @return : 0, or an error code, which can be tested using ZSTDv05_isError() */ -static size_t ZSTDv05_decodeFrameHeader_Part2(ZSTDv05_DCtx* zc, const void* src, size_t srcSize) -{ - size_t result; - if (srcSize != zc->headerSize) - return ERROR(srcSize_wrong); - result = ZSTDv05_getFrameParams(&(zc->params), src, srcSize); - if ((MEM_32bits()) && (zc->params.windowLog > 25)) return ERROR(frameParameter_unsupported); - return result; -} - - -static size_t ZSTDv05_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr) -{ - const BYTE* const in = (const BYTE*)src; - BYTE headerFlags; - U32 cSize; - - if (srcSize < 3) - return ERROR(srcSize_wrong); - - headerFlags = *in; - cSize = in[2] + (in[1]<<8) + ((in[0] & 7)<<16); - - bpPtr->blockType = (blockType_t)(headerFlags >> 6); - bpPtr->origSize = (bpPtr->blockType == bt_rle) ? cSize : 0; - - if (bpPtr->blockType == bt_end) return 0; - if (bpPtr->blockType == bt_rle) return 1; - return cSize; -} - - -static size_t ZSTDv05_copyRawBlock(void* dst, size_t maxDstSize, const void* src, size_t srcSize) -{ - if (dst==NULL) return ERROR(dstSize_tooSmall); - if (srcSize > maxDstSize) return ERROR(dstSize_tooSmall); - memcpy(dst, src, srcSize); - return srcSize; -} - - -/*! ZSTDv05_decodeLiteralsBlock() : - @return : nb of bytes read from src (< srcSize ) */ -static size_t ZSTDv05_decodeLiteralsBlock(ZSTDv05_DCtx* dctx, - const void* src, size_t srcSize) /* note : srcSize < BLOCKSIZE */ -{ - const BYTE* const istart = (const BYTE*) src; - - /* any compressed block with literals segment must be at least this size */ - if (srcSize < MIN_CBLOCK_SIZE) return ERROR(corruption_detected); - - switch(istart[0]>> 6) - { - case IS_HUFv05: - { - size_t litSize, litCSize, singleStream=0; - U32 lhSize = ((istart[0]) >> 4) & 3; - if (srcSize < 5) return ERROR(corruption_detected); /* srcSize >= MIN_CBLOCK_SIZE == 3; here we need up to 5 for case 3 */ - switch(lhSize) - { - case 0: case 1: default: /* note : default is impossible, since lhSize into [0..3] */ - /* 2 - 2 - 10 - 10 */ - lhSize=3; - singleStream = istart[0] & 16; - litSize = ((istart[0] & 15) << 6) + (istart[1] >> 2); - litCSize = ((istart[1] & 3) << 8) + istart[2]; - break; - case 2: - /* 2 - 2 - 14 - 14 */ - lhSize=4; - litSize = ((istart[0] & 15) << 10) + (istart[1] << 2) + (istart[2] >> 6); - litCSize = ((istart[2] & 63) << 8) + istart[3]; - break; - case 3: - /* 2 - 2 - 18 - 18 */ - lhSize=5; - litSize = ((istart[0] & 15) << 14) + (istart[1] << 6) + (istart[2] >> 2); - litCSize = ((istart[2] & 3) << 16) + (istart[3] << 8) + istart[4]; - break; - } - if (litSize > BLOCKSIZE) return ERROR(corruption_detected); - if (litCSize + lhSize > srcSize) return ERROR(corruption_detected); - - if (HUFv05_isError(singleStream ? - HUFv05_decompress1X2(dctx->litBuffer, litSize, istart+lhSize, litCSize) : - HUFv05_decompress (dctx->litBuffer, litSize, istart+lhSize, litCSize) )) - return ERROR(corruption_detected); - - dctx->litPtr = dctx->litBuffer; - dctx->litSize = litSize; - memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH); - return litCSize + lhSize; - } - case IS_PCH: - { - size_t errorCode; - size_t litSize, litCSize; - U32 lhSize = ((istart[0]) >> 4) & 3; - if (lhSize != 1) /* only case supported for now : small litSize, single stream */ - return ERROR(corruption_detected); - if (!dctx->flagStaticTables) - return ERROR(dictionary_corrupted); - - /* 2 - 2 - 10 - 10 */ - lhSize=3; - litSize = ((istart[0] & 15) << 6) + (istart[1] >> 2); - litCSize = ((istart[1] & 3) << 8) + istart[2]; - if (litCSize + lhSize > srcSize) return ERROR(corruption_detected); - - errorCode = HUFv05_decompress1X4_usingDTable(dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->hufTableX4); - if (HUFv05_isError(errorCode)) return ERROR(corruption_detected); - - dctx->litPtr = dctx->litBuffer; - dctx->litSize = litSize; - memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH); - return litCSize + lhSize; - } - case IS_RAW: - { - size_t litSize; - U32 lhSize = ((istart[0]) >> 4) & 3; - switch(lhSize) - { - case 0: case 1: default: /* note : default is impossible, since lhSize into [0..3] */ - lhSize=1; - litSize = istart[0] & 31; - break; - case 2: - litSize = ((istart[0] & 15) << 8) + istart[1]; - break; - case 3: - litSize = ((istart[0] & 15) << 16) + (istart[1] << 8) + istart[2]; - break; - } - - if (lhSize+litSize+WILDCOPY_OVERLENGTH > srcSize) { /* risk reading beyond src buffer with wildcopy */ - if (litSize+lhSize > srcSize) return ERROR(corruption_detected); - memcpy(dctx->litBuffer, istart+lhSize, litSize); - dctx->litPtr = dctx->litBuffer; - dctx->litSize = litSize; - memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH); - return lhSize+litSize; - } - /* direct reference into compressed stream */ - dctx->litPtr = istart+lhSize; - dctx->litSize = litSize; - return lhSize+litSize; - } - case IS_RLE: - { - size_t litSize; - U32 lhSize = ((istart[0]) >> 4) & 3; - switch(lhSize) - { - case 0: case 1: default: /* note : default is impossible, since lhSize into [0..3] */ - lhSize = 1; - litSize = istart[0] & 31; - break; - case 2: - litSize = ((istart[0] & 15) << 8) + istart[1]; - break; - case 3: - litSize = ((istart[0] & 15) << 16) + (istart[1] << 8) + istart[2]; - if (srcSize<4) return ERROR(corruption_detected); /* srcSize >= MIN_CBLOCK_SIZE == 3; here we need lhSize+1 = 4 */ - break; - } - if (litSize > BLOCKSIZE) return ERROR(corruption_detected); - memset(dctx->litBuffer, istart[lhSize], litSize + WILDCOPY_OVERLENGTH); - dctx->litPtr = dctx->litBuffer; - dctx->litSize = litSize; - return lhSize+1; - } - default: - return ERROR(corruption_detected); /* impossible */ - } -} - - -static size_t ZSTDv05_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* dumpsLengthPtr, - FSEv05_DTable* DTableLL, FSEv05_DTable* DTableML, FSEv05_DTable* DTableOffb, - const void* src, size_t srcSize, U32 flagStaticTable) -{ - const BYTE* const istart = (const BYTE*)src; - const BYTE* ip = istart; - const BYTE* const iend = istart + srcSize; - U32 LLtype, Offtype, MLtype; - unsigned LLlog, Offlog, MLlog; - size_t dumpsLength; - - /* check */ - if (srcSize < MIN_SEQUENCES_SIZE) - return ERROR(srcSize_wrong); - - /* SeqHead */ - *nbSeq = *ip++; - if (*nbSeq==0) return 1; - if (*nbSeq >= 128) { - if (ip >= iend) return ERROR(srcSize_wrong); - *nbSeq = ((nbSeq[0]-128)<<8) + *ip++; - } - - if (ip >= iend) return ERROR(srcSize_wrong); - LLtype = *ip >> 6; - Offtype = (*ip >> 4) & 3; - MLtype = (*ip >> 2) & 3; - if (*ip & 2) { - if (ip+3 > iend) return ERROR(srcSize_wrong); - dumpsLength = ip[2]; - dumpsLength += ip[1] << 8; - ip += 3; - } else { - if (ip+2 > iend) return ERROR(srcSize_wrong); - dumpsLength = ip[1]; - dumpsLength += (ip[0] & 1) << 8; - ip += 2; - } - *dumpsPtr = ip; - ip += dumpsLength; - *dumpsLengthPtr = dumpsLength; - - /* check */ - if (ip > iend-3) return ERROR(srcSize_wrong); /* min : all 3 are "raw", hence no header, but at least xxLog bits per type */ - - /* sequences */ - { - S16 norm[MaxML+1]; /* assumption : MaxML >= MaxLL >= MaxOff */ - size_t headerSize; - - /* Build DTables */ - switch(LLtype) - { - case FSEv05_ENCODING_RLE : - LLlog = 0; - FSEv05_buildDTable_rle(DTableLL, *ip++); - break; - case FSEv05_ENCODING_RAW : - LLlog = LLbits; - FSEv05_buildDTable_raw(DTableLL, LLbits); - break; - case FSEv05_ENCODING_STATIC: - if (!flagStaticTable) return ERROR(corruption_detected); - break; - case FSEv05_ENCODING_DYNAMIC : - default : /* impossible */ - { unsigned max = MaxLL; - headerSize = FSEv05_readNCount(norm, &max, &LLlog, ip, iend-ip); - if (FSEv05_isError(headerSize)) return ERROR(GENERIC); - if (LLlog > LLFSEv05Log) return ERROR(corruption_detected); - ip += headerSize; - FSEv05_buildDTable(DTableLL, norm, max, LLlog); - } } - - switch(Offtype) - { - case FSEv05_ENCODING_RLE : - Offlog = 0; - if (ip > iend-2) return ERROR(srcSize_wrong); /* min : "raw", hence no header, but at least xxLog bits */ - FSEv05_buildDTable_rle(DTableOffb, *ip++ & MaxOff); /* if *ip > MaxOff, data is corrupted */ - break; - case FSEv05_ENCODING_RAW : - Offlog = Offbits; - FSEv05_buildDTable_raw(DTableOffb, Offbits); - break; - case FSEv05_ENCODING_STATIC: - if (!flagStaticTable) return ERROR(corruption_detected); - break; - case FSEv05_ENCODING_DYNAMIC : - default : /* impossible */ - { unsigned max = MaxOff; - headerSize = FSEv05_readNCount(norm, &max, &Offlog, ip, iend-ip); - if (FSEv05_isError(headerSize)) return ERROR(GENERIC); - if (Offlog > OffFSEv05Log) return ERROR(corruption_detected); - ip += headerSize; - FSEv05_buildDTable(DTableOffb, norm, max, Offlog); - } } - - switch(MLtype) - { - case FSEv05_ENCODING_RLE : - MLlog = 0; - if (ip > iend-2) return ERROR(srcSize_wrong); /* min : "raw", hence no header, but at least xxLog bits */ - FSEv05_buildDTable_rle(DTableML, *ip++); - break; - case FSEv05_ENCODING_RAW : - MLlog = MLbits; - FSEv05_buildDTable_raw(DTableML, MLbits); - break; - case FSEv05_ENCODING_STATIC: - if (!flagStaticTable) return ERROR(corruption_detected); - break; - case FSEv05_ENCODING_DYNAMIC : - default : /* impossible */ - { unsigned max = MaxML; - headerSize = FSEv05_readNCount(norm, &max, &MLlog, ip, iend-ip); - if (FSEv05_isError(headerSize)) return ERROR(GENERIC); - if (MLlog > MLFSEv05Log) return ERROR(corruption_detected); - ip += headerSize; - FSEv05_buildDTable(DTableML, norm, max, MLlog); - } } } - - return ip-istart; -} - - -typedef struct { - size_t litLength; - size_t matchLength; - size_t offset; -} seq_t; - -typedef struct { - BITv05_DStream_t DStream; - FSEv05_DState_t stateLL; - FSEv05_DState_t stateOffb; - FSEv05_DState_t stateML; - size_t prevOffset; - const BYTE* dumps; - const BYTE* dumpsEnd; -} seqState_t; - - - -static void ZSTDv05_decodeSequence(seq_t* seq, seqState_t* seqState) -{ - size_t litLength; - size_t prevOffset; - size_t offset; - size_t matchLength; - const BYTE* dumps = seqState->dumps; - const BYTE* const de = seqState->dumpsEnd; - - /* Literal length */ - litLength = FSEv05_peakSymbol(&(seqState->stateLL)); - prevOffset = litLength ? seq->offset : seqState->prevOffset; - if (litLength == MaxLL) { - const U32 add = *dumps++; - if (add < 255) litLength += add; - else if (dumps + 2 <= de) { - litLength = MEM_readLE16(dumps); - dumps += 2; - if ((litLength & 1) && dumps < de) { - litLength += *dumps << 16; - dumps += 1; - } - litLength>>=1; - } - if (dumps >= de) { dumps = de-1; } /* late correction, to avoid read overflow (data is now corrupted anyway) */ - } - - /* Offset */ - { - static const U32 offsetPrefix[MaxOff+1] = { - 1 /*fake*/, 1, 2, 4, 8, 16, 32, 64, 128, 256, - 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, - 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, /*fake*/ 1, 1, 1, 1, 1 }; - U32 offsetCode = FSEv05_peakSymbol(&(seqState->stateOffb)); /* <= maxOff, by table construction */ - U32 nbBits = offsetCode - 1; - if (offsetCode==0) nbBits = 0; /* cmove */ - offset = offsetPrefix[offsetCode] + BITv05_readBits(&(seqState->DStream), nbBits); - if (MEM_32bits()) BITv05_reloadDStream(&(seqState->DStream)); - if (offsetCode==0) offset = prevOffset; /* repcode, cmove */ - if (offsetCode | !litLength) seqState->prevOffset = seq->offset; /* cmove */ - FSEv05_decodeSymbol(&(seqState->stateOffb), &(seqState->DStream)); /* update */ - } - - /* Literal length update */ - FSEv05_decodeSymbol(&(seqState->stateLL), &(seqState->DStream)); /* update */ - if (MEM_32bits()) BITv05_reloadDStream(&(seqState->DStream)); - - /* MatchLength */ - matchLength = FSEv05_decodeSymbol(&(seqState->stateML), &(seqState->DStream)); - if (matchLength == MaxML) { - const U32 add = dumps>= 1; - } - if (dumps >= de) { dumps = de-1; } /* late correction, to avoid read overflow (data is now corrupted anyway) */ - } - matchLength += MINMATCH; - - /* save result */ - seq->litLength = litLength; - seq->offset = offset; - seq->matchLength = matchLength; - seqState->dumps = dumps; - -#if 0 /* debug */ - { - static U64 totalDecoded = 0; - printf("pos %6u : %3u literals & match %3u bytes at distance %6u \n", - (U32)(totalDecoded), (U32)litLength, (U32)matchLength, (U32)offset); - totalDecoded += litLength + matchLength; - } -#endif -} - - -static size_t ZSTDv05_execSequence(BYTE* op, - BYTE* const oend, seq_t sequence, - const BYTE** litPtr, const BYTE* const litLimit, - const BYTE* const base, const BYTE* const vBase, const BYTE* const dictEnd) -{ - static const int dec32table[] = { 0, 1, 2, 1, 4, 4, 4, 4 }; /* added */ - static const int dec64table[] = { 8, 8, 8, 7, 8, 9,10,11 }; /* subtracted */ - BYTE* const oLitEnd = op + sequence.litLength; - const size_t sequenceLength = sequence.litLength + sequence.matchLength; - BYTE* const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */ - BYTE* const oend_8 = oend-8; - const BYTE* const litEnd = *litPtr + sequence.litLength; - const BYTE* match = oLitEnd - sequence.offset; - - /* checks */ - size_t const seqLength = sequence.litLength + sequence.matchLength; - - if (seqLength > (size_t)(oend - op)) return ERROR(dstSize_tooSmall); - if (sequence.litLength > (size_t)(litLimit - *litPtr)) return ERROR(corruption_detected); - /* Now we know there are no overflow in literal nor match lengths, can use pointer checks */ - if (oLitEnd > oend_8) return ERROR(dstSize_tooSmall); - - if (oMatchEnd > oend) return ERROR(dstSize_tooSmall); /* overwrite beyond dst buffer */ - if (litEnd > litLimit) return ERROR(corruption_detected); /* overRead beyond lit buffer */ - - /* copy Literals */ - ZSTDv05_wildcopy(op, *litPtr, (ptrdiff_t)sequence.litLength); /* note : oLitEnd <= oend-8 : no risk of overwrite beyond oend */ - op = oLitEnd; - *litPtr = litEnd; /* update for next sequence */ - - /* copy Match */ - if (sequence.offset > (size_t)(oLitEnd - base)) { - /* offset beyond prefix */ - if (sequence.offset > (size_t)(oLitEnd - vBase)) - return ERROR(corruption_detected); - match = dictEnd - (base-match); - if (match + sequence.matchLength <= dictEnd) { - memmove(oLitEnd, match, sequence.matchLength); - return sequenceLength; - } - /* span extDict & currentPrefixSegment */ - { - size_t length1 = dictEnd - match; - memmove(oLitEnd, match, length1); - op = oLitEnd + length1; - sequence.matchLength -= length1; - match = base; - if (op > oend_8 || sequence.matchLength < MINMATCH) { - while (op < oMatchEnd) *op++ = *match++; - return sequenceLength; - } - } } - /* Requirement: op <= oend_8 */ - - /* match within prefix */ - if (sequence.offset < 8) { - /* close range match, overlap */ - const int sub2 = dec64table[sequence.offset]; - op[0] = match[0]; - op[1] = match[1]; - op[2] = match[2]; - op[3] = match[3]; - match += dec32table[sequence.offset]; - ZSTDv05_copy4(op+4, match); - match -= sub2; - } else { - ZSTDv05_copy8(op, match); - } - op += 8; match += 8; - - if (oMatchEnd > oend-(16-MINMATCH)) { - if (op < oend_8) { - ZSTDv05_wildcopy(op, match, oend_8 - op); - match += oend_8 - op; - op = oend_8; - } - while (op < oMatchEnd) - *op++ = *match++; - } else { - ZSTDv05_wildcopy(op, match, (ptrdiff_t)sequence.matchLength-8); /* works even if matchLength < 8 */ - } - return sequenceLength; -} - - -static size_t ZSTDv05_decompressSequences( - ZSTDv05_DCtx* dctx, - void* dst, size_t maxDstSize, - const void* seqStart, size_t seqSize) -{ - const BYTE* ip = (const BYTE*)seqStart; - const BYTE* const iend = ip + seqSize; - BYTE* const ostart = (BYTE*)dst; - BYTE* op = ostart; - BYTE* const oend = ostart + maxDstSize; - size_t errorCode, dumpsLength=0; - const BYTE* litPtr = dctx->litPtr; - const BYTE* const litEnd = litPtr + dctx->litSize; - int nbSeq=0; - const BYTE* dumps = NULL; - unsigned* DTableLL = dctx->LLTable; - unsigned* DTableML = dctx->MLTable; - unsigned* DTableOffb = dctx->OffTable; - const BYTE* const base = (const BYTE*) (dctx->base); - const BYTE* const vBase = (const BYTE*) (dctx->vBase); - const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd); - - /* Build Decoding Tables */ - errorCode = ZSTDv05_decodeSeqHeaders(&nbSeq, &dumps, &dumpsLength, - DTableLL, DTableML, DTableOffb, - ip, seqSize, dctx->flagStaticTables); - if (ZSTDv05_isError(errorCode)) return errorCode; - ip += errorCode; - - /* Regen sequences */ - if (nbSeq) { - seq_t sequence; - seqState_t seqState; - - memset(&sequence, 0, sizeof(sequence)); - sequence.offset = REPCODE_STARTVALUE; - seqState.dumps = dumps; - seqState.dumpsEnd = dumps + dumpsLength; - seqState.prevOffset = REPCODE_STARTVALUE; - errorCode = BITv05_initDStream(&(seqState.DStream), ip, iend-ip); - if (ERR_isError(errorCode)) return ERROR(corruption_detected); - FSEv05_initDState(&(seqState.stateLL), &(seqState.DStream), DTableLL); - FSEv05_initDState(&(seqState.stateOffb), &(seqState.DStream), DTableOffb); - FSEv05_initDState(&(seqState.stateML), &(seqState.DStream), DTableML); - - for ( ; (BITv05_reloadDStream(&(seqState.DStream)) <= BITv05_DStream_completed) && nbSeq ; ) { - size_t oneSeqSize; - nbSeq--; - ZSTDv05_decodeSequence(&sequence, &seqState); - oneSeqSize = ZSTDv05_execSequence(op, oend, sequence, &litPtr, litEnd, base, vBase, dictEnd); - if (ZSTDv05_isError(oneSeqSize)) return oneSeqSize; - op += oneSeqSize; - } - - /* check if reached exact end */ - if (nbSeq) return ERROR(corruption_detected); - } - - /* last literal segment */ - { - size_t lastLLSize = litEnd - litPtr; - if (litPtr > litEnd) return ERROR(corruption_detected); /* too many literals already used */ - if (op+lastLLSize > oend) return ERROR(dstSize_tooSmall); - if (lastLLSize > 0) { - memcpy(op, litPtr, lastLLSize); - op += lastLLSize; - } - } - - return op-ostart; -} - - -static void ZSTDv05_checkContinuity(ZSTDv05_DCtx* dctx, const void* dst) -{ - if (dst != dctx->previousDstEnd) { /* not contiguous */ - dctx->dictEnd = dctx->previousDstEnd; - dctx->vBase = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->base)); - dctx->base = dst; - dctx->previousDstEnd = dst; - } -} - - -static size_t ZSTDv05_decompressBlock_internal(ZSTDv05_DCtx* dctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize) -{ /* blockType == blockCompressed */ - const BYTE* ip = (const BYTE*)src; - size_t litCSize; - - if (srcSize >= BLOCKSIZE) return ERROR(srcSize_wrong); - - /* Decode literals sub-block */ - litCSize = ZSTDv05_decodeLiteralsBlock(dctx, src, srcSize); - if (ZSTDv05_isError(litCSize)) return litCSize; - ip += litCSize; - srcSize -= litCSize; - - return ZSTDv05_decompressSequences(dctx, dst, dstCapacity, ip, srcSize); -} - - -size_t ZSTDv05_decompressBlock(ZSTDv05_DCtx* dctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize) -{ - ZSTDv05_checkContinuity(dctx, dst); - return ZSTDv05_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize); -} - - -/*! ZSTDv05_decompress_continueDCtx -* dctx must have been properly initialized */ -static size_t ZSTDv05_decompress_continueDCtx(ZSTDv05_DCtx* dctx, - void* dst, size_t maxDstSize, - const void* src, size_t srcSize) -{ - const BYTE* ip = (const BYTE*)src; - const BYTE* iend = ip + srcSize; - BYTE* const ostart = (BYTE*)dst; - BYTE* op = ostart; - BYTE* const oend = ostart + maxDstSize; - size_t remainingSize = srcSize; - blockProperties_t blockProperties; - memset(&blockProperties, 0, sizeof(blockProperties)); - - /* Frame Header */ - { size_t frameHeaderSize; - if (srcSize < ZSTDv05_frameHeaderSize_min+ZSTDv05_blockHeaderSize) return ERROR(srcSize_wrong); - frameHeaderSize = ZSTDv05_decodeFrameHeader_Part1(dctx, src, ZSTDv05_frameHeaderSize_min); - if (ZSTDv05_isError(frameHeaderSize)) return frameHeaderSize; - if (srcSize < frameHeaderSize+ZSTDv05_blockHeaderSize) return ERROR(srcSize_wrong); - ip += frameHeaderSize; remainingSize -= frameHeaderSize; - frameHeaderSize = ZSTDv05_decodeFrameHeader_Part2(dctx, src, frameHeaderSize); - if (ZSTDv05_isError(frameHeaderSize)) return frameHeaderSize; - } - - /* Loop on each block */ - while (1) - { - size_t decodedSize=0; - size_t cBlockSize = ZSTDv05_getcBlockSize(ip, iend-ip, &blockProperties); - if (ZSTDv05_isError(cBlockSize)) return cBlockSize; - - ip += ZSTDv05_blockHeaderSize; - remainingSize -= ZSTDv05_blockHeaderSize; - if (cBlockSize > remainingSize) return ERROR(srcSize_wrong); - - switch(blockProperties.blockType) - { - case bt_compressed: - decodedSize = ZSTDv05_decompressBlock_internal(dctx, op, oend-op, ip, cBlockSize); - break; - case bt_raw : - decodedSize = ZSTDv05_copyRawBlock(op, oend-op, ip, cBlockSize); - break; - case bt_rle : - return ERROR(GENERIC); /* not yet supported */ - break; - case bt_end : - /* end of frame */ - if (remainingSize) return ERROR(srcSize_wrong); - break; - default: - return ERROR(GENERIC); /* impossible */ - } - if (cBlockSize == 0) break; /* bt_end */ - - if (ZSTDv05_isError(decodedSize)) return decodedSize; - op += decodedSize; - ip += cBlockSize; - remainingSize -= cBlockSize; - } - - return op-ostart; -} - - -size_t ZSTDv05_decompress_usingPreparedDCtx(ZSTDv05_DCtx* dctx, const ZSTDv05_DCtx* refDCtx, - void* dst, size_t maxDstSize, - const void* src, size_t srcSize) -{ - ZSTDv05_copyDCtx(dctx, refDCtx); - ZSTDv05_checkContinuity(dctx, dst); - return ZSTDv05_decompress_continueDCtx(dctx, dst, maxDstSize, src, srcSize); -} - - -size_t ZSTDv05_decompress_usingDict(ZSTDv05_DCtx* dctx, - void* dst, size_t maxDstSize, - const void* src, size_t srcSize, - const void* dict, size_t dictSize) -{ - ZSTDv05_decompressBegin_usingDict(dctx, dict, dictSize); - ZSTDv05_checkContinuity(dctx, dst); - return ZSTDv05_decompress_continueDCtx(dctx, dst, maxDstSize, src, srcSize); -} - - -size_t ZSTDv05_decompressDCtx(ZSTDv05_DCtx* dctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize) -{ - return ZSTDv05_decompress_usingDict(dctx, dst, maxDstSize, src, srcSize, NULL, 0); -} - -size_t ZSTDv05_decompress(void* dst, size_t maxDstSize, const void* src, size_t srcSize) -{ -#if defined(ZSTDv05_HEAPMODE) && (ZSTDv05_HEAPMODE==1) - size_t regenSize; - ZSTDv05_DCtx* dctx = ZSTDv05_createDCtx(); - if (dctx==NULL) return ERROR(memory_allocation); - regenSize = ZSTDv05_decompressDCtx(dctx, dst, maxDstSize, src, srcSize); - ZSTDv05_freeDCtx(dctx); - return regenSize; -#else - ZSTDv05_DCtx dctx; - return ZSTDv05_decompressDCtx(&dctx, dst, maxDstSize, src, srcSize); -#endif -} - -/* ZSTD_errorFrameSizeInfoLegacy() : - assumes `cSize` and `dBound` are _not_ NULL */ -static void ZSTD_errorFrameSizeInfoLegacy(size_t* cSize, unsigned long long* dBound, size_t ret) -{ - *cSize = ret; - *dBound = ZSTD_CONTENTSIZE_ERROR; -} - -void ZSTDv05_findFrameSizeInfoLegacy(const void *src, size_t srcSize, size_t* cSize, unsigned long long* dBound) -{ - const BYTE* ip = (const BYTE*)src; - size_t remainingSize = srcSize; - size_t nbBlocks = 0; - blockProperties_t blockProperties; - - /* Frame Header */ - if (srcSize < ZSTDv05_frameHeaderSize_min) { - ZSTD_errorFrameSizeInfoLegacy(cSize, dBound, ERROR(srcSize_wrong)); - return; - } - if (MEM_readLE32(src) != ZSTDv05_MAGICNUMBER) { - ZSTD_errorFrameSizeInfoLegacy(cSize, dBound, ERROR(prefix_unknown)); - return; - } - ip += ZSTDv05_frameHeaderSize_min; remainingSize -= ZSTDv05_frameHeaderSize_min; - - /* Loop on each block */ - while (1) - { - size_t cBlockSize = ZSTDv05_getcBlockSize(ip, remainingSize, &blockProperties); - if (ZSTDv05_isError(cBlockSize)) { - ZSTD_errorFrameSizeInfoLegacy(cSize, dBound, cBlockSize); - return; - } - - ip += ZSTDv05_blockHeaderSize; - remainingSize -= ZSTDv05_blockHeaderSize; - if (cBlockSize > remainingSize) { - ZSTD_errorFrameSizeInfoLegacy(cSize, dBound, ERROR(srcSize_wrong)); - return; - } - - if (cBlockSize == 0) break; /* bt_end */ - - ip += cBlockSize; - remainingSize -= cBlockSize; - nbBlocks++; - } - - *cSize = ip - (const BYTE*)src; - *dBound = nbBlocks * BLOCKSIZE; -} - -/* ****************************** -* Streaming Decompression API -********************************/ -size_t ZSTDv05_nextSrcSizeToDecompress(ZSTDv05_DCtx* dctx) -{ - return dctx->expected; -} - -size_t ZSTDv05_decompressContinue(ZSTDv05_DCtx* dctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize) -{ - /* Sanity check */ - if (srcSize != dctx->expected) return ERROR(srcSize_wrong); - ZSTDv05_checkContinuity(dctx, dst); - - /* Decompress : frame header; part 1 */ - switch (dctx->stage) - { - case ZSTDv05ds_getFrameHeaderSize : - /* get frame header size */ - if (srcSize != ZSTDv05_frameHeaderSize_min) return ERROR(srcSize_wrong); /* impossible */ - dctx->headerSize = ZSTDv05_decodeFrameHeader_Part1(dctx, src, ZSTDv05_frameHeaderSize_min); - if (ZSTDv05_isError(dctx->headerSize)) return dctx->headerSize; - memcpy(dctx->headerBuffer, src, ZSTDv05_frameHeaderSize_min); - if (dctx->headerSize > ZSTDv05_frameHeaderSize_min) return ERROR(GENERIC); /* should never happen */ - dctx->expected = 0; /* not necessary to copy more */ - /* fallthrough */ - case ZSTDv05ds_decodeFrameHeader: - /* get frame header */ - { size_t const result = ZSTDv05_decodeFrameHeader_Part2(dctx, dctx->headerBuffer, dctx->headerSize); - if (ZSTDv05_isError(result)) return result; - dctx->expected = ZSTDv05_blockHeaderSize; - dctx->stage = ZSTDv05ds_decodeBlockHeader; - return 0; - } - case ZSTDv05ds_decodeBlockHeader: - { - /* Decode block header */ - blockProperties_t bp; - size_t blockSize = ZSTDv05_getcBlockSize(src, ZSTDv05_blockHeaderSize, &bp); - if (ZSTDv05_isError(blockSize)) return blockSize; - if (bp.blockType == bt_end) { - dctx->expected = 0; - dctx->stage = ZSTDv05ds_getFrameHeaderSize; - } - else { - dctx->expected = blockSize; - dctx->bType = bp.blockType; - dctx->stage = ZSTDv05ds_decompressBlock; - } - return 0; - } - case ZSTDv05ds_decompressBlock: - { - /* Decompress : block content */ - size_t rSize; - switch(dctx->bType) - { - case bt_compressed: - rSize = ZSTDv05_decompressBlock_internal(dctx, dst, maxDstSize, src, srcSize); - break; - case bt_raw : - rSize = ZSTDv05_copyRawBlock(dst, maxDstSize, src, srcSize); - break; - case bt_rle : - return ERROR(GENERIC); /* not yet handled */ - break; - case bt_end : /* should never happen (filtered at phase 1) */ - rSize = 0; - break; - default: - return ERROR(GENERIC); /* impossible */ - } - dctx->stage = ZSTDv05ds_decodeBlockHeader; - dctx->expected = ZSTDv05_blockHeaderSize; - if (ZSTDv05_isError(rSize)) return rSize; - dctx->previousDstEnd = (char*)dst + rSize; - return rSize; - } - default: - return ERROR(GENERIC); /* impossible */ - } -} - - -static void ZSTDv05_refDictContent(ZSTDv05_DCtx* dctx, const void* dict, size_t dictSize) -{ - dctx->dictEnd = dctx->previousDstEnd; - dctx->vBase = (const char*)dict - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->base)); - dctx->base = dict; - dctx->previousDstEnd = (const char*)dict + dictSize; -} - -static size_t ZSTDv05_loadEntropy(ZSTDv05_DCtx* dctx, const void* dict, size_t dictSize) -{ - size_t hSize, offcodeHeaderSize, matchlengthHeaderSize, errorCode, litlengthHeaderSize; - short offcodeNCount[MaxOff+1]; - unsigned offcodeMaxValue=MaxOff, offcodeLog; - short matchlengthNCount[MaxML+1]; - unsigned matchlengthMaxValue = MaxML, matchlengthLog; - short litlengthNCount[MaxLL+1]; - unsigned litlengthMaxValue = MaxLL, litlengthLog; - - hSize = HUFv05_readDTableX4(dctx->hufTableX4, dict, dictSize); - if (HUFv05_isError(hSize)) return ERROR(dictionary_corrupted); - dict = (const char*)dict + hSize; - dictSize -= hSize; - - offcodeHeaderSize = FSEv05_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dict, dictSize); - if (FSEv05_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted); - if (offcodeLog > OffFSEv05Log) return ERROR(dictionary_corrupted); - errorCode = FSEv05_buildDTable(dctx->OffTable, offcodeNCount, offcodeMaxValue, offcodeLog); - if (FSEv05_isError(errorCode)) return ERROR(dictionary_corrupted); - dict = (const char*)dict + offcodeHeaderSize; - dictSize -= offcodeHeaderSize; - - matchlengthHeaderSize = FSEv05_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dict, dictSize); - if (FSEv05_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted); - if (matchlengthLog > MLFSEv05Log) return ERROR(dictionary_corrupted); - errorCode = FSEv05_buildDTable(dctx->MLTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog); - if (FSEv05_isError(errorCode)) return ERROR(dictionary_corrupted); - dict = (const char*)dict + matchlengthHeaderSize; - dictSize -= matchlengthHeaderSize; - - litlengthHeaderSize = FSEv05_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dict, dictSize); - if (litlengthLog > LLFSEv05Log) return ERROR(dictionary_corrupted); - if (FSEv05_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted); - errorCode = FSEv05_buildDTable(dctx->LLTable, litlengthNCount, litlengthMaxValue, litlengthLog); - if (FSEv05_isError(errorCode)) return ERROR(dictionary_corrupted); - - dctx->flagStaticTables = 1; - return hSize + offcodeHeaderSize + matchlengthHeaderSize + litlengthHeaderSize; -} - -static size_t ZSTDv05_decompress_insertDictionary(ZSTDv05_DCtx* dctx, const void* dict, size_t dictSize) -{ - size_t eSize; - U32 magic = MEM_readLE32(dict); - if (magic != ZSTDv05_DICT_MAGIC) { - /* pure content mode */ - ZSTDv05_refDictContent(dctx, dict, dictSize); - return 0; - } - /* load entropy tables */ - dict = (const char*)dict + 4; - dictSize -= 4; - eSize = ZSTDv05_loadEntropy(dctx, dict, dictSize); - if (ZSTDv05_isError(eSize)) return ERROR(dictionary_corrupted); - - /* reference dictionary content */ - dict = (const char*)dict + eSize; - dictSize -= eSize; - ZSTDv05_refDictContent(dctx, dict, dictSize); - - return 0; -} - - -size_t ZSTDv05_decompressBegin_usingDict(ZSTDv05_DCtx* dctx, const void* dict, size_t dictSize) -{ - size_t errorCode; - errorCode = ZSTDv05_decompressBegin(dctx); - if (ZSTDv05_isError(errorCode)) return errorCode; - - if (dict && dictSize) { - errorCode = ZSTDv05_decompress_insertDictionary(dctx, dict, dictSize); - if (ZSTDv05_isError(errorCode)) return ERROR(dictionary_corrupted); - } - - return 0; -} - -/* - Buffered version of Zstd compression library - Copyright (C) 2015-2016, Yann Collet. - - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - zstd source repository : https://github.com/Cyan4973/zstd - - ztsd public forum : https://groups.google.com/forum/#!forum/lz4c -*/ - -/* The objects defined into this file should be considered experimental. - * They are not labelled stable, as their prototype may change in the future. - * You can use them for tests, provide feedback, or if you can endure risk of future changes. - */ - - - -/* ************************************* -* Constants -***************************************/ -static size_t ZBUFFv05_blockHeaderSize = 3; - - - -/* *** Compression *** */ - -static size_t ZBUFFv05_limitCopy(void* dst, size_t maxDstSize, const void* src, size_t srcSize) -{ - size_t length = MIN(maxDstSize, srcSize); - if (length > 0) { - memcpy(dst, src, length); - } - return length; -} - - - - -/** ************************************************ -* Streaming decompression -* -* A ZBUFFv05_DCtx object is required to track streaming operation. -* Use ZBUFFv05_createDCtx() and ZBUFFv05_freeDCtx() to create/release resources. -* Use ZBUFFv05_decompressInit() to start a new decompression operation. -* ZBUFFv05_DCtx objects can be reused multiple times. -* -* Use ZBUFFv05_decompressContinue() repetitively to consume your input. -* *srcSizePtr and *maxDstSizePtr can be any size. -* The function will report how many bytes were read or written by modifying *srcSizePtr and *maxDstSizePtr. -* 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. -* The content of dst will be overwritten (up to *maxDstSizePtr) at each function call, so save its content if it matters or change dst . -* return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to improve latency) -* or 0 when a frame is completely decoded -* or an error code, which can be tested using ZBUFFv05_isError(). -* -* Hint : recommended buffer sizes (not compulsory) -* output : 128 KB block size is the internal unit, it ensures it's always possible to write a full block when it's decoded. -* input : just follow indications from ZBUFFv05_decompressContinue() to minimize latency. It should always be <= 128 KB + 3 . -* **************************************************/ - -typedef enum { ZBUFFv05ds_init, ZBUFFv05ds_readHeader, ZBUFFv05ds_loadHeader, ZBUFFv05ds_decodeHeader, - ZBUFFv05ds_read, ZBUFFv05ds_load, ZBUFFv05ds_flush } ZBUFFv05_dStage; - -/* *** Resource management *** */ - -#define ZSTDv05_frameHeaderSize_max 5 /* too magical, should come from reference */ -struct ZBUFFv05_DCtx_s { - ZSTDv05_DCtx* zc; - ZSTDv05_parameters params; - char* inBuff; - size_t inBuffSize; - size_t inPos; - char* outBuff; - size_t outBuffSize; - size_t outStart; - size_t outEnd; - size_t hPos; - ZBUFFv05_dStage stage; - unsigned char headerBuffer[ZSTDv05_frameHeaderSize_max]; -}; /* typedef'd to ZBUFFv05_DCtx within "zstd_buffered.h" */ - - -ZBUFFv05_DCtx* ZBUFFv05_createDCtx(void) -{ - ZBUFFv05_DCtx* zbc = (ZBUFFv05_DCtx*)malloc(sizeof(ZBUFFv05_DCtx)); - if (zbc==NULL) return NULL; - memset(zbc, 0, sizeof(*zbc)); - zbc->zc = ZSTDv05_createDCtx(); - zbc->stage = ZBUFFv05ds_init; - return zbc; -} - -size_t ZBUFFv05_freeDCtx(ZBUFFv05_DCtx* zbc) -{ - if (zbc==NULL) return 0; /* support free on null */ - ZSTDv05_freeDCtx(zbc->zc); - free(zbc->inBuff); - free(zbc->outBuff); - free(zbc); - return 0; -} - - -/* *** Initialization *** */ - -size_t ZBUFFv05_decompressInitDictionary(ZBUFFv05_DCtx* zbc, const void* dict, size_t dictSize) -{ - zbc->stage = ZBUFFv05ds_readHeader; - zbc->hPos = zbc->inPos = zbc->outStart = zbc->outEnd = 0; - return ZSTDv05_decompressBegin_usingDict(zbc->zc, dict, dictSize); -} - -size_t ZBUFFv05_decompressInit(ZBUFFv05_DCtx* zbc) -{ - return ZBUFFv05_decompressInitDictionary(zbc, NULL, 0); -} - - -/* *** Decompression *** */ - -size_t ZBUFFv05_decompressContinue(ZBUFFv05_DCtx* zbc, void* dst, size_t* maxDstSizePtr, const void* src, size_t* srcSizePtr) -{ - const char* const istart = (const char*)src; - const char* ip = istart; - const char* const iend = istart + *srcSizePtr; - char* const ostart = (char*)dst; - char* op = ostart; - char* const oend = ostart + *maxDstSizePtr; - U32 notDone = 1; - - while (notDone) { - switch(zbc->stage) - { - case ZBUFFv05ds_init : - return ERROR(init_missing); - - case ZBUFFv05ds_readHeader : - /* read header from src */ - { - size_t headerSize = ZSTDv05_getFrameParams(&(zbc->params), src, *srcSizePtr); - if (ZSTDv05_isError(headerSize)) return headerSize; - if (headerSize) { - /* not enough input to decode header : tell how many bytes would be necessary */ - memcpy(zbc->headerBuffer+zbc->hPos, src, *srcSizePtr); - zbc->hPos += *srcSizePtr; - *maxDstSizePtr = 0; - zbc->stage = ZBUFFv05ds_loadHeader; - return headerSize - zbc->hPos; - } - zbc->stage = ZBUFFv05ds_decodeHeader; - break; - } - /* fall-through */ - case ZBUFFv05ds_loadHeader: - /* complete header from src */ - { - size_t headerSize = ZBUFFv05_limitCopy( - zbc->headerBuffer + zbc->hPos, ZSTDv05_frameHeaderSize_max - zbc->hPos, - src, *srcSizePtr); - zbc->hPos += headerSize; - ip += headerSize; - headerSize = ZSTDv05_getFrameParams(&(zbc->params), zbc->headerBuffer, zbc->hPos); - if (ZSTDv05_isError(headerSize)) return headerSize; - if (headerSize) { - /* not enough input to decode header : tell how many bytes would be necessary */ - *maxDstSizePtr = 0; - return headerSize - zbc->hPos; - } - /* zbc->stage = ZBUFFv05ds_decodeHeader; break; */ /* useless : stage follows */ - } - /* fall-through */ - case ZBUFFv05ds_decodeHeader: - /* apply header to create / resize buffers */ - { - size_t neededOutSize = (size_t)1 << zbc->params.windowLog; - size_t neededInSize = BLOCKSIZE; /* a block is never > BLOCKSIZE */ - if (zbc->inBuffSize < neededInSize) { - free(zbc->inBuff); - zbc->inBuffSize = neededInSize; - zbc->inBuff = (char*)malloc(neededInSize); - if (zbc->inBuff == NULL) return ERROR(memory_allocation); - } - if (zbc->outBuffSize < neededOutSize) { - free(zbc->outBuff); - zbc->outBuffSize = neededOutSize; - zbc->outBuff = (char*)malloc(neededOutSize); - if (zbc->outBuff == NULL) return ERROR(memory_allocation); - } } - if (zbc->hPos) { - /* some data already loaded into headerBuffer : transfer into inBuff */ - memcpy(zbc->inBuff, zbc->headerBuffer, zbc->hPos); - zbc->inPos = zbc->hPos; - zbc->hPos = 0; - zbc->stage = ZBUFFv05ds_load; - break; - } - zbc->stage = ZBUFFv05ds_read; - /* fall-through */ - case ZBUFFv05ds_read: - { - size_t neededInSize = ZSTDv05_nextSrcSizeToDecompress(zbc->zc); - if (neededInSize==0) { /* end of frame */ - zbc->stage = ZBUFFv05ds_init; - notDone = 0; - break; - } - if ((size_t)(iend-ip) >= neededInSize) { - /* directly decode from src */ - size_t decodedSize = ZSTDv05_decompressContinue(zbc->zc, - zbc->outBuff + zbc->outStart, zbc->outBuffSize - zbc->outStart, - ip, neededInSize); - if (ZSTDv05_isError(decodedSize)) return decodedSize; - ip += neededInSize; - if (!decodedSize) break; /* this was just a header */ - zbc->outEnd = zbc->outStart + decodedSize; - zbc->stage = ZBUFFv05ds_flush; - break; - } - if (ip==iend) { notDone = 0; break; } /* no more input */ - zbc->stage = ZBUFFv05ds_load; - } - /* fall-through */ - case ZBUFFv05ds_load: - { - size_t neededInSize = ZSTDv05_nextSrcSizeToDecompress(zbc->zc); - size_t toLoad = neededInSize - zbc->inPos; /* should always be <= remaining space within inBuff */ - size_t loadedSize; - if (toLoad > zbc->inBuffSize - zbc->inPos) return ERROR(corruption_detected); /* should never happen */ - loadedSize = ZBUFFv05_limitCopy(zbc->inBuff + zbc->inPos, toLoad, ip, iend-ip); - ip += loadedSize; - zbc->inPos += loadedSize; - if (loadedSize < toLoad) { notDone = 0; break; } /* not enough input, wait for more */ - { - size_t decodedSize = ZSTDv05_decompressContinue(zbc->zc, - zbc->outBuff + zbc->outStart, zbc->outBuffSize - zbc->outStart, - zbc->inBuff, neededInSize); - if (ZSTDv05_isError(decodedSize)) return decodedSize; - zbc->inPos = 0; /* input is consumed */ - if (!decodedSize) { zbc->stage = ZBUFFv05ds_read; break; } /* this was just a header */ - zbc->outEnd = zbc->outStart + decodedSize; - zbc->stage = ZBUFFv05ds_flush; - /* break; */ /* ZBUFFv05ds_flush follows */ - } - } - /* fall-through */ - case ZBUFFv05ds_flush: - { - size_t toFlushSize = zbc->outEnd - zbc->outStart; - size_t flushedSize = ZBUFFv05_limitCopy(op, oend-op, zbc->outBuff + zbc->outStart, toFlushSize); - op += flushedSize; - zbc->outStart += flushedSize; - if (flushedSize == toFlushSize) { - zbc->stage = ZBUFFv05ds_read; - if (zbc->outStart + BLOCKSIZE > zbc->outBuffSize) - zbc->outStart = zbc->outEnd = 0; - break; - } - /* cannot flush everything */ - notDone = 0; - break; - } - default: return ERROR(GENERIC); /* impossible */ - } } - - *srcSizePtr = ip-istart; - *maxDstSizePtr = op-ostart; - - { size_t nextSrcSizeHint = ZSTDv05_nextSrcSizeToDecompress(zbc->zc); - if (nextSrcSizeHint > ZBUFFv05_blockHeaderSize) nextSrcSizeHint+= ZBUFFv05_blockHeaderSize; /* get next block header too */ - nextSrcSizeHint -= zbc->inPos; /* already loaded*/ - return nextSrcSizeHint; - } -} - - - -/* ************************************* -* Tool functions -***************************************/ -unsigned ZBUFFv05_isError(size_t errorCode) { return ERR_isError(errorCode); } -const char* ZBUFFv05_getErrorName(size_t errorCode) { return ERR_getErrorName(errorCode); } - -size_t ZBUFFv05_recommendedDInSize(void) { return BLOCKSIZE + ZBUFFv05_blockHeaderSize /* block header size*/ ; } -size_t ZBUFFv05_recommendedDOutSize(void) { return BLOCKSIZE; } +/* Implementation moved to Rust (rust/src/legacy/zstd_v05.rs). + * The frozen v0.5 decoder, including its embedded FSE/Huff0 snapshot, frame + * state, and buffered streaming context, now lives entirely in Rust; C code + * only ever holds opaque ZSTDv05_DCtx and ZBUFFv05_DCtx pointers. */ diff --git a/lib/legacy/zstd_v06.c b/lib/legacy/zstd_v06.c index 88a39e2a0..f2a67d2f9 100644 --- a/lib/legacy/zstd_v06.c +++ b/lib/legacy/zstd_v06.c @@ -5,4106 +5,15 @@ * This source code is licensed under both the BSD-style license (found in the * LICENSE file in the root directory of this source tree) and the GPLv2 (found * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. + * You may select, at your option, one or both licenses. */ - -/*- Dependencies -*/ +#include /* size_t */ #include "zstd_v06.h" -#include /* size_t, ptrdiff_t */ -#include /* memcpy */ -#include /* malloc, free, qsort */ #include "../common/compiler.h" #include "../common/error_private.h" - - -/* ****************************************************************** - mem.h - low-level memory access routines - Copyright (C) 2013-2015, Yann Collet. - - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy - - Public forum : https://groups.google.com/forum/#!forum/lz4c -****************************************************************** */ -#ifndef MEM_H_MODULE -#define MEM_H_MODULE - -#if defined (__cplusplus) -extern "C" { -#endif - - -/*-**************************************** -* Compiler specifics -******************************************/ -#if defined(_MSC_VER) /* Visual Studio */ -# include /* _byteswap_ulong */ -# include /* _byteswap_* */ -#endif - - -/*-************************************************************** -* Basic Types -*****************************************************************/ -#if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) -# if defined(_AIX) -# include -# else -# include /* intptr_t */ -# endif - typedef uint8_t BYTE; - typedef uint16_t U16; - typedef int16_t S16; - typedef uint32_t U32; - typedef int32_t S32; - typedef uint64_t U64; - typedef int64_t S64; -#else - typedef unsigned char BYTE; - typedef unsigned short U16; - typedef signed short S16; - typedef unsigned int U32; - typedef signed int S32; - typedef unsigned long long U64; - typedef signed long long S64; -#endif - - -/*-************************************************************** -* Memory I/O -*****************************************************************/ - -MEM_STATIC unsigned MEM_32bits(void) { return sizeof(size_t)==4; } -MEM_STATIC unsigned MEM_64bits(void) { return sizeof(size_t)==8; } - -MEM_STATIC unsigned MEM_isLittleEndian(void) -{ - const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ - return one.c[0]; -} - -MEM_STATIC U16 MEM_read16(const void* memPtr) -{ - U16 val; memcpy(&val, memPtr, sizeof(val)); return val; -} - -MEM_STATIC U32 MEM_read32(const void* memPtr) -{ - U32 val; memcpy(&val, memPtr, sizeof(val)); return val; -} - -MEM_STATIC U64 MEM_read64(const void* memPtr) -{ - U64 val; memcpy(&val, memPtr, sizeof(val)); return val; -} - -MEM_STATIC void MEM_write16(void* memPtr, U16 value) -{ - memcpy(memPtr, &value, sizeof(value)); -} - -MEM_STATIC U32 MEM_swap32(U32 in) -{ -#if defined(_MSC_VER) /* Visual Studio */ - return _byteswap_ulong(in); -#elif defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403) - return __builtin_bswap32(in); -#else - return ((in << 24) & 0xff000000 ) | - ((in << 8) & 0x00ff0000 ) | - ((in >> 8) & 0x0000ff00 ) | - ((in >> 24) & 0x000000ff ); -#endif -} - -MEM_STATIC U64 MEM_swap64(U64 in) -{ -#if defined(_MSC_VER) /* Visual Studio */ - return _byteswap_uint64(in); -#elif defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403) - return __builtin_bswap64(in); -#else - return ((in << 56) & 0xff00000000000000ULL) | - ((in << 40) & 0x00ff000000000000ULL) | - ((in << 24) & 0x0000ff0000000000ULL) | - ((in << 8) & 0x000000ff00000000ULL) | - ((in >> 8) & 0x00000000ff000000ULL) | - ((in >> 24) & 0x0000000000ff0000ULL) | - ((in >> 40) & 0x000000000000ff00ULL) | - ((in >> 56) & 0x00000000000000ffULL); -#endif -} - - -/*=== Little endian r/w ===*/ - -MEM_STATIC U16 MEM_readLE16(const void* memPtr) -{ - if (MEM_isLittleEndian()) - return MEM_read16(memPtr); - else { - const BYTE* p = (const BYTE*)memPtr; - return (U16)(p[0] + (p[1]<<8)); - } -} - -MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val) -{ - if (MEM_isLittleEndian()) { - MEM_write16(memPtr, val); - } else { - BYTE* p = (BYTE*)memPtr; - p[0] = (BYTE)val; - p[1] = (BYTE)(val>>8); - } -} - -MEM_STATIC U32 MEM_readLE32(const void* memPtr) -{ - if (MEM_isLittleEndian()) - return MEM_read32(memPtr); - else - return MEM_swap32(MEM_read32(memPtr)); -} - - -MEM_STATIC U64 MEM_readLE64(const void* memPtr) -{ - if (MEM_isLittleEndian()) - return MEM_read64(memPtr); - else - return MEM_swap64(MEM_read64(memPtr)); -} - - -MEM_STATIC size_t MEM_readLEST(const void* memPtr) -{ - if (MEM_32bits()) - return (size_t)MEM_readLE32(memPtr); - else - return (size_t)MEM_readLE64(memPtr); -} - - - -#if defined (__cplusplus) -} -#endif - -#endif /* MEM_H_MODULE */ - -/* - zstd - standard compression library - Header File for static linking only - Copyright (C) 2014-2016, Yann Collet. - - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - zstd homepage : https://facebook.github.io/zstd -*/ -#ifndef ZSTDv06_STATIC_H -#define ZSTDv06_STATIC_H - -/* The prototypes defined within this file are considered experimental. - * They should not be used in the context DLL as they may change in the future. - * Prefer static linking if you need them, to control breaking version changes issues. - */ - -#if defined (__cplusplus) -extern "C" { -#endif - - - -/*- Advanced Decompression functions -*/ - -/*! ZSTDv06_decompress_usingPreparedDCtx() : -* Same as ZSTDv06_decompress_usingDict, but using a reference context `preparedDCtx`, where dictionary has been loaded. -* It avoids reloading the dictionary each time. -* `preparedDCtx` must have been properly initialized using ZSTDv06_decompressBegin_usingDict(). -* Requires 2 contexts : 1 for reference (preparedDCtx), which will not be modified, and 1 to run the decompression operation (dctx) */ -ZSTDLIBv06_API size_t ZSTDv06_decompress_usingPreparedDCtx( - ZSTDv06_DCtx* dctx, const ZSTDv06_DCtx* preparedDCtx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize); - - - -#define ZSTDv06_FRAMEHEADERSIZE_MAX 13 /* for static allocation */ -static const size_t ZSTDv06_frameHeaderSize_min = 5; -static const size_t ZSTDv06_frameHeaderSize_max = ZSTDv06_FRAMEHEADERSIZE_MAX; - -ZSTDLIBv06_API size_t ZSTDv06_decompressBegin(ZSTDv06_DCtx* dctx); - -/* - Streaming decompression, direct mode (bufferless) - - A ZSTDv06_DCtx object is required to track streaming operations. - Use ZSTDv06_createDCtx() / ZSTDv06_freeDCtx() to manage it. - A ZSTDv06_DCtx object can be re-used multiple times. - - First optional operation is to retrieve frame parameters, using ZSTDv06_getFrameParams(), which doesn't consume the input. - It can provide the minimum size of rolling buffer required to properly decompress data, - and optionally the final size of uncompressed content. - (Note : content size is an optional info that may not be present. 0 means : content size unknown) - Frame parameters are extracted from the beginning of compressed frame. - The amount of data to read is variable, from ZSTDv06_frameHeaderSize_min to ZSTDv06_frameHeaderSize_max (so if `srcSize` >= ZSTDv06_frameHeaderSize_max, it will always work) - If `srcSize` is too small for operation to succeed, function will return the minimum size it requires to produce a result. - Result : 0 when successful, it means the ZSTDv06_frameParams structure has been filled. - >0 : means there is not enough data into `src`. Provides the expected size to successfully decode header. - errorCode, which can be tested using ZSTDv06_isError() - - Start decompression, with ZSTDv06_decompressBegin() or ZSTDv06_decompressBegin_usingDict(). - Alternatively, you can copy a prepared context, using ZSTDv06_copyDCtx(). - - Then use ZSTDv06_nextSrcSizeToDecompress() and ZSTDv06_decompressContinue() alternatively. - ZSTDv06_nextSrcSizeToDecompress() tells how much bytes to provide as 'srcSize' to ZSTDv06_decompressContinue(). - ZSTDv06_decompressContinue() requires this exact amount of bytes, or it will fail. - ZSTDv06_decompressContinue() needs previous data blocks during decompression, up to (1 << windowlog). - They should preferably be located contiguously, prior to current block. Alternatively, a round buffer is also possible. - - @result of ZSTDv06_decompressContinue() is the number of bytes regenerated within 'dst' (necessarily <= dstCapacity) - It can be zero, which is not an error; it just means ZSTDv06_decompressContinue() has decoded some header. - - A frame is fully decoded when ZSTDv06_nextSrcSizeToDecompress() returns zero. - Context can then be reset to start a new decompression. -*/ - - -/* ************************************** -* Block functions -****************************************/ -/*! Block functions produce and decode raw zstd blocks, without frame metadata. - User will have to take in charge required information to regenerate data, such as compressed and content sizes. - - A few rules to respect : - - Uncompressed block size must be <= ZSTDv06_BLOCKSIZE_MAX (128 KB) - - Compressing or decompressing requires a context structure - + Use ZSTDv06_createCCtx() and ZSTDv06_createDCtx() - - It is necessary to init context before starting - + compression : ZSTDv06_compressBegin() - + decompression : ZSTDv06_decompressBegin() - + variants _usingDict() are also allowed - + copyCCtx() and copyDCtx() work too - - When a block is considered not compressible enough, ZSTDv06_compressBlock() result will be zero. - In which case, nothing is produced into `dst`. - + User must test for such outcome and deal directly with uncompressed data - + ZSTDv06_decompressBlock() doesn't accept uncompressed data as input !! -*/ - -#define ZSTDv06_BLOCKSIZE_MAX (128 * 1024) /* define, for static allocation */ -ZSTDLIBv06_API size_t ZSTDv06_decompressBlock(ZSTDv06_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); - - - -#if defined (__cplusplus) -} -#endif - -#endif /* ZSTDv06_STATIC_H */ -/* - zstd_internal - common functions to include - Header File for include - Copyright (C) 2014-2016, Yann Collet. - - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - zstd homepage : https://www.zstd.net -*/ -#ifndef ZSTDv06_CCOMMON_H_MODULE -#define ZSTDv06_CCOMMON_H_MODULE - - -/*-************************************* -* Common macros -***************************************/ -#define MIN(a,b) ((a)<(b) ? (a) : (b)) -#define MAX(a,b) ((a)>(b) ? (a) : (b)) - - -/*-************************************* -* Common constants -***************************************/ -#define ZSTDv06_DICT_MAGIC 0xEC30A436 - -#define ZSTDv06_REP_NUM 3 -#define ZSTDv06_REP_INIT ZSTDv06_REP_NUM -#define ZSTDv06_REP_MOVE (ZSTDv06_REP_NUM-1) - -#define KB *(1 <<10) -#define MB *(1 <<20) -#define GB *(1U<<30) - -#define BIT7 128 -#define BIT6 64 -#define BIT5 32 -#define BIT4 16 -#define BIT1 2 -#define BIT0 1 - -#define ZSTDv06_WINDOWLOG_ABSOLUTEMIN 12 -static const size_t ZSTDv06_fcs_fieldSize[4] = { 0, 1, 2, 8 }; - -#define ZSTDv06_BLOCKHEADERSIZE 3 /* because C standard does not allow a static const value to be defined using another static const value .... :( */ -static const size_t ZSTDv06_blockHeaderSize = ZSTDv06_BLOCKHEADERSIZE; -typedef enum { bt_compressed, bt_raw, bt_rle, bt_end } blockType_t; - -#define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */ -#define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */ - -#define ZSTD_HUFFDTABLE_CAPACITY_LOG 12 - -#define IS_HUF 0 -#define IS_PCH 1 -#define IS_RAW 2 -#define IS_RLE 3 - -#define LONGNBSEQ 0x7F00 - -#define MINMATCH 3 -#define EQUAL_READ32 4 -#define REPCODE_STARTVALUE 1 - -#define Litbits 8 -#define MaxLit ((1< /* support for bextr (experimental) */ -#endif - - - -/*-******************************************** -* bitStream decoding API (read backward) -**********************************************/ -typedef struct -{ - size_t bitContainer; - unsigned bitsConsumed; - const char* ptr; - const char* start; -} BITv06_DStream_t; - -typedef enum { BITv06_DStream_unfinished = 0, - BITv06_DStream_endOfBuffer = 1, - BITv06_DStream_completed = 2, - BITv06_DStream_overflow = 3 } BITv06_DStream_status; /* result of BITv06_reloadDStream() */ - /* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */ - -MEM_STATIC size_t BITv06_initDStream(BITv06_DStream_t* bitD, const void* srcBuffer, size_t srcSize); -MEM_STATIC size_t BITv06_readBits(BITv06_DStream_t* bitD, unsigned nbBits); -MEM_STATIC BITv06_DStream_status BITv06_reloadDStream(BITv06_DStream_t* bitD); -MEM_STATIC unsigned BITv06_endOfDStream(const BITv06_DStream_t* bitD); - - - -/*-**************************************** -* unsafe API -******************************************/ -MEM_STATIC size_t BITv06_readBitsFast(BITv06_DStream_t* bitD, unsigned nbBits); -/* faster, but works only if nbBits >= 1 */ - - - -/*-************************************************************** -* Internal functions -****************************************************************/ -MEM_STATIC unsigned BITv06_highbit32 ( U32 val) -{ -# if defined(_MSC_VER) /* Visual */ - unsigned long r; - return _BitScanReverse(&r, val) ? (unsigned)r : 0; -# elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */ - return __builtin_clz (val) ^ 31; -# else /* Software version */ - 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 }; - U32 v = val; - unsigned r; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - r = DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27]; - return r; -# endif -} - - - -/*-******************************************************** -* bitStream decoding -**********************************************************/ -/*! BITv06_initDStream() : -* Initialize a BITv06_DStream_t. -* `bitD` : a pointer to an already allocated BITv06_DStream_t structure. -* `srcSize` must be the *exact* size of the bitStream, in bytes. -* @return : size of stream (== srcSize) or an errorCode if a problem is detected -*/ -MEM_STATIC size_t BITv06_initDStream(BITv06_DStream_t* bitD, const void* srcBuffer, size_t srcSize) -{ - if (srcSize < 1) { memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); } - - if (srcSize >= sizeof(bitD->bitContainer)) { /* normal case */ - bitD->start = (const char*)srcBuffer; - bitD->ptr = (const char*)srcBuffer + srcSize - sizeof(bitD->bitContainer); - bitD->bitContainer = MEM_readLEST(bitD->ptr); - { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1]; - if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ - bitD->bitsConsumed = 8 - BITv06_highbit32(lastByte); } - } else { - bitD->start = (const char*)srcBuffer; - bitD->ptr = bitD->start; - bitD->bitContainer = *(const BYTE*)(bitD->start); - switch(srcSize) - { - case 7: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16);/* fall-through */ - case 6: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24);/* fall-through */ - case 5: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32);/* fall-through */ - case 4: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[3]) << 24; /* fall-through */ - case 3: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[2]) << 16; /* fall-through */ - case 2: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[1]) << 8; /* fall-through */ - default: break; - } - { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1]; - if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ - bitD->bitsConsumed = 8 - BITv06_highbit32(lastByte); } - bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize)*8; - } - - return srcSize; -} - - - MEM_STATIC size_t BITv06_lookBits(const BITv06_DStream_t* bitD, U32 nbBits) -{ - U32 const bitMask = sizeof(bitD->bitContainer)*8 - 1; - return ((bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> 1) >> ((bitMask-nbBits) & bitMask); -} - -/*! BITv06_lookBitsFast() : -* unsafe version; only works if nbBits >= 1 */ -MEM_STATIC size_t BITv06_lookBitsFast(const BITv06_DStream_t* bitD, U32 nbBits) -{ - U32 const bitMask = sizeof(bitD->bitContainer)*8 - 1; - return (bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> (((bitMask+1)-nbBits) & bitMask); -} - -MEM_STATIC void BITv06_skipBits(BITv06_DStream_t* bitD, U32 nbBits) -{ - bitD->bitsConsumed += nbBits; -} - -MEM_STATIC size_t BITv06_readBits(BITv06_DStream_t* bitD, U32 nbBits) -{ - size_t const value = BITv06_lookBits(bitD, nbBits); - BITv06_skipBits(bitD, nbBits); - return value; -} - -/*! BITv06_readBitsFast() : -* unsafe version; only works if nbBits >= 1 */ -MEM_STATIC size_t BITv06_readBitsFast(BITv06_DStream_t* bitD, U32 nbBits) -{ - size_t const value = BITv06_lookBitsFast(bitD, nbBits); - BITv06_skipBits(bitD, nbBits); - return value; -} - -MEM_STATIC BITv06_DStream_status BITv06_reloadDStream(BITv06_DStream_t* bitD) -{ - if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* should never happen */ - return BITv06_DStream_overflow; - - if (bitD->ptr >= bitD->start + sizeof(bitD->bitContainer)) { - bitD->ptr -= bitD->bitsConsumed >> 3; - bitD->bitsConsumed &= 7; - bitD->bitContainer = MEM_readLEST(bitD->ptr); - return BITv06_DStream_unfinished; - } - if (bitD->ptr == bitD->start) { - if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BITv06_DStream_endOfBuffer; - return BITv06_DStream_completed; - } - { U32 nbBytes = bitD->bitsConsumed >> 3; - BITv06_DStream_status result = BITv06_DStream_unfinished; - if (bitD->ptr - nbBytes < bitD->start) { - nbBytes = (U32)(bitD->ptr - bitD->start); /* ptr > start */ - result = BITv06_DStream_endOfBuffer; - } - bitD->ptr -= nbBytes; - bitD->bitsConsumed -= nbBytes*8; - bitD->bitContainer = MEM_readLEST(bitD->ptr); /* reminder : srcSize > sizeof(bitD) */ - return result; - } -} - -/*! BITv06_endOfDStream() : -* @return Tells if DStream has exactly reached its end (all bits consumed). -*/ -MEM_STATIC unsigned BITv06_endOfDStream(const BITv06_DStream_t* DStream) -{ - return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer)*8)); -} - -#if defined (__cplusplus) -} -#endif - -#endif /* BITSTREAM_H_MODULE */ -/* ****************************************************************** - FSE : Finite State Entropy coder - header file for static linking (only) - Copyright (C) 2013-2015, Yann Collet - - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - Source repository : https://github.com/Cyan4973/FiniteStateEntropy - - Public forum : https://groups.google.com/forum/#!forum/lz4c -****************************************************************** */ -#ifndef FSEv06_STATIC_H -#define FSEv06_STATIC_H - -#if defined (__cplusplus) -extern "C" { -#endif - - -/* ***************************************** -* Static allocation -*******************************************/ -/* FSE buffer bounds */ -#define FSEv06_NCOUNTBOUND 512 -#define FSEv06_BLOCKBOUND(size) (size + (size>>7)) -#define FSEv06_COMPRESSBOUND(size) (FSEv06_NCOUNTBOUND + FSEv06_BLOCKBOUND(size)) /* Macro version, useful for static allocation */ - -/* It is possible to statically allocate FSE CTable/DTable as a table of unsigned using below macros */ -#define FSEv06_DTABLE_SIZE_U32(maxTableLog) (1 + (1<= 1 (otherwise, result will be corrupted) */ - - -/* ***************************************** -* Implementation of inlined functions -*******************************************/ - - -/* ====== Decompression ====== */ - -typedef struct { - U16 tableLog; - U16 fastMode; -} FSEv06_DTableHeader; /* sizeof U32 */ - -typedef struct -{ - unsigned short newState; - unsigned char symbol; - unsigned char nbBits; -} FSEv06_decode_t; /* size == U32 */ - -MEM_STATIC void FSEv06_initDState(FSEv06_DState_t* DStatePtr, BITv06_DStream_t* bitD, const FSEv06_DTable* dt) -{ - const void* ptr = dt; - const FSEv06_DTableHeader* const DTableH = (const FSEv06_DTableHeader*)ptr; - DStatePtr->state = BITv06_readBits(bitD, DTableH->tableLog); - BITv06_reloadDStream(bitD); - DStatePtr->table = dt + 1; -} - -MEM_STATIC BYTE FSEv06_peekSymbol(const FSEv06_DState_t* DStatePtr) -{ - FSEv06_decode_t const DInfo = ((const FSEv06_decode_t*)(DStatePtr->table))[DStatePtr->state]; - return DInfo.symbol; -} - -MEM_STATIC void FSEv06_updateState(FSEv06_DState_t* DStatePtr, BITv06_DStream_t* bitD) -{ - FSEv06_decode_t const DInfo = ((const FSEv06_decode_t*)(DStatePtr->table))[DStatePtr->state]; - U32 const nbBits = DInfo.nbBits; - size_t const lowBits = BITv06_readBits(bitD, nbBits); - DStatePtr->state = DInfo.newState + lowBits; -} - -MEM_STATIC BYTE FSEv06_decodeSymbol(FSEv06_DState_t* DStatePtr, BITv06_DStream_t* bitD) -{ - FSEv06_decode_t const DInfo = ((const FSEv06_decode_t*)(DStatePtr->table))[DStatePtr->state]; - U32 const nbBits = DInfo.nbBits; - BYTE const symbol = DInfo.symbol; - size_t const lowBits = BITv06_readBits(bitD, nbBits); - - DStatePtr->state = DInfo.newState + lowBits; - return symbol; -} - -/*! FSEv06_decodeSymbolFast() : - unsafe, only works if no symbol has a probability > 50% */ -MEM_STATIC BYTE FSEv06_decodeSymbolFast(FSEv06_DState_t* DStatePtr, BITv06_DStream_t* bitD) -{ - FSEv06_decode_t const DInfo = ((const FSEv06_decode_t*)(DStatePtr->table))[DStatePtr->state]; - U32 const nbBits = DInfo.nbBits; - BYTE const symbol = DInfo.symbol; - size_t const lowBits = BITv06_readBitsFast(bitD, nbBits); - - DStatePtr->state = DInfo.newState + lowBits; - return symbol; -} - - - -#ifndef FSEv06_COMMONDEFS_ONLY - -/* ************************************************************** -* Tuning parameters -****************************************************************/ -/*!MEMORY_USAGE : -* Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) -* Increasing memory usage improves compression ratio -* Reduced memory usage can improve speed, due to cache effect -* Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */ -#define FSEv06_MAX_MEMORY_USAGE 14 -#define FSEv06_DEFAULT_MEMORY_USAGE 13 - -/*!FSEv06_MAX_SYMBOL_VALUE : -* Maximum symbol value authorized. -* Required for proper stack allocation */ -#define FSEv06_MAX_SYMBOL_VALUE 255 - - -/* ************************************************************** -* template functions type & suffix -****************************************************************/ -#define FSEv06_FUNCTION_TYPE BYTE -#define FSEv06_FUNCTION_EXTENSION -#define FSEv06_DECODE_TYPE FSEv06_decode_t - - -#endif /* !FSEv06_COMMONDEFS_ONLY */ - - -/* *************************************************************** -* Constants -*****************************************************************/ -#define FSEv06_MAX_TABLELOG (FSEv06_MAX_MEMORY_USAGE-2) -#define FSEv06_MAX_TABLESIZE (1U< FSEv06_TABLELOG_ABSOLUTE_MAX -#error "FSEv06_MAX_TABLELOG > FSEv06_TABLELOG_ABSOLUTE_MAX is not supported" -#endif - -#define FSEv06_TABLESTEP(tableSize) ((tableSize>>1) + (tableSize>>3) + 3) - - -#if defined (__cplusplus) -} -#endif - -#endif /* FSEv06_STATIC_H */ -/* - Common functions of New Generation Entropy library - Copyright (C) 2016, Yann Collet. - - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy - - Public forum : https://groups.google.com/forum/#!forum/lz4c -*************************************************************************** */ - - -/*-**************************************** -* FSE Error Management -******************************************/ -unsigned FSEv06_isError(size_t code) { return ERR_isError(code); } - -const char* FSEv06_getErrorName(size_t code) { return ERR_getErrorName(code); } - - -/* ************************************************************** -* HUF Error Management -****************************************************************/ -static unsigned HUFv06_isError(size_t code) { return ERR_isError(code); } - - -/*-************************************************************** -* FSE NCount encoding-decoding -****************************************************************/ -static short FSEv06_abs(short a) { return a<0 ? -a : a; } - -size_t FSEv06_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, - const void* headerBuffer, size_t hbSize) -{ - const BYTE* const istart = (const BYTE*) headerBuffer; - const BYTE* const iend = istart + hbSize; - const BYTE* ip = istart; - int nbBits; - int remaining; - int threshold; - U32 bitStream; - int bitCount; - unsigned charnum = 0; - int previous0 = 0; - - if (hbSize < 4) return ERROR(srcSize_wrong); - bitStream = MEM_readLE32(ip); - nbBits = (bitStream & 0xF) + FSEv06_MIN_TABLELOG; /* extract tableLog */ - if (nbBits > FSEv06_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge); - bitStream >>= 4; - bitCount = 4; - *tableLogPtr = nbBits; - remaining = (1<1) && (charnum<=*maxSVPtr)) { - if (previous0) { - unsigned n0 = charnum; - while ((bitStream & 0xFFFF) == 0xFFFF) { - n0+=24; - if (ip < iend-5) { - ip+=2; - bitStream = MEM_readLE32(ip) >> bitCount; - } else { - bitStream >>= 16; - bitCount+=16; - } } - while ((bitStream & 3) == 3) { - n0+=3; - bitStream>>=2; - bitCount+=2; - } - n0 += bitStream & 3; - bitCount += 2; - if (n0 > *maxSVPtr) return ERROR(maxSymbolValue_tooSmall); - while (charnum < n0) normalizedCounter[charnum++] = 0; - if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { - ip += bitCount>>3; - bitCount &= 7; - bitStream = MEM_readLE32(ip) >> bitCount; - } - else - bitStream >>= 2; - } - { short const max = (short)((2*threshold-1)-remaining); - short count; - - if ((bitStream & (threshold-1)) < (U32)max) { - count = (short)(bitStream & (threshold-1)); - bitCount += nbBits-1; - } else { - count = (short)(bitStream & (2*threshold-1)); - if (count >= threshold) count -= max; - bitCount += nbBits; - } - - count--; /* extra accuracy */ - remaining -= FSEv06_abs(count); - normalizedCounter[charnum++] = count; - previous0 = !count; - while (remaining < threshold) { - nbBits--; - threshold >>= 1; - } - - if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { - ip += bitCount>>3; - bitCount &= 7; - } else { - bitCount -= (int)(8 * (iend - 4 - ip)); - ip = iend - 4; - } - bitStream = MEM_readLE32(ip) >> (bitCount & 31); - } } /* while ((remaining>1) && (charnum<=*maxSVPtr)) */ - if (remaining != 1) return ERROR(GENERIC); - *maxSVPtr = charnum-1; - - ip += (bitCount+7)>>3; - if ((size_t)(ip-istart) > hbSize) return ERROR(srcSize_wrong); - return ip-istart; -} -/* ****************************************************************** - FSE : Finite State Entropy decoder - Copyright (C) 2013-2015, Yann Collet. - - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy - - Public forum : https://groups.google.com/forum/#!forum/lz4c -****************************************************************** */ - - -/* ************************************************************** -* Compiler specifics -****************************************************************/ -#ifdef _MSC_VER /* Visual Studio */ -# define FORCE_INLINE static __forceinline -# include /* For Visual 2005 */ -# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -# pragma warning(disable : 4214) /* disable: C4214: non-int bitfields */ -#else -# if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ -# ifdef __GNUC__ -# define FORCE_INLINE static inline __attribute__((always_inline)) -# else -# define FORCE_INLINE static inline -# endif -# else -# define FORCE_INLINE static -# endif /* __STDC_VERSION__ */ -#endif - - -/* ************************************************************** -* Error Management -****************************************************************/ -#define FSEv06_isError ERR_isError -#define FSEv06_STATIC_ASSERT(c) { enum { FSEv06_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */ - - -/* ************************************************************** -* Complex types -****************************************************************/ -typedef U32 DTable_max_t[FSEv06_DTABLE_SIZE_U32(FSEv06_MAX_TABLELOG)]; - - -/* ************************************************************** -* Templates -****************************************************************/ -/* - designed to be included - for type-specific functions (template emulation in C) - Objective is to write these functions only once, for improved maintenance -*/ - -/* safety checks */ -#ifndef FSEv06_FUNCTION_EXTENSION -# error "FSEv06_FUNCTION_EXTENSION must be defined" -#endif -#ifndef FSEv06_FUNCTION_TYPE -# error "FSEv06_FUNCTION_TYPE must be defined" -#endif - -/* Function names */ -#define FSEv06_CAT(X,Y) X##Y -#define FSEv06_FUNCTION_NAME(X,Y) FSEv06_CAT(X,Y) -#define FSEv06_TYPE_NAME(X,Y) FSEv06_CAT(X,Y) - - -/* Function templates */ -FSEv06_DTable* FSEv06_createDTable (unsigned tableLog) -{ - if (tableLog > FSEv06_TABLELOG_ABSOLUTE_MAX) tableLog = FSEv06_TABLELOG_ABSOLUTE_MAX; - return (FSEv06_DTable*)malloc( FSEv06_DTABLE_SIZE_U32(tableLog) * sizeof (U32) ); -} - -void FSEv06_freeDTable (FSEv06_DTable* dt) -{ - free(dt); -} - -size_t FSEv06_buildDTable(FSEv06_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog) -{ - void* const tdPtr = dt+1; /* because *dt is unsigned, 32-bits aligned on 32-bits */ - FSEv06_DECODE_TYPE* const tableDecode = (FSEv06_DECODE_TYPE*) (tdPtr); - U16 symbolNext[FSEv06_MAX_SYMBOL_VALUE+1]; - - U32 const maxSV1 = maxSymbolValue + 1; - U32 const tableSize = 1 << tableLog; - U32 highThreshold = tableSize-1; - - /* Sanity Checks */ - if (maxSymbolValue > FSEv06_MAX_SYMBOL_VALUE) return ERROR(maxSymbolValue_tooLarge); - if (tableLog > FSEv06_MAX_TABLELOG) return ERROR(tableLog_tooLarge); - - /* Init, lay down lowprob symbols */ - { FSEv06_DTableHeader DTableH; - DTableH.tableLog = (U16)tableLog; - DTableH.fastMode = 1; - { S16 const largeLimit= (S16)(1 << (tableLog-1)); - U32 s; - for (s=0; s= largeLimit) DTableH.fastMode=0; - symbolNext[s] = normalizedCounter[s]; - } } } - memcpy(dt, &DTableH, sizeof(DTableH)); - } - - /* Spread symbols */ - { U32 const tableMask = tableSize-1; - U32 const step = FSEv06_TABLESTEP(tableSize); - U32 s, position = 0; - for (s=0; s highThreshold) position = (position + step) & tableMask; /* lowprob area */ - } } - - if (position!=0) return ERROR(GENERIC); /* position must reach all cells once, otherwise normalizedCounter is incorrect */ - } - - /* Build Decoding table */ - { U32 u; - for (u=0; utableLog = 0; - DTableH->fastMode = 0; - - cell->newState = 0; - cell->symbol = symbolValue; - cell->nbBits = 0; - - return 0; -} - - -size_t FSEv06_buildDTable_raw (FSEv06_DTable* dt, unsigned nbBits) -{ - void* ptr = dt; - FSEv06_DTableHeader* const DTableH = (FSEv06_DTableHeader*)ptr; - void* dPtr = dt + 1; - FSEv06_decode_t* const dinfo = (FSEv06_decode_t*)dPtr; - const unsigned tableSize = 1 << nbBits; - const unsigned tableMask = tableSize - 1; - const unsigned maxSV1 = tableMask+1; - unsigned s; - - /* Sanity checks */ - if (nbBits < 1) return ERROR(GENERIC); /* min size */ - - /* Build Decoding Table */ - DTableH->tableLog = (U16)nbBits; - DTableH->fastMode = 1; - for (s=0; s sizeof(bitD.bitContainer)*8) /* This test must be static */ - BITv06_reloadDStream(&bitD); - - op[1] = FSEv06_GETSYMBOL(&state2); - - if (FSEv06_MAX_TABLELOG*4+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */ - { if (BITv06_reloadDStream(&bitD) > BITv06_DStream_unfinished) { op+=2; break; } } - - op[2] = FSEv06_GETSYMBOL(&state1); - - if (FSEv06_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */ - BITv06_reloadDStream(&bitD); - - op[3] = FSEv06_GETSYMBOL(&state2); - } - - /* tail */ - /* note : BITv06_reloadDStream(&bitD) >= FSEv06_DStream_partiallyFilled; Ends at exactly BITv06_DStream_completed */ - while (1) { - if (op>(omax-2)) return ERROR(dstSize_tooSmall); - - *op++ = FSEv06_GETSYMBOL(&state1); - - if (BITv06_reloadDStream(&bitD)==BITv06_DStream_overflow) { - *op++ = FSEv06_GETSYMBOL(&state2); - break; - } - - if (op>(omax-2)) return ERROR(dstSize_tooSmall); - - *op++ = FSEv06_GETSYMBOL(&state2); - - if (BITv06_reloadDStream(&bitD)==BITv06_DStream_overflow) { - *op++ = FSEv06_GETSYMBOL(&state1); - break; - } } - - return op-ostart; -} - - -size_t FSEv06_decompress_usingDTable(void* dst, size_t originalSize, - const void* cSrc, size_t cSrcSize, - const FSEv06_DTable* dt) -{ - const void* ptr = dt; - const FSEv06_DTableHeader* DTableH = (const FSEv06_DTableHeader*)ptr; - const U32 fastMode = DTableH->fastMode; - - /* select fast mode (static) */ - if (fastMode) return FSEv06_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 1); - return FSEv06_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 0); -} - - -size_t FSEv06_decompress(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize) -{ - const BYTE* const istart = (const BYTE*)cSrc; - const BYTE* ip = istart; - short counting[FSEv06_MAX_SYMBOL_VALUE+1]; - DTable_max_t dt; /* Static analyzer seems unable to understand this table will be properly initialized later */ - unsigned tableLog; - unsigned maxSymbolValue = FSEv06_MAX_SYMBOL_VALUE; - - if (cSrcSize<2) return ERROR(srcSize_wrong); /* too small input size */ - - /* normal FSE decoding mode */ - { size_t const NCountLength = FSEv06_readNCount (counting, &maxSymbolValue, &tableLog, istart, cSrcSize); - if (FSEv06_isError(NCountLength)) return NCountLength; - if (NCountLength >= cSrcSize) return ERROR(srcSize_wrong); /* too small input size */ - ip += NCountLength; - cSrcSize -= NCountLength; - } - - { size_t const errorCode = FSEv06_buildDTable (dt, counting, maxSymbolValue, tableLog); - if (FSEv06_isError(errorCode)) return errorCode; } - - return FSEv06_decompress_usingDTable (dst, maxDstSize, ip, cSrcSize, dt); /* always return, even if it is an error code */ -} - - - -#endif /* FSEv06_COMMONDEFS_ONLY */ -/* ****************************************************************** - Huffman coder, part of New Generation Entropy library - header file - Copyright (C) 2013-2016, Yann Collet. - - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - Source repository : https://github.com/Cyan4973/FiniteStateEntropy -****************************************************************** */ -#ifndef HUFv06_H -#define HUFv06_H - -#if defined (__cplusplus) -extern "C" { -#endif - - -/* **************************************** -* HUF simple functions -******************************************/ -size_t HUFv06_decompress(void* dst, size_t dstSize, - const void* cSrc, size_t cSrcSize); -/* -HUFv06_decompress() : - Decompress HUF data from buffer 'cSrc', of size 'cSrcSize', - into already allocated destination buffer 'dst', of size 'dstSize'. - `dstSize` : must be the **exact** size of original (uncompressed) data. - Note : in contrast with FSE, HUFv06_decompress can regenerate - RLE (cSrcSize==1) and uncompressed (cSrcSize==dstSize) data, - because it knows size to regenerate. - @return : size of regenerated data (== dstSize) - or an error code, which can be tested using HUFv06_isError() -*/ - - -/* **************************************** -* Tool functions -******************************************/ -size_t HUFv06_compressBound(size_t size); /**< maximum compressed size */ - - -#if defined (__cplusplus) -} -#endif - -#endif /* HUFv06_H */ -/* ****************************************************************** - Huffman codec, part of New Generation Entropy library - header file, for static linking only - Copyright (C) 2013-2016, Yann Collet - - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - Source repository : https://github.com/Cyan4973/FiniteStateEntropy -****************************************************************** */ -#ifndef HUFv06_STATIC_H -#define HUFv06_STATIC_H - -#if defined (__cplusplus) -extern "C" { -#endif - - -/* **************************************** -* Static allocation -******************************************/ -/* HUF buffer bounds */ -#define HUFv06_CTABLEBOUND 129 -#define HUFv06_BLOCKBOUND(size) (size + (size>>8) + 8) /* only true if incompressible pre-filtered with fast heuristic */ -#define HUFv06_COMPRESSBOUND(size) (HUFv06_CTABLEBOUND + HUFv06_BLOCKBOUND(size)) /* Macro version, useful for static allocation */ - -/* static allocation of HUF's DTable */ -#define HUFv06_DTABLE_SIZE(maxTableLog) (1 + (1< HUFv06_ABSOLUTEMAX_TABLELOG) -# error "HUFv06_MAX_TABLELOG is too large !" -#endif - - - -/*! HUFv06_readStats() : - Read compact Huffman tree, saved by HUFv06_writeCTable(). - `huffWeight` is destination buffer. - @return : size read from `src` -*/ -MEM_STATIC size_t HUFv06_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, - U32* nbSymbolsPtr, U32* tableLogPtr, - const void* src, size_t srcSize) -{ - U32 weightTotal; - const BYTE* ip = (const BYTE*) src; - size_t iSize; - size_t oSize; - - if (!srcSize) return ERROR(srcSize_wrong); - iSize = ip[0]; - /* memset(huffWeight, 0, hwSize); */ /* is not necessary, even though some analyzer complain ... */ - - if (iSize >= 128) { /* special header */ - if (iSize >= (242)) { /* RLE */ - static U32 l[14] = { 1, 2, 3, 4, 7, 8, 15, 16, 31, 32, 63, 64, 127, 128 }; - oSize = l[iSize-242]; - memset(huffWeight, 1, hwSize); - iSize = 0; - } - else { /* Incompressible */ - oSize = iSize - 127; - iSize = ((oSize+1)/2); - if (iSize+1 > srcSize) return ERROR(srcSize_wrong); - if (oSize >= hwSize) return ERROR(corruption_detected); - ip += 1; - { U32 n; - for (n=0; n> 4; - huffWeight[n+1] = ip[n/2] & 15; - } } } } - else { /* header compressed with FSE (normal case) */ - if (iSize+1 > srcSize) return ERROR(srcSize_wrong); - oSize = FSEv06_decompress(huffWeight, hwSize-1, ip+1, iSize); /* max (hwSize-1) values decoded, as last one is implied */ - if (FSEv06_isError(oSize)) return oSize; - } - - /* collect weight stats */ - memset(rankStats, 0, (HUFv06_ABSOLUTEMAX_TABLELOG + 1) * sizeof(U32)); - weightTotal = 0; - { U32 n; for (n=0; n= HUFv06_ABSOLUTEMAX_TABLELOG) return ERROR(corruption_detected); - rankStats[huffWeight[n]]++; - weightTotal += (1 << huffWeight[n]) >> 1; - } } - if (weightTotal == 0) return ERROR(corruption_detected); - - /* get last non-null symbol weight (implied, total must be 2^n) */ - { U32 const tableLog = BITv06_highbit32(weightTotal) + 1; - if (tableLog > HUFv06_ABSOLUTEMAX_TABLELOG) return ERROR(corruption_detected); - *tableLogPtr = tableLog; - /* determine last weight */ - { U32 const total = 1 << tableLog; - U32 const rest = total - weightTotal; - U32 const verif = 1 << BITv06_highbit32(rest); - U32 const lastWeight = BITv06_highbit32(rest) + 1; - if (verif != rest) return ERROR(corruption_detected); /* last value must be a clean power of 2 */ - huffWeight[oSize] = (BYTE)lastWeight; - rankStats[lastWeight]++; - } } - - /* check tree construction validity */ - if ((rankStats[1] < 2) || (rankStats[1] & 1)) return ERROR(corruption_detected); /* by construction : at least 2 elts of rank 1, must be even */ - - /* results */ - *nbSymbolsPtr = (U32)(oSize+1); - return iSize+1; -} - - - -#if defined (__cplusplus) -} -#endif - -#endif /* HUFv06_STATIC_H */ -/* ****************************************************************** - Huffman decoder, part of New Generation Entropy library - Copyright (C) 2013-2016, Yann Collet. - - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy - - Public forum : https://groups.google.com/forum/#!forum/lz4c -****************************************************************** */ - -/* ************************************************************** -* Compiler specifics -****************************************************************/ -#if defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) -/* inline is defined */ -#elif defined(_MSC_VER) -# define inline __inline -#else -# define inline /* disable inline */ -#endif - - -#ifdef _MSC_VER /* Visual Studio */ -# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -#endif - - - -/* ************************************************************** -* Error Management -****************************************************************/ -#define HUFv06_STATIC_ASSERT(c) { enum { HUFv06_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */ - - - -/* ******************************************************* -* HUF : Huffman block decompression -*********************************************************/ -typedef struct { BYTE byte; BYTE nbBits; } HUFv06_DEltX2; /* single-symbol decoding */ - -typedef struct { U16 sequence; BYTE nbBits; BYTE length; } HUFv06_DEltX4; /* double-symbols decoding */ - -typedef struct { BYTE symbol; BYTE weight; } sortedSymbol_t; - - - -/*-***************************/ -/* single-symbol decoding */ -/*-***************************/ - -size_t HUFv06_readDTableX2 (U16* DTable, const void* src, size_t srcSize) -{ - BYTE huffWeight[HUFv06_MAX_SYMBOL_VALUE + 1]; - U32 rankVal[HUFv06_ABSOLUTEMAX_TABLELOG + 1]; /* large enough for values from 0 to 16 */ - U32 tableLog = 0; - size_t iSize; - U32 nbSymbols = 0; - U32 n; - U32 nextRankStart; - void* const dtPtr = DTable + 1; - HUFv06_DEltX2* const dt = (HUFv06_DEltX2*)dtPtr; - - HUFv06_STATIC_ASSERT(sizeof(HUFv06_DEltX2) == sizeof(U16)); /* if compilation fails here, assertion is false */ - /* memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */ - - iSize = HUFv06_readStats(huffWeight, HUFv06_MAX_SYMBOL_VALUE + 1, rankVal, &nbSymbols, &tableLog, src, srcSize); - if (HUFv06_isError(iSize)) return iSize; - - /* check result */ - if (tableLog > DTable[0]) return ERROR(tableLog_tooLarge); /* DTable is too small */ - DTable[0] = (U16)tableLog; /* maybe should separate sizeof allocated DTable, from used size of DTable, in case of re-use */ - - /* Prepare ranks */ - nextRankStart = 0; - for (n=1; n> 1; - U32 i; - HUFv06_DEltX2 D; - D.byte = (BYTE)n; D.nbBits = (BYTE)(tableLog + 1 - w); - for (i = rankVal[w]; i < rankVal[w] + length; i++) - dt[i] = D; - rankVal[w] += length; - } - - return iSize; -} - - -static BYTE HUFv06_decodeSymbolX2(BITv06_DStream_t* Dstream, const HUFv06_DEltX2* dt, const U32 dtLog) -{ - const size_t val = BITv06_lookBitsFast(Dstream, dtLog); /* note : dtLog >= 1 */ - const BYTE c = dt[val].byte; - BITv06_skipBits(Dstream, dt[val].nbBits); - return c; -} - -#define HUFv06_DECODE_SYMBOLX2_0(ptr, DStreamPtr) \ - *ptr++ = HUFv06_decodeSymbolX2(DStreamPtr, dt, dtLog) - -#define HUFv06_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \ - if (MEM_64bits() || (HUFv06_MAX_TABLELOG<=12)) \ - HUFv06_DECODE_SYMBOLX2_0(ptr, DStreamPtr) - -#define HUFv06_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \ - if (MEM_64bits()) \ - HUFv06_DECODE_SYMBOLX2_0(ptr, DStreamPtr) - -static inline size_t HUFv06_decodeStreamX2(BYTE* p, BITv06_DStream_t* const bitDPtr, BYTE* const pEnd, const HUFv06_DEltX2* const dt, const U32 dtLog) -{ - BYTE* const pStart = p; - - /* up to 4 symbols at a time */ - while ((BITv06_reloadDStream(bitDPtr) == BITv06_DStream_unfinished) && (p <= pEnd-4)) { - HUFv06_DECODE_SYMBOLX2_2(p, bitDPtr); - HUFv06_DECODE_SYMBOLX2_1(p, bitDPtr); - HUFv06_DECODE_SYMBOLX2_2(p, bitDPtr); - HUFv06_DECODE_SYMBOLX2_0(p, bitDPtr); - } - - /* closer to the end */ - while ((BITv06_reloadDStream(bitDPtr) == BITv06_DStream_unfinished) && (p < pEnd)) - HUFv06_DECODE_SYMBOLX2_0(p, bitDPtr); - - /* no more data to retrieve from bitstream, hence no need to reload */ - while (p < pEnd) - HUFv06_DECODE_SYMBOLX2_0(p, bitDPtr); - - return pEnd-pStart; -} - -size_t HUFv06_decompress1X2_usingDTable( - void* dst, size_t dstSize, - const void* cSrc, size_t cSrcSize, - const U16* DTable) -{ - BYTE* op = (BYTE*)dst; - BYTE* const oend = op + dstSize; - const U32 dtLog = DTable[0]; - const void* dtPtr = DTable; - const HUFv06_DEltX2* const dt = ((const HUFv06_DEltX2*)dtPtr)+1; - BITv06_DStream_t bitD; - - { size_t const errorCode = BITv06_initDStream(&bitD, cSrc, cSrcSize); - if (HUFv06_isError(errorCode)) return errorCode; } - - HUFv06_decodeStreamX2(op, &bitD, oend, dt, dtLog); - - /* check */ - if (!BITv06_endOfDStream(&bitD)) return ERROR(corruption_detected); - - return dstSize; -} - -size_t HUFv06_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) -{ - HUFv06_CREATE_STATIC_DTABLEX2(DTable, HUFv06_MAX_TABLELOG); - const BYTE* ip = (const BYTE*) cSrc; - - size_t const errorCode = HUFv06_readDTableX2 (DTable, cSrc, cSrcSize); - if (HUFv06_isError(errorCode)) return errorCode; - if (errorCode >= cSrcSize) return ERROR(srcSize_wrong); - ip += errorCode; - cSrcSize -= errorCode; - - return HUFv06_decompress1X2_usingDTable (dst, dstSize, ip, cSrcSize, DTable); -} - - -size_t HUFv06_decompress4X2_usingDTable( - void* dst, size_t dstSize, - const void* cSrc, size_t cSrcSize, - const U16* DTable) -{ - /* Check */ - if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */ - - { const BYTE* const istart = (const BYTE*) cSrc; - BYTE* const ostart = (BYTE*) dst; - BYTE* const oend = ostart + dstSize; - const void* const dtPtr = DTable; - const HUFv06_DEltX2* const dt = ((const HUFv06_DEltX2*)dtPtr) +1; - const U32 dtLog = DTable[0]; - size_t errorCode; - - /* Init */ - BITv06_DStream_t bitD1; - BITv06_DStream_t bitD2; - BITv06_DStream_t bitD3; - BITv06_DStream_t bitD4; - const size_t length1 = MEM_readLE16(istart); - const size_t length2 = MEM_readLE16(istart+2); - const size_t length3 = MEM_readLE16(istart+4); - size_t length4; - const BYTE* const istart1 = istart + 6; /* jumpTable */ - const BYTE* const istart2 = istart1 + length1; - const BYTE* const istart3 = istart2 + length2; - const BYTE* const istart4 = istart3 + length3; - const size_t segmentSize = (dstSize+3) / 4; - BYTE* const opStart2 = ostart + segmentSize; - BYTE* const opStart3 = opStart2 + segmentSize; - BYTE* const opStart4 = opStart3 + segmentSize; - BYTE* op1 = ostart; - BYTE* op2 = opStart2; - BYTE* op3 = opStart3; - BYTE* op4 = opStart4; - U32 endSignal; - - length4 = cSrcSize - (length1 + length2 + length3 + 6); - if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */ - errorCode = BITv06_initDStream(&bitD1, istart1, length1); - if (HUFv06_isError(errorCode)) return errorCode; - errorCode = BITv06_initDStream(&bitD2, istart2, length2); - if (HUFv06_isError(errorCode)) return errorCode; - errorCode = BITv06_initDStream(&bitD3, istart3, length3); - if (HUFv06_isError(errorCode)) return errorCode; - errorCode = BITv06_initDStream(&bitD4, istart4, length4); - if (HUFv06_isError(errorCode)) return errorCode; - - /* 16-32 symbols per loop (4-8 symbols per stream) */ - endSignal = BITv06_reloadDStream(&bitD1) | BITv06_reloadDStream(&bitD2) | BITv06_reloadDStream(&bitD3) | BITv06_reloadDStream(&bitD4); - for ( ; (endSignal==BITv06_DStream_unfinished) && (op4<(oend-7)) ; ) { - HUFv06_DECODE_SYMBOLX2_2(op1, &bitD1); - HUFv06_DECODE_SYMBOLX2_2(op2, &bitD2); - HUFv06_DECODE_SYMBOLX2_2(op3, &bitD3); - HUFv06_DECODE_SYMBOLX2_2(op4, &bitD4); - HUFv06_DECODE_SYMBOLX2_1(op1, &bitD1); - HUFv06_DECODE_SYMBOLX2_1(op2, &bitD2); - HUFv06_DECODE_SYMBOLX2_1(op3, &bitD3); - HUFv06_DECODE_SYMBOLX2_1(op4, &bitD4); - HUFv06_DECODE_SYMBOLX2_2(op1, &bitD1); - HUFv06_DECODE_SYMBOLX2_2(op2, &bitD2); - HUFv06_DECODE_SYMBOLX2_2(op3, &bitD3); - HUFv06_DECODE_SYMBOLX2_2(op4, &bitD4); - HUFv06_DECODE_SYMBOLX2_0(op1, &bitD1); - HUFv06_DECODE_SYMBOLX2_0(op2, &bitD2); - HUFv06_DECODE_SYMBOLX2_0(op3, &bitD3); - HUFv06_DECODE_SYMBOLX2_0(op4, &bitD4); - endSignal = BITv06_reloadDStream(&bitD1) | BITv06_reloadDStream(&bitD2) | BITv06_reloadDStream(&bitD3) | BITv06_reloadDStream(&bitD4); - } - - /* check corruption */ - if (op1 > opStart2) return ERROR(corruption_detected); - if (op2 > opStart3) return ERROR(corruption_detected); - if (op3 > opStart4) return ERROR(corruption_detected); - /* note : op4 supposed already verified within main loop */ - - /* finish bitStreams one by one */ - HUFv06_decodeStreamX2(op1, &bitD1, opStart2, dt, dtLog); - HUFv06_decodeStreamX2(op2, &bitD2, opStart3, dt, dtLog); - HUFv06_decodeStreamX2(op3, &bitD3, opStart4, dt, dtLog); - HUFv06_decodeStreamX2(op4, &bitD4, oend, dt, dtLog); - - /* check */ - endSignal = BITv06_endOfDStream(&bitD1) & BITv06_endOfDStream(&bitD2) & BITv06_endOfDStream(&bitD3) & BITv06_endOfDStream(&bitD4); - if (!endSignal) return ERROR(corruption_detected); - - /* decoded size */ - return dstSize; - } -} - - -size_t HUFv06_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) -{ - HUFv06_CREATE_STATIC_DTABLEX2(DTable, HUFv06_MAX_TABLELOG); - const BYTE* ip = (const BYTE*) cSrc; - - size_t const errorCode = HUFv06_readDTableX2 (DTable, cSrc, cSrcSize); - if (HUFv06_isError(errorCode)) return errorCode; - if (errorCode >= cSrcSize) return ERROR(srcSize_wrong); - ip += errorCode; - cSrcSize -= errorCode; - - return HUFv06_decompress4X2_usingDTable (dst, dstSize, ip, cSrcSize, DTable); -} - - -/* *************************/ -/* double-symbols decoding */ -/* *************************/ - -static void HUFv06_fillDTableX4Level2(HUFv06_DEltX4* DTable, U32 sizeLog, const U32 consumed, - const U32* rankValOrigin, const int minWeight, - const sortedSymbol_t* sortedSymbols, const U32 sortedListSize, - U32 nbBitsBaseline, U16 baseSeq) -{ - HUFv06_DEltX4 DElt; - U32 rankVal[HUFv06_ABSOLUTEMAX_TABLELOG + 1]; - - /* get pre-calculated rankVal */ - memcpy(rankVal, rankValOrigin, sizeof(rankVal)); - - /* fill skipped values */ - if (minWeight>1) { - U32 i, skipSize = rankVal[minWeight]; - MEM_writeLE16(&(DElt.sequence), baseSeq); - DElt.nbBits = (BYTE)(consumed); - DElt.length = 1; - for (i = 0; i < skipSize; i++) - DTable[i] = DElt; - } - - /* fill DTable */ - { U32 s; for (s=0; s= 1 */ - - rankVal[weight] += length; - }} -} - -typedef U32 rankVal_t[HUFv06_ABSOLUTEMAX_TABLELOG][HUFv06_ABSOLUTEMAX_TABLELOG + 1]; - -static void HUFv06_fillDTableX4(HUFv06_DEltX4* DTable, const U32 targetLog, - const sortedSymbol_t* sortedList, const U32 sortedListSize, - const U32* rankStart, rankVal_t rankValOrigin, const U32 maxWeight, - const U32 nbBitsBaseline) -{ - U32 rankVal[HUFv06_ABSOLUTEMAX_TABLELOG + 1]; - const int scaleLog = nbBitsBaseline - targetLog; /* note : targetLog >= srcLog, hence scaleLog <= 1 */ - const U32 minBits = nbBitsBaseline - maxWeight; - U32 s; - - memcpy(rankVal, rankValOrigin, sizeof(rankVal)); - - /* fill DTable */ - for (s=0; s= minBits) { /* enough room for a second symbol */ - U32 sortedRank; - int minWeight = nbBits + scaleLog; - if (minWeight < 1) minWeight = 1; - sortedRank = rankStart[minWeight]; - HUFv06_fillDTableX4Level2(DTable+start, targetLog-nbBits, nbBits, - rankValOrigin[nbBits], minWeight, - sortedList+sortedRank, sortedListSize-sortedRank, - nbBitsBaseline, symbol); - } else { - HUFv06_DEltX4 DElt; - MEM_writeLE16(&(DElt.sequence), symbol); - DElt.nbBits = (BYTE)(nbBits); - DElt.length = 1; - { U32 u; - const U32 end = start + length; - for (u = start; u < end; u++) DTable[u] = DElt; - } } - rankVal[weight] += length; - } -} - -size_t HUFv06_readDTableX4 (U32* DTable, const void* src, size_t srcSize) -{ - BYTE weightList[HUFv06_MAX_SYMBOL_VALUE + 1]; - sortedSymbol_t sortedSymbol[HUFv06_MAX_SYMBOL_VALUE + 1]; - U32 rankStats[HUFv06_ABSOLUTEMAX_TABLELOG + 1] = { 0 }; - U32 rankStart0[HUFv06_ABSOLUTEMAX_TABLELOG + 2] = { 0 }; - U32* const rankStart = rankStart0+1; - rankVal_t rankVal; - U32 tableLog, maxW, sizeOfSort, nbSymbols; - const U32 memLog = DTable[0]; - size_t iSize; - void* dtPtr = DTable; - HUFv06_DEltX4* const dt = ((HUFv06_DEltX4*)dtPtr) + 1; - - HUFv06_STATIC_ASSERT(sizeof(HUFv06_DEltX4) == sizeof(U32)); /* if compilation fails here, assertion is false */ - if (memLog > HUFv06_ABSOLUTEMAX_TABLELOG) return ERROR(tableLog_tooLarge); - /* memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */ - - iSize = HUFv06_readStats(weightList, HUFv06_MAX_SYMBOL_VALUE + 1, rankStats, &nbSymbols, &tableLog, src, srcSize); - if (HUFv06_isError(iSize)) return iSize; - - /* check result */ - if (tableLog > memLog) return ERROR(tableLog_tooLarge); /* DTable can't fit code depth */ - - /* find maxWeight */ - for (maxW = tableLog; rankStats[maxW]==0; maxW--) {} /* necessarily finds a solution before 0 */ - - /* Get start index of each weight */ - { U32 w, nextRankStart = 0; - for (w=1; w> consumed; - } } } } - - HUFv06_fillDTableX4(dt, memLog, - sortedSymbol, sizeOfSort, - rankStart0, rankVal, maxW, - tableLog+1); - - return iSize; -} - - -static U32 HUFv06_decodeSymbolX4(void* op, BITv06_DStream_t* DStream, const HUFv06_DEltX4* dt, const U32 dtLog) -{ - const size_t val = BITv06_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */ - memcpy(op, dt+val, 2); - BITv06_skipBits(DStream, dt[val].nbBits); - return dt[val].length; -} - -static U32 HUFv06_decodeLastSymbolX4(void* op, BITv06_DStream_t* DStream, const HUFv06_DEltX4* dt, const U32 dtLog) -{ - const size_t val = BITv06_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */ - memcpy(op, dt+val, 1); - if (dt[val].length==1) BITv06_skipBits(DStream, dt[val].nbBits); - else { - if (DStream->bitsConsumed < (sizeof(DStream->bitContainer)*8)) { - BITv06_skipBits(DStream, dt[val].nbBits); - if (DStream->bitsConsumed > (sizeof(DStream->bitContainer)*8)) - 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 */ - } } - return 1; -} - - -#define HUFv06_DECODE_SYMBOLX4_0(ptr, DStreamPtr) \ - ptr += HUFv06_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog) - -#define HUFv06_DECODE_SYMBOLX4_1(ptr, DStreamPtr) \ - if (MEM_64bits() || (HUFv06_MAX_TABLELOG<=12)) \ - ptr += HUFv06_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog) - -#define HUFv06_DECODE_SYMBOLX4_2(ptr, DStreamPtr) \ - if (MEM_64bits()) \ - ptr += HUFv06_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog) - -static inline size_t HUFv06_decodeStreamX4(BYTE* p, BITv06_DStream_t* bitDPtr, BYTE* const pEnd, const HUFv06_DEltX4* const dt, const U32 dtLog) -{ - BYTE* const pStart = p; - - /* up to 8 symbols at a time */ - while ((BITv06_reloadDStream(bitDPtr) == BITv06_DStream_unfinished) && (p < pEnd-7)) { - HUFv06_DECODE_SYMBOLX4_2(p, bitDPtr); - HUFv06_DECODE_SYMBOLX4_1(p, bitDPtr); - HUFv06_DECODE_SYMBOLX4_2(p, bitDPtr); - HUFv06_DECODE_SYMBOLX4_0(p, bitDPtr); - } - - /* closer to the end */ - while ((BITv06_reloadDStream(bitDPtr) == BITv06_DStream_unfinished) && (p <= pEnd-2)) - HUFv06_DECODE_SYMBOLX4_0(p, bitDPtr); - - while (p <= pEnd-2) - HUFv06_DECODE_SYMBOLX4_0(p, bitDPtr); /* no need to reload : reached the end of DStream */ - - if (p < pEnd) - p += HUFv06_decodeLastSymbolX4(p, bitDPtr, dt, dtLog); - - return p-pStart; -} - - -size_t HUFv06_decompress1X4_usingDTable( - void* dst, size_t dstSize, - const void* cSrc, size_t cSrcSize, - const U32* DTable) -{ - const BYTE* const istart = (const BYTE*) cSrc; - BYTE* const ostart = (BYTE*) dst; - BYTE* const oend = ostart + dstSize; - - const U32 dtLog = DTable[0]; - const void* const dtPtr = DTable; - const HUFv06_DEltX4* const dt = ((const HUFv06_DEltX4*)dtPtr) +1; - - /* Init */ - BITv06_DStream_t bitD; - { size_t const errorCode = BITv06_initDStream(&bitD, istart, cSrcSize); - if (HUFv06_isError(errorCode)) return errorCode; } - - /* decode */ - HUFv06_decodeStreamX4(ostart, &bitD, oend, dt, dtLog); - - /* check */ - if (!BITv06_endOfDStream(&bitD)) return ERROR(corruption_detected); - - /* decoded size */ - return dstSize; -} - -size_t HUFv06_decompress1X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) -{ - HUFv06_CREATE_STATIC_DTABLEX4(DTable, HUFv06_MAX_TABLELOG); - const BYTE* ip = (const BYTE*) cSrc; - - size_t const hSize = HUFv06_readDTableX4 (DTable, cSrc, cSrcSize); - if (HUFv06_isError(hSize)) return hSize; - if (hSize >= cSrcSize) return ERROR(srcSize_wrong); - ip += hSize; - cSrcSize -= hSize; - - return HUFv06_decompress1X4_usingDTable (dst, dstSize, ip, cSrcSize, DTable); -} - -size_t HUFv06_decompress4X4_usingDTable( - void* dst, size_t dstSize, - const void* cSrc, size_t cSrcSize, - const U32* DTable) -{ - if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */ - - { const BYTE* const istart = (const BYTE*) cSrc; - BYTE* const ostart = (BYTE*) dst; - BYTE* const oend = ostart + dstSize; - const void* const dtPtr = DTable; - const HUFv06_DEltX4* const dt = ((const HUFv06_DEltX4*)dtPtr) +1; - const U32 dtLog = DTable[0]; - size_t errorCode; - - /* Init */ - BITv06_DStream_t bitD1; - BITv06_DStream_t bitD2; - BITv06_DStream_t bitD3; - BITv06_DStream_t bitD4; - const size_t length1 = MEM_readLE16(istart); - const size_t length2 = MEM_readLE16(istart+2); - const size_t length3 = MEM_readLE16(istart+4); - size_t length4; - const BYTE* const istart1 = istart + 6; /* jumpTable */ - const BYTE* const istart2 = istart1 + length1; - const BYTE* const istart3 = istart2 + length2; - const BYTE* const istart4 = istart3 + length3; - const size_t segmentSize = (dstSize+3) / 4; - BYTE* const opStart2 = ostart + segmentSize; - BYTE* const opStart3 = opStart2 + segmentSize; - BYTE* const opStart4 = opStart3 + segmentSize; - BYTE* op1 = ostart; - BYTE* op2 = opStart2; - BYTE* op3 = opStart3; - BYTE* op4 = opStart4; - U32 endSignal; - - length4 = cSrcSize - (length1 + length2 + length3 + 6); - if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */ - errorCode = BITv06_initDStream(&bitD1, istart1, length1); - if (HUFv06_isError(errorCode)) return errorCode; - errorCode = BITv06_initDStream(&bitD2, istart2, length2); - if (HUFv06_isError(errorCode)) return errorCode; - errorCode = BITv06_initDStream(&bitD3, istart3, length3); - if (HUFv06_isError(errorCode)) return errorCode; - errorCode = BITv06_initDStream(&bitD4, istart4, length4); - if (HUFv06_isError(errorCode)) return errorCode; - - /* 16-32 symbols per loop (4-8 symbols per stream) */ - endSignal = BITv06_reloadDStream(&bitD1) | BITv06_reloadDStream(&bitD2) | BITv06_reloadDStream(&bitD3) | BITv06_reloadDStream(&bitD4); - for ( ; (endSignal==BITv06_DStream_unfinished) && (op4<(oend-7)) ; ) { - HUFv06_DECODE_SYMBOLX4_2(op1, &bitD1); - HUFv06_DECODE_SYMBOLX4_2(op2, &bitD2); - HUFv06_DECODE_SYMBOLX4_2(op3, &bitD3); - HUFv06_DECODE_SYMBOLX4_2(op4, &bitD4); - HUFv06_DECODE_SYMBOLX4_1(op1, &bitD1); - HUFv06_DECODE_SYMBOLX4_1(op2, &bitD2); - HUFv06_DECODE_SYMBOLX4_1(op3, &bitD3); - HUFv06_DECODE_SYMBOLX4_1(op4, &bitD4); - HUFv06_DECODE_SYMBOLX4_2(op1, &bitD1); - HUFv06_DECODE_SYMBOLX4_2(op2, &bitD2); - HUFv06_DECODE_SYMBOLX4_2(op3, &bitD3); - HUFv06_DECODE_SYMBOLX4_2(op4, &bitD4); - HUFv06_DECODE_SYMBOLX4_0(op1, &bitD1); - HUFv06_DECODE_SYMBOLX4_0(op2, &bitD2); - HUFv06_DECODE_SYMBOLX4_0(op3, &bitD3); - HUFv06_DECODE_SYMBOLX4_0(op4, &bitD4); - - endSignal = BITv06_reloadDStream(&bitD1) | BITv06_reloadDStream(&bitD2) | BITv06_reloadDStream(&bitD3) | BITv06_reloadDStream(&bitD4); - } - - /* check corruption */ - if (op1 > opStart2) return ERROR(corruption_detected); - if (op2 > opStart3) return ERROR(corruption_detected); - if (op3 > opStart4) return ERROR(corruption_detected); - /* note : op4 supposed already verified within main loop */ - - /* finish bitStreams one by one */ - HUFv06_decodeStreamX4(op1, &bitD1, opStart2, dt, dtLog); - HUFv06_decodeStreamX4(op2, &bitD2, opStart3, dt, dtLog); - HUFv06_decodeStreamX4(op3, &bitD3, opStart4, dt, dtLog); - HUFv06_decodeStreamX4(op4, &bitD4, oend, dt, dtLog); - - /* check */ - endSignal = BITv06_endOfDStream(&bitD1) & BITv06_endOfDStream(&bitD2) & BITv06_endOfDStream(&bitD3) & BITv06_endOfDStream(&bitD4); - if (!endSignal) return ERROR(corruption_detected); - - /* decoded size */ - return dstSize; - } -} - - -size_t HUFv06_decompress4X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) -{ - HUFv06_CREATE_STATIC_DTABLEX4(DTable, HUFv06_MAX_TABLELOG); - const BYTE* ip = (const BYTE*) cSrc; - - size_t hSize = HUFv06_readDTableX4 (DTable, cSrc, cSrcSize); - if (HUFv06_isError(hSize)) return hSize; - if (hSize >= cSrcSize) return ERROR(srcSize_wrong); - ip += hSize; - cSrcSize -= hSize; - - return HUFv06_decompress4X4_usingDTable (dst, dstSize, ip, cSrcSize, DTable); -} - - - - -/* ********************************/ -/* Generic decompression selector */ -/* ********************************/ - -typedef struct { U32 tableTime; U32 decode256Time; } algo_time_t; -static const algo_time_t algoTime[16 /* Quantization */][3 /* single, double, quad */] = -{ - /* single, double, quad */ - {{0,0}, {1,1}, {2,2}}, /* Q==0 : impossible */ - {{0,0}, {1,1}, {2,2}}, /* Q==1 : impossible */ - {{ 38,130}, {1313, 74}, {2151, 38}}, /* Q == 2 : 12-18% */ - {{ 448,128}, {1353, 74}, {2238, 41}}, /* Q == 3 : 18-25% */ - {{ 556,128}, {1353, 74}, {2238, 47}}, /* Q == 4 : 25-32% */ - {{ 714,128}, {1418, 74}, {2436, 53}}, /* Q == 5 : 32-38% */ - {{ 883,128}, {1437, 74}, {2464, 61}}, /* Q == 6 : 38-44% */ - {{ 897,128}, {1515, 75}, {2622, 68}}, /* Q == 7 : 44-50% */ - {{ 926,128}, {1613, 75}, {2730, 75}}, /* Q == 8 : 50-56% */ - {{ 947,128}, {1729, 77}, {3359, 77}}, /* Q == 9 : 56-62% */ - {{1107,128}, {2083, 81}, {4006, 84}}, /* Q ==10 : 62-69% */ - {{1177,128}, {2379, 87}, {4785, 88}}, /* Q ==11 : 69-75% */ - {{1242,128}, {2415, 93}, {5155, 84}}, /* Q ==12 : 75-81% */ - {{1349,128}, {2644,106}, {5260,106}}, /* Q ==13 : 81-87% */ - {{1455,128}, {2422,124}, {4174,124}}, /* Q ==14 : 87-93% */ - {{ 722,128}, {1891,145}, {1936,146}}, /* Q ==15 : 93-99% */ -}; - -typedef size_t (*decompressionAlgo)(void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); - -size_t HUFv06_decompress (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) -{ - static const decompressionAlgo decompress[3] = { HUFv06_decompress4X2, HUFv06_decompress4X4, NULL }; - U32 Dtime[3]; /* decompression time estimation */ - - /* validation checks */ - if (dstSize == 0) return ERROR(dstSize_tooSmall); - if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */ - if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */ - if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */ - - /* decoder timing evaluation */ - { U32 const Q = (U32)(cSrcSize * 16 / dstSize); /* Q < 16 since dstSize > cSrcSize */ - U32 const D256 = (U32)(dstSize >> 8); - U32 n; for (n=0; n<3; n++) - Dtime[n] = algoTime[Q][n].tableTime + (algoTime[Q][n].decode256Time * D256); - } - - Dtime[1] += Dtime[1] >> 4; Dtime[2] += Dtime[2] >> 3; /* advantage to algorithms using less memory, for cache eviction */ - - { U32 algoNb = 0; - if (Dtime[1] < Dtime[0]) algoNb = 1; - /* if (Dtime[2] < Dtime[algoNb]) algoNb = 2; */ /* current speed of HUFv06_decompress4X6 is not good */ - return decompress[algoNb](dst, dstSize, cSrc, cSrcSize); - } - - /* return HUFv06_decompress4X2(dst, dstSize, cSrc, cSrcSize); */ /* multi-streams single-symbol decoding */ - /* return HUFv06_decompress4X4(dst, dstSize, cSrc, cSrcSize); */ /* multi-streams double-symbols decoding */ - /* return HUFv06_decompress4X6(dst, dstSize, cSrc, cSrcSize); */ /* multi-streams quad-symbols decoding */ -} -/* - Common functions of Zstd compression library - Copyright (C) 2015-2016, Yann Collet. - - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - zstd homepage : https://facebook.github.io/zstd/ -*/ - - -/*-**************************************** -* Version -******************************************/ - -/*-**************************************** -* ZSTD Error Management -******************************************/ -/*! ZSTDv06_isError() : -* tells if a return value is an error code */ -unsigned ZSTDv06_isError(size_t code) { return ERR_isError(code); } - -/*! ZSTDv06_getErrorName() : -* provides error code string from function result (useful for debugging) */ -const char* ZSTDv06_getErrorName(size_t code) { return ERR_getErrorName(code); } - - -/* ************************************************************** -* ZBUFF Error Management -****************************************************************/ -unsigned ZBUFFv06_isError(size_t errorCode) { return ERR_isError(errorCode); } - -const char* ZBUFFv06_getErrorName(size_t errorCode) { return ERR_getErrorName(errorCode); } -/* - zstd - standard compression library - Copyright (C) 2014-2016, Yann Collet. - - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - zstd homepage : https://facebook.github.io/zstd -*/ - -/* *************************************************************** -* Tuning parameters -*****************************************************************/ -/*! - * HEAPMODE : - * Select how default decompression function ZSTDv06_decompress() will allocate memory, - * in memory stack (0), or in memory heap (1, requires malloc()) - */ -#ifndef ZSTDv06_HEAPMODE -# define ZSTDv06_HEAPMODE 1 -#endif - - - -/*-******************************************************* -* Compiler specifics -*********************************************************/ -#ifdef _MSC_VER /* Visual Studio */ -# include /* For Visual 2005 */ -# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -# pragma warning(disable : 4324) /* disable: C4324: padded structure */ -#endif - - -/*-************************************* -* Macros -***************************************/ -#define ZSTDv06_isError ERR_isError /* for inlining */ -#define FSEv06_isError ERR_isError -#define HUFv06_isError ERR_isError - - -/*_******************************************************* -* Memory operations -**********************************************************/ -static void ZSTDv06_copy4(void* dst, const void* src) { memcpy(dst, src, 4); } - - -/*-************************************************************* -* Context management -***************************************************************/ -typedef enum { ZSTDds_getFrameHeaderSize, ZSTDds_decodeFrameHeader, - ZSTDds_decodeBlockHeader, ZSTDds_decompressBlock } ZSTDv06_dStage; - -struct ZSTDv06_DCtx_s -{ - FSEv06_DTable LLTable[FSEv06_DTABLE_SIZE_U32(LLFSELog)]; - FSEv06_DTable OffTable[FSEv06_DTABLE_SIZE_U32(OffFSELog)]; - FSEv06_DTable MLTable[FSEv06_DTABLE_SIZE_U32(MLFSELog)]; - unsigned hufTableX4[HUFv06_DTABLE_SIZE(ZSTD_HUFFDTABLE_CAPACITY_LOG)]; - const void* previousDstEnd; - const void* base; - const void* vBase; - const void* dictEnd; - size_t expected; - size_t headerSize; - ZSTDv06_frameParams fParams; - blockType_t bType; /* used in ZSTDv06_decompressContinue(), to transfer blockType between header decoding and block decoding stages */ - ZSTDv06_dStage stage; - U32 flagRepeatTable; - const BYTE* litPtr; - size_t litSize; - BYTE litBuffer[ZSTDv06_BLOCKSIZE_MAX + WILDCOPY_OVERLENGTH]; - BYTE headerBuffer[ZSTDv06_FRAMEHEADERSIZE_MAX]; -}; /* typedef'd to ZSTDv06_DCtx within "zstd_static.h" */ - -size_t ZSTDv06_sizeofDCtx (void); /* Hidden declaration */ -size_t ZSTDv06_sizeofDCtx (void) { return sizeof(ZSTDv06_DCtx); } - -size_t ZSTDv06_decompressBegin(ZSTDv06_DCtx* dctx) -{ - dctx->expected = ZSTDv06_frameHeaderSize_min; - dctx->stage = ZSTDds_getFrameHeaderSize; - dctx->previousDstEnd = NULL; - dctx->base = NULL; - dctx->vBase = NULL; - dctx->dictEnd = NULL; - dctx->hufTableX4[0] = ZSTD_HUFFDTABLE_CAPACITY_LOG; - dctx->flagRepeatTable = 0; - return 0; -} - -ZSTDv06_DCtx* ZSTDv06_createDCtx(void) -{ - ZSTDv06_DCtx* dctx = (ZSTDv06_DCtx*)malloc(sizeof(ZSTDv06_DCtx)); - if (dctx==NULL) return NULL; - ZSTDv06_decompressBegin(dctx); - return dctx; -} - -size_t ZSTDv06_freeDCtx(ZSTDv06_DCtx* dctx) -{ - free(dctx); - return 0; /* reserved as a potential error code in the future */ -} - -void ZSTDv06_copyDCtx(ZSTDv06_DCtx* dstDCtx, const ZSTDv06_DCtx* srcDCtx) -{ - memcpy(dstDCtx, srcDCtx, - sizeof(ZSTDv06_DCtx) - (ZSTDv06_BLOCKSIZE_MAX+WILDCOPY_OVERLENGTH + ZSTDv06_frameHeaderSize_max)); /* no need to copy workspace */ -} - - -/*-************************************************************* -* Decompression section -***************************************************************/ - -/* Frame format description - Frame Header - [ Block Header - Block ] - Frame End - 1) Frame Header - - 4 bytes - Magic Number : ZSTDv06_MAGICNUMBER (defined within zstd_static.h) - - 1 byte - Frame Descriptor - 2) Block Header - - 3 bytes, starting with a 2-bits descriptor - Uncompressed, Compressed, Frame End, unused - 3) Block - See Block Format Description - 4) Frame End - - 3 bytes, compatible with Block Header -*/ - - -/* Frame descriptor - - 1 byte, using : - bit 0-3 : windowLog - ZSTDv06_WINDOWLOG_ABSOLUTEMIN (see zstd_internal.h) - bit 4 : minmatch 4(0) or 3(1) - bit 5 : reserved (must be zero) - bit 6-7 : Frame content size : unknown, 1 byte, 2 bytes, 8 bytes - - Optional : content size (0, 1, 2 or 8 bytes) - 0 : unknown - 1 : 0-255 bytes - 2 : 256 - 65535+256 - 8 : up to 16 exa -*/ - - -/* Compressed Block, format description - - Block = Literal Section - Sequences Section - Prerequisite : size of (compressed) block, maximum size of regenerated data - - 1) Literal Section - - 1.1) Header : 1-5 bytes - flags: 2 bits - 00 compressed by Huff0 - 01 unused - 10 is Raw (uncompressed) - 11 is Rle - Note : using 01 => Huff0 with precomputed table ? - Note : delta map ? => compressed ? - - 1.1.1) Huff0-compressed literal block : 3-5 bytes - srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream - srcSize < 1 KB => 3 bytes (2-2-10-10) - srcSize < 16KB => 4 bytes (2-2-14-14) - else => 5 bytes (2-2-18-18) - big endian convention - - 1.1.2) Raw (uncompressed) literal block header : 1-3 bytes - size : 5 bits: (IS_RAW<<6) + (0<<4) + size - 12 bits: (IS_RAW<<6) + (2<<4) + (size>>8) - size&255 - 20 bits: (IS_RAW<<6) + (3<<4) + (size>>16) - size>>8&255 - size&255 - - 1.1.3) Rle (repeated single byte) literal block header : 1-3 bytes - size : 5 bits: (IS_RLE<<6) + (0<<4) + size - 12 bits: (IS_RLE<<6) + (2<<4) + (size>>8) - size&255 - 20 bits: (IS_RLE<<6) + (3<<4) + (size>>16) - size>>8&255 - size&255 - - 1.1.4) Huff0-compressed literal block, using precomputed CTables : 3-5 bytes - srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream - srcSize < 1 KB => 3 bytes (2-2-10-10) - srcSize < 16KB => 4 bytes (2-2-14-14) - else => 5 bytes (2-2-18-18) - big endian convention - - 1- CTable available (stored into workspace ?) - 2- Small input (fast heuristic ? Full comparison ? depend on clevel ?) - - - 1.2) Literal block content - - 1.2.1) Huff0 block, using sizes from header - See Huff0 format - - 1.2.2) Huff0 block, using prepared table - - 1.2.3) Raw content - - 1.2.4) single byte - - - 2) Sequences section - TO DO -*/ - -/** ZSTDv06_frameHeaderSize() : -* srcSize must be >= ZSTDv06_frameHeaderSize_min. -* @return : size of the Frame Header */ -static size_t ZSTDv06_frameHeaderSize(const void* src, size_t srcSize) -{ - if (srcSize < ZSTDv06_frameHeaderSize_min) return ERROR(srcSize_wrong); - { U32 const fcsId = (((const BYTE*)src)[4]) >> 6; - return ZSTDv06_frameHeaderSize_min + ZSTDv06_fcs_fieldSize[fcsId]; } -} - - -/** ZSTDv06_getFrameParams() : -* decode Frame Header, or provide expected `srcSize`. -* @return : 0, `fparamsPtr` is correctly filled, -* >0, `srcSize` is too small, result is expected `srcSize`, -* or an error code, which can be tested using ZSTDv06_isError() */ -size_t ZSTDv06_getFrameParams(ZSTDv06_frameParams* fparamsPtr, const void* src, size_t srcSize) -{ - const BYTE* ip = (const BYTE*)src; - - if (srcSize < ZSTDv06_frameHeaderSize_min) return ZSTDv06_frameHeaderSize_min; - if (MEM_readLE32(src) != ZSTDv06_MAGICNUMBER) return ERROR(prefix_unknown); - - /* ensure there is enough `srcSize` to fully read/decode frame header */ - { size_t const fhsize = ZSTDv06_frameHeaderSize(src, srcSize); - if (srcSize < fhsize) return fhsize; } - - memset(fparamsPtr, 0, sizeof(*fparamsPtr)); - { BYTE const frameDesc = ip[4]; - fparamsPtr->windowLog = (frameDesc & 0xF) + ZSTDv06_WINDOWLOG_ABSOLUTEMIN; - if ((frameDesc & 0x20) != 0) return ERROR(frameParameter_unsupported); /* reserved 1 bit */ - switch(frameDesc >> 6) /* fcsId */ - { - default: /* impossible */ - case 0 : fparamsPtr->frameContentSize = 0; break; - case 1 : fparamsPtr->frameContentSize = ip[5]; break; - case 2 : fparamsPtr->frameContentSize = MEM_readLE16(ip+5)+256; break; - case 3 : fparamsPtr->frameContentSize = MEM_readLE64(ip+5); break; - } } - return 0; -} - - -/** ZSTDv06_decodeFrameHeader() : -* `srcSize` must be the size provided by ZSTDv06_frameHeaderSize(). -* @return : 0 if success, or an error code, which can be tested using ZSTDv06_isError() */ -static size_t ZSTDv06_decodeFrameHeader(ZSTDv06_DCtx* zc, const void* src, size_t srcSize) -{ - size_t const result = ZSTDv06_getFrameParams(&(zc->fParams), src, srcSize); - if ((MEM_32bits()) && (zc->fParams.windowLog > 25)) return ERROR(frameParameter_unsupported); - return result; -} - - -typedef struct -{ - blockType_t blockType; - U32 origSize; -} blockProperties_t; - -/*! ZSTDv06_getcBlockSize() : -* Provides the size of compressed block from block header `src` */ -static size_t ZSTDv06_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr) -{ - const BYTE* const in = (const BYTE*)src; - U32 cSize; - - if (srcSize < ZSTDv06_blockHeaderSize) return ERROR(srcSize_wrong); - - bpPtr->blockType = (blockType_t)((*in) >> 6); - cSize = in[2] + (in[1]<<8) + ((in[0] & 7)<<16); - bpPtr->origSize = (bpPtr->blockType == bt_rle) ? cSize : 0; - - if (bpPtr->blockType == bt_end) return 0; - if (bpPtr->blockType == bt_rle) return 1; - return cSize; -} - - -static size_t ZSTDv06_copyRawBlock(void* dst, size_t dstCapacity, const void* src, size_t srcSize) -{ - if (dst==NULL) return ERROR(dstSize_tooSmall); - if (srcSize > dstCapacity) return ERROR(dstSize_tooSmall); - memcpy(dst, src, srcSize); - return srcSize; -} - - -/*! ZSTDv06_decodeLiteralsBlock() : - @return : nb of bytes read from src (< srcSize ) */ -static size_t ZSTDv06_decodeLiteralsBlock(ZSTDv06_DCtx* dctx, - const void* src, size_t srcSize) /* note : srcSize < BLOCKSIZE */ -{ - const BYTE* const istart = (const BYTE*) src; - - /* any compressed block with literals segment must be at least this size */ - if (srcSize < MIN_CBLOCK_SIZE) return ERROR(corruption_detected); - - switch(istart[0]>> 6) - { - case IS_HUF: - { size_t litSize, litCSize, singleStream=0; - U32 lhSize = ((istart[0]) >> 4) & 3; - if (srcSize < 5) return ERROR(corruption_detected); /* srcSize >= MIN_CBLOCK_SIZE == 3; here we need up to 5 for lhSize, + cSize (+nbSeq) */ - switch(lhSize) - { - case 0: case 1: default: /* note : default is impossible, since lhSize into [0..3] */ - /* 2 - 2 - 10 - 10 */ - lhSize=3; - singleStream = istart[0] & 16; - litSize = ((istart[0] & 15) << 6) + (istart[1] >> 2); - litCSize = ((istart[1] & 3) << 8) + istart[2]; - break; - case 2: - /* 2 - 2 - 14 - 14 */ - lhSize=4; - litSize = ((istart[0] & 15) << 10) + (istart[1] << 2) + (istart[2] >> 6); - litCSize = ((istart[2] & 63) << 8) + istart[3]; - break; - case 3: - /* 2 - 2 - 18 - 18 */ - lhSize=5; - litSize = ((istart[0] & 15) << 14) + (istart[1] << 6) + (istart[2] >> 2); - litCSize = ((istart[2] & 3) << 16) + (istart[3] << 8) + istart[4]; - break; - } - if (litSize > ZSTDv06_BLOCKSIZE_MAX) return ERROR(corruption_detected); - if (litCSize + lhSize > srcSize) return ERROR(corruption_detected); - - if (HUFv06_isError(singleStream ? - HUFv06_decompress1X2(dctx->litBuffer, litSize, istart+lhSize, litCSize) : - HUFv06_decompress (dctx->litBuffer, litSize, istart+lhSize, litCSize) )) - return ERROR(corruption_detected); - - dctx->litPtr = dctx->litBuffer; - dctx->litSize = litSize; - memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH); - return litCSize + lhSize; - } - case IS_PCH: - { size_t litSize, litCSize; - U32 lhSize = ((istart[0]) >> 4) & 3; - if (lhSize != 1) /* only case supported for now : small litSize, single stream */ - return ERROR(corruption_detected); - if (!dctx->flagRepeatTable) - return ERROR(dictionary_corrupted); - - /* 2 - 2 - 10 - 10 */ - lhSize=3; - litSize = ((istart[0] & 15) << 6) + (istart[1] >> 2); - litCSize = ((istart[1] & 3) << 8) + istart[2]; - if (litCSize + lhSize > srcSize) return ERROR(corruption_detected); - - { size_t const errorCode = HUFv06_decompress1X4_usingDTable(dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->hufTableX4); - if (HUFv06_isError(errorCode)) return ERROR(corruption_detected); - } - dctx->litPtr = dctx->litBuffer; - dctx->litSize = litSize; - memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH); - return litCSize + lhSize; - } - case IS_RAW: - { size_t litSize; - U32 lhSize = ((istart[0]) >> 4) & 3; - switch(lhSize) - { - case 0: case 1: default: /* note : default is impossible, since lhSize into [0..3] */ - lhSize=1; - litSize = istart[0] & 31; - break; - case 2: - litSize = ((istart[0] & 15) << 8) + istart[1]; - break; - case 3: - litSize = ((istart[0] & 15) << 16) + (istart[1] << 8) + istart[2]; - break; - } - - if (lhSize+litSize+WILDCOPY_OVERLENGTH > srcSize) { /* risk reading beyond src buffer with wildcopy */ - if (litSize+lhSize > srcSize) return ERROR(corruption_detected); - memcpy(dctx->litBuffer, istart+lhSize, litSize); - dctx->litPtr = dctx->litBuffer; - dctx->litSize = litSize; - memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH); - return lhSize+litSize; - } - /* direct reference into compressed stream */ - dctx->litPtr = istart+lhSize; - dctx->litSize = litSize; - return lhSize+litSize; - } - case IS_RLE: - { size_t litSize; - U32 lhSize = ((istart[0]) >> 4) & 3; - switch(lhSize) - { - case 0: case 1: default: /* note : default is impossible, since lhSize into [0..3] */ - lhSize = 1; - litSize = istart[0] & 31; - break; - case 2: - litSize = ((istart[0] & 15) << 8) + istart[1]; - break; - case 3: - litSize = ((istart[0] & 15) << 16) + (istart[1] << 8) + istart[2]; - if (srcSize<4) return ERROR(corruption_detected); /* srcSize >= MIN_CBLOCK_SIZE == 3; here we need lhSize+1 = 4 */ - break; - } - if (litSize > ZSTDv06_BLOCKSIZE_MAX) return ERROR(corruption_detected); - memset(dctx->litBuffer, istart[lhSize], litSize + WILDCOPY_OVERLENGTH); - dctx->litPtr = dctx->litBuffer; - dctx->litSize = litSize; - return lhSize+1; - } - default: - return ERROR(corruption_detected); /* impossible */ - } -} - - -/*! ZSTDv06_buildSeqTable() : - @return : nb bytes read from src, - or an error code if it fails, testable with ZSTDv06_isError() -*/ -static size_t ZSTDv06_buildSeqTable(FSEv06_DTable* DTable, U32 type, U32 max, U32 maxLog, - const void* src, size_t srcSize, - const S16* defaultNorm, U32 defaultLog, U32 flagRepeatTable) -{ - switch(type) - { - case FSEv06_ENCODING_RLE : - if (!srcSize) return ERROR(srcSize_wrong); - if ( (*(const BYTE*)src) > max) return ERROR(corruption_detected); - FSEv06_buildDTable_rle(DTable, *(const BYTE*)src); /* if *src > max, data is corrupted */ - return 1; - case FSEv06_ENCODING_RAW : - FSEv06_buildDTable(DTable, defaultNorm, max, defaultLog); - return 0; - case FSEv06_ENCODING_STATIC: - if (!flagRepeatTable) return ERROR(corruption_detected); - return 0; - default : /* impossible */ - case FSEv06_ENCODING_DYNAMIC : - { U32 tableLog; - S16 norm[MaxSeq+1]; - size_t const headerSize = FSEv06_readNCount(norm, &max, &tableLog, src, srcSize); - if (FSEv06_isError(headerSize)) return ERROR(corruption_detected); - if (tableLog > maxLog) return ERROR(corruption_detected); - FSEv06_buildDTable(DTable, norm, max, tableLog); - return headerSize; - } } -} - - -static size_t ZSTDv06_decodeSeqHeaders(int* nbSeqPtr, - FSEv06_DTable* DTableLL, FSEv06_DTable* DTableML, FSEv06_DTable* DTableOffb, U32 flagRepeatTable, - const void* src, size_t srcSize) -{ - const BYTE* const istart = (const BYTE*)src; - const BYTE* const iend = istart + srcSize; - const BYTE* ip = istart; - - /* check */ - if (srcSize < MIN_SEQUENCES_SIZE) return ERROR(srcSize_wrong); - - /* SeqHead */ - { int nbSeq = *ip++; - if (!nbSeq) { *nbSeqPtr=0; return 1; } - if (nbSeq > 0x7F) { - if (nbSeq == 0xFF) { - if (ip+2 > iend) return ERROR(srcSize_wrong); - nbSeq = MEM_readLE16(ip) + LONGNBSEQ, ip+=2; - } else { - if (ip >= iend) return ERROR(srcSize_wrong); - nbSeq = ((nbSeq-0x80)<<8) + *ip++; - } - } - *nbSeqPtr = nbSeq; - } - - /* FSE table descriptors */ - if (ip + 4 > iend) return ERROR(srcSize_wrong); /* min : header byte + all 3 are "raw", hence no header, but at least xxLog bits per type */ - { U32 const LLtype = *ip >> 6; - U32 const Offtype = (*ip >> 4) & 3; - U32 const MLtype = (*ip >> 2) & 3; - ip++; - - /* Build DTables */ - { size_t const bhSize = ZSTDv06_buildSeqTable(DTableLL, LLtype, MaxLL, LLFSELog, ip, iend-ip, LL_defaultNorm, LL_defaultNormLog, flagRepeatTable); - if (ZSTDv06_isError(bhSize)) return ERROR(corruption_detected); - ip += bhSize; - } - { size_t const bhSize = ZSTDv06_buildSeqTable(DTableOffb, Offtype, MaxOff, OffFSELog, ip, iend-ip, OF_defaultNorm, OF_defaultNormLog, flagRepeatTable); - if (ZSTDv06_isError(bhSize)) return ERROR(corruption_detected); - ip += bhSize; - } - { size_t const bhSize = ZSTDv06_buildSeqTable(DTableML, MLtype, MaxML, MLFSELog, ip, iend-ip, ML_defaultNorm, ML_defaultNormLog, flagRepeatTable); - if (ZSTDv06_isError(bhSize)) return ERROR(corruption_detected); - ip += bhSize; - } } - - return ip-istart; -} - - -typedef struct { - size_t litLength; - size_t matchLength; - size_t offset; -} seq_t; - -typedef struct { - BITv06_DStream_t DStream; - FSEv06_DState_t stateLL; - FSEv06_DState_t stateOffb; - FSEv06_DState_t stateML; - size_t prevOffset[ZSTDv06_REP_INIT]; -} seqState_t; - - - -static void ZSTDv06_decodeSequence(seq_t* seq, seqState_t* seqState) -{ - /* Literal length */ - U32 const llCode = FSEv06_peekSymbol(&(seqState->stateLL)); - U32 const mlCode = FSEv06_peekSymbol(&(seqState->stateML)); - U32 const ofCode = FSEv06_peekSymbol(&(seqState->stateOffb)); /* <= maxOff, by table construction */ - - U32 const llBits = LL_bits[llCode]; - U32 const mlBits = ML_bits[mlCode]; - U32 const ofBits = ofCode; - U32 const totalBits = llBits+mlBits+ofBits; - - static const U32 LL_base[MaxLL+1] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 18, 20, 22, 24, 28, 32, 40, 48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, - 0x2000, 0x4000, 0x8000, 0x10000 }; - - static const U32 ML_base[MaxML+1] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 34, 36, 38, 40, 44, 48, 56, 64, 80, 96, 0x80, 0x100, 0x200, 0x400, 0x800, - 0x1000, 0x2000, 0x4000, 0x8000, 0x10000 }; - - static const U32 OF_base[MaxOff+1] = { - 0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, - 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, - 0xFFFF, 0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, - 0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF, /*fake*/ 1, 1 }; - - /* sequence */ - { size_t offset; - if (!ofCode) - offset = 0; - else { - offset = OF_base[ofCode] + BITv06_readBits(&(seqState->DStream), ofBits); /* <= 26 bits */ - if (MEM_32bits()) BITv06_reloadDStream(&(seqState->DStream)); - } - - if (offset < ZSTDv06_REP_NUM) { - if (llCode == 0 && offset <= 1) offset = 1-offset; - - if (offset != 0) { - size_t temp = seqState->prevOffset[offset]; - if (offset != 1) { - seqState->prevOffset[2] = seqState->prevOffset[1]; - } - seqState->prevOffset[1] = seqState->prevOffset[0]; - seqState->prevOffset[0] = offset = temp; - - } else { - offset = seqState->prevOffset[0]; - } - } else { - offset -= ZSTDv06_REP_MOVE; - seqState->prevOffset[2] = seqState->prevOffset[1]; - seqState->prevOffset[1] = seqState->prevOffset[0]; - seqState->prevOffset[0] = offset; - } - seq->offset = offset; - } - - seq->matchLength = ML_base[mlCode] + MINMATCH + ((mlCode>31) ? BITv06_readBits(&(seqState->DStream), mlBits) : 0); /* <= 16 bits */ - if (MEM_32bits() && (mlBits+llBits>24)) BITv06_reloadDStream(&(seqState->DStream)); - - seq->litLength = LL_base[llCode] + ((llCode>15) ? BITv06_readBits(&(seqState->DStream), llBits) : 0); /* <= 16 bits */ - if (MEM_32bits() || - (totalBits > 64 - 7 - (LLFSELog+MLFSELog+OffFSELog)) ) BITv06_reloadDStream(&(seqState->DStream)); - - /* ANS state update */ - FSEv06_updateState(&(seqState->stateLL), &(seqState->DStream)); /* <= 9 bits */ - FSEv06_updateState(&(seqState->stateML), &(seqState->DStream)); /* <= 9 bits */ - if (MEM_32bits()) BITv06_reloadDStream(&(seqState->DStream)); /* <= 18 bits */ - FSEv06_updateState(&(seqState->stateOffb), &(seqState->DStream)); /* <= 8 bits */ -} - - -static size_t ZSTDv06_execSequence(BYTE* op, - BYTE* const oend, seq_t sequence, - const BYTE** litPtr, const BYTE* const litLimit, - const BYTE* const base, const BYTE* const vBase, const BYTE* const dictEnd) -{ - BYTE* const oLitEnd = op + sequence.litLength; - size_t const sequenceLength = sequence.litLength + sequence.matchLength; - BYTE* const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */ - BYTE* const oend_8 = oend-8; - const BYTE* const iLitEnd = *litPtr + sequence.litLength; - const BYTE* match = oLitEnd - sequence.offset; - - /* checks */ - size_t const seqLength = sequence.litLength + sequence.matchLength; - - if (seqLength > (size_t)(oend - op)) return ERROR(dstSize_tooSmall); - if (sequence.litLength > (size_t)(litLimit - *litPtr)) return ERROR(corruption_detected); - /* Now we know there are no overflow in literal nor match lengths, can use pointer checks */ - if (oLitEnd > oend_8) return ERROR(dstSize_tooSmall); - - if (oMatchEnd > oend) return ERROR(dstSize_tooSmall); /* overwrite beyond dst buffer */ - if (iLitEnd > litLimit) return ERROR(corruption_detected); /* overRead beyond lit buffer */ - - /* copy Literals */ - ZSTDv06_wildcopy(op, *litPtr, (ptrdiff_t)sequence.litLength); /* note : oLitEnd <= oend-8 : no risk of overwrite beyond oend */ - op = oLitEnd; - *litPtr = iLitEnd; /* update for next sequence */ - - /* copy Match */ - if (sequence.offset > (size_t)(oLitEnd - base)) { - /* offset beyond prefix */ - if (sequence.offset > (size_t)(oLitEnd - vBase)) return ERROR(corruption_detected); - match = dictEnd - (base-match); - if (match + sequence.matchLength <= dictEnd) { - memmove(oLitEnd, match, sequence.matchLength); - return sequenceLength; - } - /* span extDict & currentPrefixSegment */ - { size_t const length1 = dictEnd - match; - memmove(oLitEnd, match, length1); - op = oLitEnd + length1; - sequence.matchLength -= length1; - match = base; - if (op > oend_8 || sequence.matchLength < MINMATCH) { - while (op < oMatchEnd) *op++ = *match++; - return sequenceLength; - } - } } - /* Requirement: op <= oend_8 */ - - /* match within prefix */ - if (sequence.offset < 8) { - /* close range match, overlap */ - static const U32 dec32table[] = { 0, 1, 2, 1, 4, 4, 4, 4 }; /* added */ - static const int dec64table[] = { 8, 8, 8, 7, 8, 9,10,11 }; /* subtracted */ - int const sub2 = dec64table[sequence.offset]; - op[0] = match[0]; - op[1] = match[1]; - op[2] = match[2]; - op[3] = match[3]; - match += dec32table[sequence.offset]; - ZSTDv06_copy4(op+4, match); - match -= sub2; - } else { - ZSTDv06_copy8(op, match); - } - op += 8; match += 8; - - if (oMatchEnd > oend-(16-MINMATCH)) { - if (op < oend_8) { - ZSTDv06_wildcopy(op, match, oend_8 - op); - match += oend_8 - op; - op = oend_8; - } - while (op < oMatchEnd) *op++ = *match++; - } else { - ZSTDv06_wildcopy(op, match, (ptrdiff_t)sequence.matchLength-8); /* works even if matchLength < 8 */ - } - return sequenceLength; -} - - -static size_t ZSTDv06_decompressSequences( - ZSTDv06_DCtx* dctx, - void* dst, size_t maxDstSize, - const void* seqStart, size_t seqSize) -{ - const BYTE* ip = (const BYTE*)seqStart; - const BYTE* const iend = ip + seqSize; - BYTE* const ostart = (BYTE*)dst; - BYTE* const oend = ostart + maxDstSize; - BYTE* op = ostart; - const BYTE* litPtr = dctx->litPtr; - const BYTE* const litEnd = litPtr + dctx->litSize; - FSEv06_DTable* DTableLL = dctx->LLTable; - FSEv06_DTable* DTableML = dctx->MLTable; - FSEv06_DTable* DTableOffb = dctx->OffTable; - const BYTE* const base = (const BYTE*) (dctx->base); - const BYTE* const vBase = (const BYTE*) (dctx->vBase); - const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd); - int nbSeq; - - /* Build Decoding Tables */ - { size_t const seqHSize = ZSTDv06_decodeSeqHeaders(&nbSeq, DTableLL, DTableML, DTableOffb, dctx->flagRepeatTable, ip, seqSize); - if (ZSTDv06_isError(seqHSize)) return seqHSize; - ip += seqHSize; - dctx->flagRepeatTable = 0; - } - - /* Regen sequences */ - if (nbSeq) { - seq_t sequence; - seqState_t seqState; - - memset(&sequence, 0, sizeof(sequence)); - sequence.offset = REPCODE_STARTVALUE; - { U32 i; for (i=0; i= 5810037) && (pos < 5810400)) - printf("Dpos %6u :%5u literals & match %3u bytes at distance %6u \n", - pos, (U32)sequence.litLength, (U32)sequence.matchLength, (U32)sequence.offset); -#endif - - { size_t const oneSeqSize = ZSTDv06_execSequence(op, oend, sequence, &litPtr, litEnd, base, vBase, dictEnd); - if (ZSTDv06_isError(oneSeqSize)) return oneSeqSize; - op += oneSeqSize; - } } - - /* check if reached exact end */ - if (nbSeq) return ERROR(corruption_detected); - } - - /* last literal segment */ - { size_t const lastLLSize = litEnd - litPtr; - if (litPtr > litEnd) return ERROR(corruption_detected); /* too many literals already used */ - if (op+lastLLSize > oend) return ERROR(dstSize_tooSmall); - if (lastLLSize > 0) { - memcpy(op, litPtr, lastLLSize); - op += lastLLSize; - } - } - - return op-ostart; -} - - -static void ZSTDv06_checkContinuity(ZSTDv06_DCtx* dctx, const void* dst) -{ - if (dst != dctx->previousDstEnd) { /* not contiguous */ - dctx->dictEnd = dctx->previousDstEnd; - dctx->vBase = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->base)); - dctx->base = dst; - dctx->previousDstEnd = dst; - } -} - - -static size_t ZSTDv06_decompressBlock_internal(ZSTDv06_DCtx* dctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize) -{ /* blockType == blockCompressed */ - const BYTE* ip = (const BYTE*)src; - - if (srcSize >= ZSTDv06_BLOCKSIZE_MAX) return ERROR(srcSize_wrong); - - /* Decode literals sub-block */ - { size_t const litCSize = ZSTDv06_decodeLiteralsBlock(dctx, src, srcSize); - if (ZSTDv06_isError(litCSize)) return litCSize; - ip += litCSize; - srcSize -= litCSize; - } - return ZSTDv06_decompressSequences(dctx, dst, dstCapacity, ip, srcSize); -} - - -size_t ZSTDv06_decompressBlock(ZSTDv06_DCtx* dctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize) -{ - ZSTDv06_checkContinuity(dctx, dst); - return ZSTDv06_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize); -} - - -/*! ZSTDv06_decompressFrame() : -* `dctx` must be properly initialized */ -static size_t ZSTDv06_decompressFrame(ZSTDv06_DCtx* dctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize) -{ - const BYTE* ip = (const BYTE*)src; - const BYTE* const iend = ip + srcSize; - BYTE* const ostart = (BYTE*)dst; - BYTE* op = ostart; - BYTE* const oend = ostart + dstCapacity; - size_t remainingSize = srcSize; - blockProperties_t blockProperties = { bt_compressed, 0 }; - - /* check */ - if (srcSize < ZSTDv06_frameHeaderSize_min+ZSTDv06_blockHeaderSize) return ERROR(srcSize_wrong); - - /* Frame Header */ - { size_t const frameHeaderSize = ZSTDv06_frameHeaderSize(src, ZSTDv06_frameHeaderSize_min); - if (ZSTDv06_isError(frameHeaderSize)) return frameHeaderSize; - if (srcSize < frameHeaderSize+ZSTDv06_blockHeaderSize) return ERROR(srcSize_wrong); - if (ZSTDv06_decodeFrameHeader(dctx, src, frameHeaderSize)) return ERROR(corruption_detected); - ip += frameHeaderSize; remainingSize -= frameHeaderSize; - } - - /* Loop on each block */ - while (1) { - size_t decodedSize=0; - size_t const cBlockSize = ZSTDv06_getcBlockSize(ip, iend-ip, &blockProperties); - if (ZSTDv06_isError(cBlockSize)) return cBlockSize; - - ip += ZSTDv06_blockHeaderSize; - remainingSize -= ZSTDv06_blockHeaderSize; - if (cBlockSize > remainingSize) return ERROR(srcSize_wrong); - - switch(blockProperties.blockType) - { - case bt_compressed: - decodedSize = ZSTDv06_decompressBlock_internal(dctx, op, oend-op, ip, cBlockSize); - break; - case bt_raw : - decodedSize = ZSTDv06_copyRawBlock(op, oend-op, ip, cBlockSize); - break; - case bt_rle : - return ERROR(GENERIC); /* not yet supported */ - break; - case bt_end : - /* end of frame */ - if (remainingSize) return ERROR(srcSize_wrong); - break; - default: - return ERROR(GENERIC); /* impossible */ - } - if (cBlockSize == 0) break; /* bt_end */ - - if (ZSTDv06_isError(decodedSize)) return decodedSize; - op += decodedSize; - ip += cBlockSize; - remainingSize -= cBlockSize; - } - - return op-ostart; -} - - -size_t ZSTDv06_decompress_usingPreparedDCtx(ZSTDv06_DCtx* dctx, const ZSTDv06_DCtx* refDCtx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize) -{ - ZSTDv06_copyDCtx(dctx, refDCtx); - ZSTDv06_checkContinuity(dctx, dst); - return ZSTDv06_decompressFrame(dctx, dst, dstCapacity, src, srcSize); -} - - -size_t ZSTDv06_decompress_usingDict(ZSTDv06_DCtx* dctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - const void* dict, size_t dictSize) -{ - ZSTDv06_decompressBegin_usingDict(dctx, dict, dictSize); - ZSTDv06_checkContinuity(dctx, dst); - return ZSTDv06_decompressFrame(dctx, dst, dstCapacity, src, srcSize); -} - - -size_t ZSTDv06_decompressDCtx(ZSTDv06_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) -{ - return ZSTDv06_decompress_usingDict(dctx, dst, dstCapacity, src, srcSize, NULL, 0); -} - - -size_t ZSTDv06_decompress(void* dst, size_t dstCapacity, const void* src, size_t srcSize) -{ -#if defined(ZSTDv06_HEAPMODE) && (ZSTDv06_HEAPMODE==1) - size_t regenSize; - ZSTDv06_DCtx* dctx = ZSTDv06_createDCtx(); - if (dctx==NULL) return ERROR(memory_allocation); - regenSize = ZSTDv06_decompressDCtx(dctx, dst, dstCapacity, src, srcSize); - ZSTDv06_freeDCtx(dctx); - return regenSize; -#else /* stack mode */ - ZSTDv06_DCtx dctx; - return ZSTDv06_decompressDCtx(&dctx, dst, dstCapacity, src, srcSize); -#endif -} - -/* ZSTD_errorFrameSizeInfoLegacy() : - assumes `cSize` and `dBound` are _not_ NULL */ -static void ZSTD_errorFrameSizeInfoLegacy(size_t* cSize, unsigned long long* dBound, size_t ret) -{ - *cSize = ret; - *dBound = ZSTD_CONTENTSIZE_ERROR; -} - -void ZSTDv06_findFrameSizeInfoLegacy(const void *src, size_t srcSize, size_t* cSize, unsigned long long* dBound) -{ - const BYTE* ip = (const BYTE*)src; - size_t remainingSize = srcSize; - size_t nbBlocks = 0; - blockProperties_t blockProperties = { bt_compressed, 0 }; - - /* Frame Header */ - { size_t const frameHeaderSize = ZSTDv06_frameHeaderSize(src, srcSize); - if (ZSTDv06_isError(frameHeaderSize)) { - ZSTD_errorFrameSizeInfoLegacy(cSize, dBound, frameHeaderSize); - return; - } - if (MEM_readLE32(src) != ZSTDv06_MAGICNUMBER) { - ZSTD_errorFrameSizeInfoLegacy(cSize, dBound, ERROR(prefix_unknown)); - return; - } - if (srcSize < frameHeaderSize+ZSTDv06_blockHeaderSize) { - ZSTD_errorFrameSizeInfoLegacy(cSize, dBound, ERROR(srcSize_wrong)); - return; - } - ip += frameHeaderSize; remainingSize -= frameHeaderSize; - } - - /* Loop on each block */ - while (1) { - size_t const cBlockSize = ZSTDv06_getcBlockSize(ip, remainingSize, &blockProperties); - if (ZSTDv06_isError(cBlockSize)) { - ZSTD_errorFrameSizeInfoLegacy(cSize, dBound, cBlockSize); - return; - } - - ip += ZSTDv06_blockHeaderSize; - remainingSize -= ZSTDv06_blockHeaderSize; - if (cBlockSize > remainingSize) { - ZSTD_errorFrameSizeInfoLegacy(cSize, dBound, ERROR(srcSize_wrong)); - return; - } - - if (cBlockSize == 0) break; /* bt_end */ - - ip += cBlockSize; - remainingSize -= cBlockSize; - nbBlocks++; - } - - *cSize = ip - (const BYTE*)src; - *dBound = nbBlocks * ZSTDv06_BLOCKSIZE_MAX; -} - -/*_****************************** -* Streaming Decompression API -********************************/ -size_t ZSTDv06_nextSrcSizeToDecompress(ZSTDv06_DCtx* dctx) -{ - return dctx->expected; -} - -size_t ZSTDv06_decompressContinue(ZSTDv06_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) -{ - /* Sanity check */ - if (srcSize != dctx->expected) return ERROR(srcSize_wrong); - if (dstCapacity) ZSTDv06_checkContinuity(dctx, dst); - - /* Decompress : frame header; part 1 */ - switch (dctx->stage) - { - case ZSTDds_getFrameHeaderSize : - if (srcSize != ZSTDv06_frameHeaderSize_min) return ERROR(srcSize_wrong); /* impossible */ - dctx->headerSize = ZSTDv06_frameHeaderSize(src, ZSTDv06_frameHeaderSize_min); - if (ZSTDv06_isError(dctx->headerSize)) return dctx->headerSize; - memcpy(dctx->headerBuffer, src, ZSTDv06_frameHeaderSize_min); - if (dctx->headerSize > ZSTDv06_frameHeaderSize_min) { - dctx->expected = dctx->headerSize - ZSTDv06_frameHeaderSize_min; - dctx->stage = ZSTDds_decodeFrameHeader; - return 0; - } - dctx->expected = 0; /* not necessary to copy more */ - /* fall-through */ - case ZSTDds_decodeFrameHeader: - { size_t result; - memcpy(dctx->headerBuffer + ZSTDv06_frameHeaderSize_min, src, dctx->expected); - result = ZSTDv06_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize); - if (ZSTDv06_isError(result)) return result; - dctx->expected = ZSTDv06_blockHeaderSize; - dctx->stage = ZSTDds_decodeBlockHeader; - return 0; - } - case ZSTDds_decodeBlockHeader: - { blockProperties_t bp; - size_t const cBlockSize = ZSTDv06_getcBlockSize(src, ZSTDv06_blockHeaderSize, &bp); - if (ZSTDv06_isError(cBlockSize)) return cBlockSize; - if (bp.blockType == bt_end) { - dctx->expected = 0; - dctx->stage = ZSTDds_getFrameHeaderSize; - } else { - dctx->expected = cBlockSize; - dctx->bType = bp.blockType; - dctx->stage = ZSTDds_decompressBlock; - } - return 0; - } - case ZSTDds_decompressBlock: - { size_t rSize; - switch(dctx->bType) - { - case bt_compressed: - rSize = ZSTDv06_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize); - break; - case bt_raw : - rSize = ZSTDv06_copyRawBlock(dst, dstCapacity, src, srcSize); - break; - case bt_rle : - return ERROR(GENERIC); /* not yet handled */ - break; - case bt_end : /* should never happen (filtered at phase 1) */ - rSize = 0; - break; - default: - return ERROR(GENERIC); /* impossible */ - } - dctx->stage = ZSTDds_decodeBlockHeader; - dctx->expected = ZSTDv06_blockHeaderSize; - if (ZSTDv06_isError(rSize)) return rSize; - dctx->previousDstEnd = (char*)dst + rSize; - return rSize; - } - default: - return ERROR(GENERIC); /* impossible */ - } -} - - -static void ZSTDv06_refDictContent(ZSTDv06_DCtx* dctx, const void* dict, size_t dictSize) -{ - dctx->dictEnd = dctx->previousDstEnd; - dctx->vBase = (const char*)dict - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->base)); - dctx->base = dict; - dctx->previousDstEnd = (const char*)dict + dictSize; -} - -static size_t ZSTDv06_loadEntropy(ZSTDv06_DCtx* dctx, const void* dict, size_t dictSize) -{ - size_t hSize, offcodeHeaderSize, matchlengthHeaderSize, litlengthHeaderSize; - - hSize = HUFv06_readDTableX4(dctx->hufTableX4, dict, dictSize); - if (HUFv06_isError(hSize)) return ERROR(dictionary_corrupted); - dict = (const char*)dict + hSize; - dictSize -= hSize; - - { short offcodeNCount[MaxOff+1]; - U32 offcodeMaxValue=MaxOff, offcodeLog; - offcodeHeaderSize = FSEv06_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dict, dictSize); - if (FSEv06_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted); - if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted); - { size_t const errorCode = FSEv06_buildDTable(dctx->OffTable, offcodeNCount, offcodeMaxValue, offcodeLog); - if (FSEv06_isError(errorCode)) return ERROR(dictionary_corrupted); } - dict = (const char*)dict + offcodeHeaderSize; - dictSize -= offcodeHeaderSize; - } - - { short matchlengthNCount[MaxML+1]; - unsigned matchlengthMaxValue = MaxML, matchlengthLog; - matchlengthHeaderSize = FSEv06_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dict, dictSize); - if (FSEv06_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted); - if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted); - { size_t const errorCode = FSEv06_buildDTable(dctx->MLTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog); - if (FSEv06_isError(errorCode)) return ERROR(dictionary_corrupted); } - dict = (const char*)dict + matchlengthHeaderSize; - dictSize -= matchlengthHeaderSize; - } - - { short litlengthNCount[MaxLL+1]; - unsigned litlengthMaxValue = MaxLL, litlengthLog; - litlengthHeaderSize = FSEv06_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dict, dictSize); - if (FSEv06_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted); - if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted); - { size_t const errorCode = FSEv06_buildDTable(dctx->LLTable, litlengthNCount, litlengthMaxValue, litlengthLog); - if (FSEv06_isError(errorCode)) return ERROR(dictionary_corrupted); } - } - - dctx->flagRepeatTable = 1; - return hSize + offcodeHeaderSize + matchlengthHeaderSize + litlengthHeaderSize; -} - -static size_t ZSTDv06_decompress_insertDictionary(ZSTDv06_DCtx* dctx, const void* dict, size_t dictSize) -{ - size_t eSize; - U32 const magic = MEM_readLE32(dict); - if (magic != ZSTDv06_DICT_MAGIC) { - /* pure content mode */ - ZSTDv06_refDictContent(dctx, dict, dictSize); - return 0; - } - /* load entropy tables */ - dict = (const char*)dict + 4; - dictSize -= 4; - eSize = ZSTDv06_loadEntropy(dctx, dict, dictSize); - if (ZSTDv06_isError(eSize)) return ERROR(dictionary_corrupted); - - /* reference dictionary content */ - dict = (const char*)dict + eSize; - dictSize -= eSize; - ZSTDv06_refDictContent(dctx, dict, dictSize); - - return 0; -} - - -size_t ZSTDv06_decompressBegin_usingDict(ZSTDv06_DCtx* dctx, const void* dict, size_t dictSize) -{ - { size_t const errorCode = ZSTDv06_decompressBegin(dctx); - if (ZSTDv06_isError(errorCode)) return errorCode; } - - if (dict && dictSize) { - size_t const errorCode = ZSTDv06_decompress_insertDictionary(dctx, dict, dictSize); - if (ZSTDv06_isError(errorCode)) return ERROR(dictionary_corrupted); - } - - return 0; -} - -/* - Buffered version of Zstd compression library - Copyright (C) 2015-2016, Yann Collet. - - BSD 2-Clause License (https://opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - zstd homepage : https://facebook.github.io/zstd/ -*/ - - -/*-*************************************************************************** -* Streaming decompression howto -* -* A ZBUFFv06_DCtx object is required to track streaming operations. -* Use ZBUFFv06_createDCtx() and ZBUFFv06_freeDCtx() to create/release resources. -* Use ZBUFFv06_decompressInit() to start a new decompression operation, -* or ZBUFFv06_decompressInitDictionary() if decompression requires a dictionary. -* Note that ZBUFFv06_DCtx objects can be re-init multiple times. -* -* Use ZBUFFv06_decompressContinue() repetitively to consume your input. -* *srcSizePtr and *dstCapacityPtr can be any size. -* The function will report how many bytes were read or written by modifying *srcSizePtr and *dstCapacityPtr. -* Note that it may not consume the entire input, in which case it's up to the caller to present remaining input again. -* The content of @dst will be overwritten (up to *dstCapacityPtr) at each function call, so save its content if it matters, or change @dst. -* @return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to help latency), -* or 0 when a frame is completely decoded, -* or an error code, which can be tested using ZBUFFv06_isError(). -* -* Hint : recommended buffer sizes (not compulsory) : ZBUFFv06_recommendedDInSize() and ZBUFFv06_recommendedDOutSize() -* output : ZBUFFv06_recommendedDOutSize==128 KB block size is the internal unit, it ensures it's always possible to write a full block when decoded. -* input : ZBUFFv06_recommendedDInSize == 128KB + 3; -* just follow indications from ZBUFFv06_decompressContinue() to minimize latency. It should always be <= 128 KB + 3 . -* *******************************************************************************/ - -typedef enum { ZBUFFds_init, ZBUFFds_loadHeader, - ZBUFFds_read, ZBUFFds_load, ZBUFFds_flush } ZBUFFv06_dStage; - -/* *** Resource management *** */ -struct ZBUFFv06_DCtx_s { - ZSTDv06_DCtx* zd; - ZSTDv06_frameParams fParams; - ZBUFFv06_dStage stage; - char* inBuff; - size_t inBuffSize; - size_t inPos; - char* outBuff; - size_t outBuffSize; - size_t outStart; - size_t outEnd; - size_t blockSize; - BYTE headerBuffer[ZSTDv06_FRAMEHEADERSIZE_MAX]; - size_t lhSize; -}; /* typedef'd to ZBUFFv06_DCtx within "zstd_buffered.h" */ - - -ZBUFFv06_DCtx* ZBUFFv06_createDCtx(void) -{ - ZBUFFv06_DCtx* zbd = (ZBUFFv06_DCtx*)malloc(sizeof(ZBUFFv06_DCtx)); - if (zbd==NULL) return NULL; - memset(zbd, 0, sizeof(*zbd)); - zbd->zd = ZSTDv06_createDCtx(); - if (zbd->zd==NULL) { - ZBUFFv06_freeDCtx(zbd); /* avoid leaking the context */ - return NULL; - } - zbd->stage = ZBUFFds_init; - return zbd; -} - -size_t ZBUFFv06_freeDCtx(ZBUFFv06_DCtx* zbd) -{ - if (zbd==NULL) return 0; /* support free on null */ - ZSTDv06_freeDCtx(zbd->zd); - free(zbd->inBuff); - free(zbd->outBuff); - free(zbd); - return 0; -} - - -/* *** Initialization *** */ - -size_t ZBUFFv06_decompressInitDictionary(ZBUFFv06_DCtx* zbd, const void* dict, size_t dictSize) -{ - zbd->stage = ZBUFFds_loadHeader; - zbd->lhSize = zbd->inPos = zbd->outStart = zbd->outEnd = 0; - return ZSTDv06_decompressBegin_usingDict(zbd->zd, dict, dictSize); -} - -size_t ZBUFFv06_decompressInit(ZBUFFv06_DCtx* zbd) -{ - return ZBUFFv06_decompressInitDictionary(zbd, NULL, 0); -} - - - -MEM_STATIC size_t ZBUFFv06_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize) -{ - size_t length = MIN(dstCapacity, srcSize); - if (length > 0) { - memcpy(dst, src, length); - } - return length; -} - - -/* *** Decompression *** */ - -size_t ZBUFFv06_decompressContinue(ZBUFFv06_DCtx* zbd, - void* dst, size_t* dstCapacityPtr, - const void* src, size_t* srcSizePtr) -{ - const char* const istart = (const char*)src; - const char* const iend = istart + *srcSizePtr; - const char* ip = istart; - char* const ostart = (char*)dst; - char* const oend = ostart + *dstCapacityPtr; - char* op = ostart; - U32 notDone = 1; - - while (notDone) { - switch(zbd->stage) - { - case ZBUFFds_init : - return ERROR(init_missing); - - case ZBUFFds_loadHeader : - { size_t const hSize = ZSTDv06_getFrameParams(&(zbd->fParams), zbd->headerBuffer, zbd->lhSize); - if (hSize != 0) { - size_t const toLoad = hSize - zbd->lhSize; /* if hSize!=0, hSize > zbd->lhSize */ - if (ZSTDv06_isError(hSize)) return hSize; - if (toLoad > (size_t)(iend-ip)) { /* not enough input to load full header */ - if (ip != NULL) - memcpy(zbd->headerBuffer + zbd->lhSize, ip, iend-ip); - zbd->lhSize += iend-ip; - *dstCapacityPtr = 0; - return (hSize - zbd->lhSize) + ZSTDv06_blockHeaderSize; /* remaining header bytes + next block header */ - } - memcpy(zbd->headerBuffer + zbd->lhSize, ip, toLoad); zbd->lhSize = hSize; ip += toLoad; - break; - } } - - /* Consume header */ - { size_t const h1Size = ZSTDv06_nextSrcSizeToDecompress(zbd->zd); /* == ZSTDv06_frameHeaderSize_min */ - size_t const h1Result = ZSTDv06_decompressContinue(zbd->zd, NULL, 0, zbd->headerBuffer, h1Size); - if (ZSTDv06_isError(h1Result)) return h1Result; - if (h1Size < zbd->lhSize) { /* long header */ - size_t const h2Size = ZSTDv06_nextSrcSizeToDecompress(zbd->zd); - size_t const h2Result = ZSTDv06_decompressContinue(zbd->zd, NULL, 0, zbd->headerBuffer+h1Size, h2Size); - if (ZSTDv06_isError(h2Result)) return h2Result; - } } - - /* Frame header instruct buffer sizes */ - { size_t const blockSize = MIN(1 << zbd->fParams.windowLog, ZSTDv06_BLOCKSIZE_MAX); - zbd->blockSize = blockSize; - if (zbd->inBuffSize < blockSize) { - free(zbd->inBuff); - zbd->inBuffSize = blockSize; - zbd->inBuff = (char*)malloc(blockSize); - if (zbd->inBuff == NULL) return ERROR(memory_allocation); - } - { size_t const neededOutSize = ((size_t)1 << zbd->fParams.windowLog) + blockSize + WILDCOPY_OVERLENGTH * 2; - if (zbd->outBuffSize < neededOutSize) { - free(zbd->outBuff); - zbd->outBuffSize = neededOutSize; - zbd->outBuff = (char*)malloc(neededOutSize); - if (zbd->outBuff == NULL) return ERROR(memory_allocation); - } } } - zbd->stage = ZBUFFds_read; - /* fall-through */ - case ZBUFFds_read: - { size_t const neededInSize = ZSTDv06_nextSrcSizeToDecompress(zbd->zd); - if (neededInSize==0) { /* end of frame */ - zbd->stage = ZBUFFds_init; - notDone = 0; - break; - } - if ((size_t)(iend-ip) >= neededInSize) { /* decode directly from src */ - size_t const decodedSize = ZSTDv06_decompressContinue(zbd->zd, - zbd->outBuff + zbd->outStart, zbd->outBuffSize - zbd->outStart, - ip, neededInSize); - if (ZSTDv06_isError(decodedSize)) return decodedSize; - ip += neededInSize; - if (!decodedSize) break; /* this was just a header */ - zbd->outEnd = zbd->outStart + decodedSize; - zbd->stage = ZBUFFds_flush; - break; - } - if (ip==iend) { notDone = 0; break; } /* no more input */ - zbd->stage = ZBUFFds_load; - } - /* fall-through */ - case ZBUFFds_load: - { size_t const neededInSize = ZSTDv06_nextSrcSizeToDecompress(zbd->zd); - size_t const toLoad = neededInSize - zbd->inPos; /* should always be <= remaining space within inBuff */ - size_t loadedSize; - if (toLoad > zbd->inBuffSize - zbd->inPos) return ERROR(corruption_detected); /* should never happen */ - loadedSize = ZBUFFv06_limitCopy(zbd->inBuff + zbd->inPos, toLoad, ip, iend-ip); - ip += loadedSize; - zbd->inPos += loadedSize; - if (loadedSize < toLoad) { notDone = 0; break; } /* not enough input, wait for more */ - - /* decode loaded input */ - { size_t const decodedSize = ZSTDv06_decompressContinue(zbd->zd, - zbd->outBuff + zbd->outStart, zbd->outBuffSize - zbd->outStart, - zbd->inBuff, neededInSize); - if (ZSTDv06_isError(decodedSize)) return decodedSize; - zbd->inPos = 0; /* input is consumed */ - if (!decodedSize) { zbd->stage = ZBUFFds_read; break; } /* this was just a header */ - zbd->outEnd = zbd->outStart + decodedSize; - zbd->stage = ZBUFFds_flush; - /* break; */ /* ZBUFFds_flush follows */ - } - } - /* fall-through */ - case ZBUFFds_flush: - { size_t const toFlushSize = zbd->outEnd - zbd->outStart; - size_t const flushedSize = ZBUFFv06_limitCopy(op, oend-op, zbd->outBuff + zbd->outStart, toFlushSize); - op += flushedSize; - zbd->outStart += flushedSize; - if (flushedSize == toFlushSize) { - zbd->stage = ZBUFFds_read; - if (zbd->outStart + zbd->blockSize > zbd->outBuffSize) - zbd->outStart = zbd->outEnd = 0; - break; - } - /* cannot flush everything */ - notDone = 0; - break; - } - default: return ERROR(GENERIC); /* impossible */ - } } - - /* result */ - *srcSizePtr = ip-istart; - *dstCapacityPtr = op-ostart; - { size_t nextSrcSizeHint = ZSTDv06_nextSrcSizeToDecompress(zbd->zd); - if (nextSrcSizeHint > ZSTDv06_blockHeaderSize) nextSrcSizeHint+= ZSTDv06_blockHeaderSize; /* get following block header too */ - nextSrcSizeHint -= zbd->inPos; /* already loaded*/ - return nextSrcSizeHint; - } -} - - - -/* ************************************* -* Tool functions -***************************************/ -size_t ZBUFFv06_recommendedDInSize(void) { return ZSTDv06_BLOCKSIZE_MAX + ZSTDv06_blockHeaderSize /* block header size*/ ; } -size_t ZBUFFv06_recommendedDOutSize(void) { return ZSTDv06_BLOCKSIZE_MAX; } +/* Implementation moved to Rust (rust/src/legacy/zstd_v06.rs). + * The frozen v0.6 decoder, including its embedded FSE/Huff0 snapshot, frame + * state, and buffered streaming context, now lives entirely in Rust; this + * translation unit remains a declaration-only ABI shim. */ diff --git a/rust/src/legacy/mod.rs b/rust/src/legacy/mod.rs index a80fdfeeb..3fde6e531 100644 --- a/rust/src/legacy/mod.rs +++ b/rust/src/legacy/mod.rs @@ -47,3 +47,9 @@ pub mod zstd_v03; #[cfg(feature = "legacy-v04")] pub mod zstd_v04; + +#[cfg(feature = "legacy-v05")] +pub mod zstd_v05; + +#[cfg(feature = "legacy-v06")] +pub mod zstd_v06; diff --git a/rust/src/legacy/zstd_v05.rs b/rust/src/legacy/zstd_v05.rs new file mode 100644 index 000000000..50c61be50 --- /dev/null +++ b/rust/src/legacy/zstd_v05.rs @@ -0,0 +1,3675 @@ +#![allow(non_snake_case)] + +//! Frozen decoder for the zstd v0.5 format. +//! +//! `lib/legacy/zstd_v05.c` is an old, self-contained decoder. This module +//! keeps that boundary: it owns its FSE, bit-stream, and Huffman state rather +//! than depending on the current entropy implementations. The public entry +//! points below retain the C ABI and the context is deliberately malloc/free +//! allocated so C callers can continue to own an opaque `ZSTDv05_Dctx`. + +use crate::errors::{ERR_getErrorName, ERR_isError, ZstdErrorCode, ERROR}; +use std::os::raw::{c_char, c_uint, c_void}; +use std::ptr; +use std::slice; + +const ZSTD_MAGIC_NUMBER: u32 = 0xFD2F_B525; +const ZSTD_CONTENTSIZE_ERROR: u64 = u64::MAX - 1; + +const BLOCKSIZE: usize = 128 * 1024; +const MIN_SEQUENCES_SIZE: usize = 1; +const MIN_CBLOCK_SIZE: usize = 1 + 1 + MIN_SEQUENCES_SIZE; +const MINMATCH: usize = 4; +const IS_HUF: u8 = 0; +const IS_PCH: u8 = 1; +const IS_RAW: u8 = 2; +const IS_RLE: u8 = 3; + +const ML_BITS: u32 = 7; +const LL_BITS: u32 = 6; +const OFF_BITS: u32 = 5; +const MAX_ML: u32 = (1 << ML_BITS) - 1; +const MAX_LL: u32 = (1 << LL_BITS) - 1; +const MAX_OFF: u32 = 31; +const REPCODE_STARTVALUE: usize = 1; +const ML_FSE_LOG: u32 = 10; +const LL_FSE_LOG: u32 = 10; +const OFF_FSE_LOG: u32 = 9; + +const FSE_MAX_MEMORY_USAGE: u32 = 14; +const FSE_MAX_SYMBOL_VALUE: u32 = 255; +const FSE_MAX_TABLELOG: u32 = FSE_MAX_MEMORY_USAGE - 2; +const FSE_MIN_TABLELOG: u32 = 5; +const FSE_TABLELOG_ABSOLUTE_MAX: u32 = 15; + +const HUF_MAX_SYMBOL_VALUE: usize = 255; +const HUF_MAX_TABLELOG: usize = 12; +const HUF_ABSOLUTE_MAX_TABLELOG: usize = 16; + +const ZSTD_DICT_MAGIC: u32 = 0xEC30_A435; + +const BT_COMPRESSED: u32 = 0; +const BT_RAW: u32 = 1; +const BT_RLE: u32 = 2; +const BT_END: u32 = 3; + +const FSE_ENCODING_RAW: u32 = 0; +const FSE_ENCODING_RLE: u32 = 1; +const FSE_ENCODING_STATIC: u32 = 2; +const FSE_ENCODING_DYNAMIC: u32 = 3; + +const DSTREAM_UNFINISHED: u32 = 0; +const DSTREAM_END_OF_BUFFER: u32 = 1; +const DSTREAM_COMPLETED: u32 = 2; +const DSTREAM_TOO_FAR: u32 = 3; + +const USIZE_BITS: u32 = usize::BITS; + +#[repr(C)] +#[derive(Clone, Copy)] +struct FseDecode { + new_state: u16, + symbol: u8, + nb_bits: u8, +} + +#[repr(C)] +struct FseDTableHeader { + table_log: u16, + fast_mode: u16, +} + +#[derive(Clone, Copy)] +struct DStream { + bit_container: usize, + bits_consumed: u32, + ptr: *const u8, + start: *const u8, +} + +#[derive(Clone, Copy)] +struct FseDState { + state: usize, + table: *const FseDecode, +} + +#[inline] +fn highbit32(value: u32) -> u32 { + value.leading_zeros() ^ 31 +} + +#[inline] +unsafe fn write_le16(dst: *mut u8, value: u16) { + let bytes = value.to_le_bytes(); + ptr::copy_nonoverlapping(bytes.as_ptr(), dst, 2); +} + +#[inline] +unsafe fn zstd_copy8(dst: *mut u8, src: *const u8) { + ptr::copy(src, dst, 8); +} + +#[inline] +unsafe fn zstd_copy4(dst: *mut u8, src: *const u8) { + ptr::copy(src, dst, 4); +} + +unsafe fn zstd_wildcopy(dst: *mut u8, src: *const u8, length: isize) { + let mut op = dst; + let mut ip = src; + let end = if length >= 0 { + (dst as usize).wrapping_add(length as usize) + } else { + (dst as usize).wrapping_sub(length.wrapping_neg() as usize) + }; + loop { + zstd_copy8(op, ip); + op = op.add(8); + ip = ip.add(8); + if (op as usize) >= end { + break; + } + } +} + +#[inline] +unsafe fn read_le16(ptr: *const u8) -> u16 { + u16::from_le_bytes(std::ptr::read_unaligned(ptr as *const [u8; 2])) +} + +#[inline] +unsafe fn read_le32(ptr: *const u8) -> u32 { + u32::from_le_bytes(std::ptr::read_unaligned(ptr as *const [u8; 4])) +} + +#[inline] +unsafe fn read_le_size(ptr: *const u8) -> usize { + if std::mem::size_of::() == 4 { + read_le32(ptr) as usize + } else { + u64::from_le_bytes(std::ptr::read_unaligned(ptr as *const [u8; 8])) as usize + } +} + +/* ****************************************** + * Backward bit stream (the v0.5 snapshot) + ********************************************/ + +unsafe fn init_dstream(stream: &mut DStream, src: *const u8, src_size: usize) -> usize { + let word = std::mem::size_of::(); + if src_size == 0 { + *stream = DStream { + bit_container: 0, + bits_consumed: 0, + ptr: ptr::null(), + start: ptr::null(), + }; + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + + stream.start = src; + if src_size >= word { + stream.ptr = src.add(src_size - word); + stream.bit_container = read_le_size(stream.ptr); + let end_byte = *src.add(src_size - 1) as u32; + if end_byte == 0 { + return ERROR(ZstdErrorCode::Generic); + } + stream.bits_consumed = 8 - highbit32(end_byte); + } else { + stream.ptr = src; + stream.bit_container = *src as usize; + if src_size >= 7 { + stream.bit_container += (*src.add(6) as usize) << (USIZE_BITS as usize - 16); + } + if src_size >= 6 { + stream.bit_container += (*src.add(5) as usize) << (USIZE_BITS as usize - 24); + } + if src_size >= 5 { + stream.bit_container += (*src.add(4) as usize) << (USIZE_BITS as usize - 32); + } + if src_size >= 4 { + stream.bit_container += (*src.add(3) as usize) << 24; + } + if src_size >= 3 { + stream.bit_container += (*src.add(2) as usize) << 16; + } + if src_size >= 2 { + stream.bit_container += (*src.add(1) as usize) << 8; + } + let end_byte = *src.add(src_size - 1) as u32; + if end_byte == 0 { + return ERROR(ZstdErrorCode::Generic); + } + stream.bits_consumed = 8 - highbit32(end_byte); + stream.bits_consumed += ((word - src_size) * 8) as u32; + } + src_size +} + +#[inline] +unsafe fn look_bits(stream: &DStream, nb_bits: u32) -> usize { + let mask = USIZE_BITS - 1; + ((stream.bit_container << (stream.bits_consumed & mask)) >> 1) + >> (mask.wrapping_sub(nb_bits) & mask) +} + +#[inline] +unsafe fn look_bits_fast(stream: &DStream, nb_bits: u32) -> usize { + let mask = USIZE_BITS - 1; + (stream.bit_container << (stream.bits_consumed & mask)) + >> ((mask + 1).wrapping_sub(nb_bits) & mask) +} + +#[inline] +fn skip_bits(stream: &mut DStream, nb_bits: u32) { + stream.bits_consumed = stream.bits_consumed.wrapping_add(nb_bits); +} + +#[inline] +unsafe fn read_bits(stream: &mut DStream, nb_bits: u32) -> usize { + let value = look_bits(stream, nb_bits); + skip_bits(stream, nb_bits); + value +} + +#[inline] +unsafe fn read_bits_fast(stream: &mut DStream, nb_bits: u32) -> usize { + let value = look_bits_fast(stream, nb_bits); + skip_bits(stream, nb_bits); + value +} + +unsafe fn reload_dstream(stream: &mut DStream) -> u32 { + let word = std::mem::size_of::(); + if stream.bits_consumed > (word * 8) as u32 { + return DSTREAM_TOO_FAR; + } + if (stream.ptr as usize) >= (stream.start as usize).wrapping_add(word) { + stream.ptr = stream.ptr.sub((stream.bits_consumed >> 3) as usize); + stream.bits_consumed &= 7; + stream.bit_container = read_le_size(stream.ptr); + return DSTREAM_UNFINISHED; + } + if stream.ptr == stream.start { + if stream.bits_consumed < (word * 8) as u32 { + return DSTREAM_END_OF_BUFFER; + } + return DSTREAM_COMPLETED; + } + + let mut nb_bytes = stream.bits_consumed >> 3; + let mut result = DSTREAM_UNFINISHED; + if (stream.ptr as usize).wrapping_sub(nb_bytes as usize) < stream.start as usize { + nb_bytes = (stream.ptr as usize - stream.start as usize) as u32; + result = DSTREAM_END_OF_BUFFER; + } + stream.ptr = stream.ptr.sub(nb_bytes as usize); + stream.bits_consumed -= nb_bytes * 8; + stream.bit_container = read_le_size(stream.ptr); + result +} + +#[inline] +fn end_of_dstream(stream: &DStream) -> bool { + stream.ptr == stream.start && stream.bits_consumed == USIZE_BITS +} + +/* ****************************************** + * FSE decoding + ********************************************/ + +#[inline] +fn fse_table_step(table_size: u32) -> u32 { + (table_size >> 1) + (table_size >> 3) + 3 +} + +#[allow(clippy::needless_range_loop)] +unsafe fn fse_build_dtable( + dt: &mut [u32], + normalized_counter: &[i16; 256], + max_symbol_value: u32, + table_log: u32, +) -> usize { + if max_symbol_value > FSE_MAX_SYMBOL_VALUE { + return ERROR(ZstdErrorCode::MaxSymbolValueTooLarge); + } + if table_log > FSE_MAX_TABLELOG { + return ERROR(ZstdErrorCode::TableLogTooLarge); + } + + let table_size = 1u32 << table_log; + let table_mask = table_size - 1; + let step = fse_table_step(table_size); + let mut symbol_next = [0u16; 256]; + let table_header = dt.as_mut_ptr() as *mut FseDTableHeader; + let table_decode = dt.as_mut_ptr().add(1) as *mut FseDecode; + let mut position = 0u32; + let mut high_threshold = table_size - 1; + let large_limit = (1i32 << (table_log - 1)) as i16; + let mut no_large = 1u16; + + (*table_header).table_log = table_log as u16; + for symbol in 0..=max_symbol_value as usize { + let count = normalized_counter[symbol]; + if count == -1 { + (*table_decode.add(high_threshold as usize)).symbol = symbol as u8; + high_threshold = high_threshold.wrapping_sub(1); + symbol_next[symbol] = 1; + } else { + if count >= large_limit { + no_large = 0; + } + symbol_next[symbol] = count as u16; + } + } + + for symbol in 0..=max_symbol_value as usize { + let count = normalized_counter[symbol]; + for _ in 0..count.max(0) { + (*table_decode.add(position as usize)).symbol = symbol as u8; + position = (position + step) & table_mask; + while position > high_threshold { + position = (position + step) & table_mask; + } + } + } + if position != 0 { + return ERROR(ZstdErrorCode::Generic); + } + + for index in 0..table_size as usize { + let symbol = (*table_decode.add(index)).symbol as usize; + let next_state = symbol_next[symbol]; + symbol_next[symbol] = symbol_next[symbol].wrapping_add(1); + let nb_bits = (table_log - highbit32(next_state as u32)) as u8; + (*table_decode.add(index)).nb_bits = nb_bits; + (*table_decode.add(index)).new_state = + (((next_state as u32) << nb_bits).wrapping_sub(table_size)) as u16; + } + (*table_header).fast_mode = no_large; + 0 +} + +unsafe fn fse_read_ncount( + normalized_counter: &mut [i16; 256], + max_sv: &mut u32, + table_log: &mut u32, + header: *const u8, + header_size: usize, +) -> usize { + if header_size < 4 { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + let start = header as usize; + let end = start.wrapping_add(header_size); + let mut ip = header; + let mut char_num = 0u32; + let mut previous_zero = false; + let mut bit_stream = read_le32(ip); + let mut nb_bits = ((bit_stream & 0xF) + FSE_MIN_TABLELOG) as i32; + if nb_bits > FSE_TABLELOG_ABSOLUTE_MAX as i32 { + return ERROR(ZstdErrorCode::TableLogTooLarge); + } + bit_stream >>= 4; + let mut bit_count = 4i32; + *table_log = nb_bits as u32; + let mut remaining = (1i32 << nb_bits) + 1; + let mut threshold = 1i32 << nb_bits; + nb_bits += 1; + + while remaining > 1 && char_num <= *max_sv { + if previous_zero { + let mut n0 = char_num; + while bit_stream & 0xFFFF == 0xFFFF { + n0 += 24; + if (ip as usize) < end.wrapping_sub(5) { + ip = ip.add(2); + bit_stream = read_le32(ip) >> bit_count; + } else { + bit_stream >>= 16; + bit_count += 16; + } + } + while bit_stream & 3 == 3 { + n0 += 3; + bit_stream >>= 2; + bit_count += 2; + } + n0 += bit_stream & 3; + bit_count += 2; + if n0 > *max_sv { + return ERROR(ZstdErrorCode::MaxSymbolValueTooSmall); + } + while char_num < n0 { + normalized_counter[char_num as usize] = 0; + char_num += 1; + } + if (ip as usize) <= end.wrapping_sub(7) + || (ip as usize).wrapping_add((bit_count >> 3) as usize) <= end.wrapping_sub(4) + { + ip = ip.add((bit_count >> 3) as usize); + bit_count &= 7; + bit_stream = read_le32(ip) >> bit_count; + } else { + bit_stream >>= 2; + } + } + + let max = ((2 * threshold - 1) - remaining) as i16; + let mut count: i16; + if (bit_stream & (threshold - 1) as u32) < max as i32 as u32 { + count = (bit_stream & (threshold - 1) as u32) as u16 as i16; + bit_count += nb_bits - 1; + } else { + count = (bit_stream & (2 * threshold - 1) as u32) as u16 as i16; + if count as i32 >= threshold { + count = (count as i32 - max as i32) as i16; + } + bit_count += nb_bits; + } + count = count.wrapping_sub(1); + remaining -= (count as i32).abs(); + normalized_counter[char_num as usize] = count; + char_num += 1; + previous_zero = count == 0; + while remaining < threshold { + nb_bits -= 1; + threshold >>= 1; + } + + if (ip as usize) <= end.wrapping_sub(7) + || (ip as usize).wrapping_add((bit_count >> 3) as usize) <= end.wrapping_sub(4) + { + ip = ip.add((bit_count >> 3) as usize); + bit_count &= 7; + } else { + bit_count -= (8 * (end.wrapping_sub(4) as isize - ip as usize as isize)) as i32; + ip = (end - 4) as *const u8; + } + bit_stream = read_le32(ip) >> (bit_count & 31); + } + + if remaining != 1 { + return ERROR(ZstdErrorCode::Generic); + } + *max_sv = char_num - 1; + ip = ip.add(((bit_count + 7) >> 3) as usize); + if (ip as usize).wrapping_sub(start) > header_size { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + (ip as usize).wrapping_sub(start) +} + +unsafe fn fse_build_dtable_rle(dt: &mut [u32], symbol: u8) -> usize { + let header = dt.as_mut_ptr() as *mut FseDTableHeader; + let cell = dt.as_mut_ptr().add(1) as *mut FseDecode; + (*header).table_log = 0; + (*header).fast_mode = 0; + (*cell).new_state = 0; + (*cell).symbol = symbol; + (*cell).nb_bits = 0; + 0 +} + +unsafe fn fse_build_dtable_raw(dt: &mut [u32], nb_bits: u32) -> usize { + if nb_bits < 1 { + return ERROR(ZstdErrorCode::Generic); + } + let header = dt.as_mut_ptr() as *mut FseDTableHeader; + let cells = dt.as_mut_ptr().add(1) as *mut FseDecode; + let table_size = 1u32 << nb_bits; + (*header).table_log = nb_bits as u16; + (*header).fast_mode = 1; + for symbol in 0..table_size { + let cell = cells.add(symbol as usize); + (*cell).new_state = 0; + (*cell).symbol = symbol as u8; + (*cell).nb_bits = nb_bits as u8; + } + 0 +} + +unsafe fn fse_init_dstate(state: &mut FseDState, stream: &mut DStream, dt: *const u32) { + let header = dt as *const FseDTableHeader; + state.state = read_bits(stream, (*header).table_log as u32); + reload_dstream(stream); + state.table = dt.add(1) as *const FseDecode; +} + +#[inline] +unsafe fn fse_decode_symbol(state: &mut FseDState, stream: &mut DStream, fast: bool) -> u8 { + let info = *state.table.add(state.state); + let low_bits = if fast { + read_bits_fast(stream, info.nb_bits as u32) + } else { + read_bits(stream, info.nb_bits as u32) + }; + state.state = (info.new_state as usize).wrapping_add(low_bits); + info.symbol +} + +#[inline] +unsafe fn fse_peak_symbol(state: &FseDState) -> u8 { + (*state.table.add(state.state)).symbol +} + +unsafe fn fse_decompress_using_dtable( + dst: *mut u8, + max_dst_size: usize, + c_src: *const u8, + c_src_size: usize, + dt: &[u32], +) -> usize { + let header = &*(dt.as_ptr() as *const FseDTableHeader); + let fast = header.fast_mode != 0; + let start = dst; + let end_addr = (dst as usize).wrapping_add(max_dst_size); + let limit_addr = end_addr.wrapping_sub(3); + let mut op = dst; + let mut stream = DStream { + bit_container: 0, + bits_consumed: 0, + ptr: ptr::null(), + start: ptr::null(), + }; + let mut state1 = FseDState { + state: 0, + table: ptr::null(), + }; + let mut state2 = state1; + let error = init_dstream(&mut stream, c_src, c_src_size); + if ERR_isError(error) { + return error; + } + fse_init_dstate(&mut state1, &mut stream, dt.as_ptr()); + fse_init_dstate(&mut state2, &mut stream, dt.as_ptr()); + + const RELOAD_2: bool = FSE_MAX_TABLELOG * 2 + 7 > USIZE_BITS; + const RELOAD_4: bool = FSE_MAX_TABLELOG * 4 + 7 > USIZE_BITS; + while reload_dstream(&mut stream) == DSTREAM_UNFINISHED && (op as usize) < limit_addr { + *op = fse_decode_symbol(&mut state1, &mut stream, fast); + if RELOAD_2 { + reload_dstream(&mut stream); + } + *op.add(1) = fse_decode_symbol(&mut state2, &mut stream, fast); + if RELOAD_4 && reload_dstream(&mut stream) > DSTREAM_UNFINISHED { + op = op.add(2); + break; + } + *op.add(2) = fse_decode_symbol(&mut state1, &mut stream, fast); + if RELOAD_2 { + reload_dstream(&mut stream); + } + *op.add(3) = fse_decode_symbol(&mut state2, &mut stream, fast); + op = op.add(4); + } + + loop { + if reload_dstream(&mut stream) > DSTREAM_COMPLETED + || op as usize == end_addr + || (end_of_dstream(&stream) && (fast || state1.state == 0)) + { + break; + } + *op = fse_decode_symbol(&mut state1, &mut stream, fast); + op = op.add(1); + if reload_dstream(&mut stream) > DSTREAM_COMPLETED + || op as usize == end_addr + || (end_of_dstream(&stream) && (fast || state2.state == 0)) + { + break; + } + *op = fse_decode_symbol(&mut state2, &mut stream, fast); + op = op.add(1); + } + + if end_of_dstream(&stream) && state1.state == 0 && state2.state == 0 { + return (op as usize) - (start as usize); + } + if op as usize == end_addr { + return ERROR(ZstdErrorCode::DstSizeTooSmall); + } + ERROR(ZstdErrorCode::CorruptionDetected) +} + +unsafe fn fse_decompress( + dst: *mut u8, + max_dst_size: usize, + c_src: *const u8, + c_src_size: usize, +) -> usize { + if c_src_size < 2 { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + let mut counters = [0i16; 256]; + let mut max_symbol = FSE_MAX_SYMBOL_VALUE; + let mut table_log = 0; + let header_size = fse_read_ncount( + &mut counters, + &mut max_symbol, + &mut table_log, + c_src, + c_src_size, + ); + if ERR_isError(header_size) { + return header_size; + } + if header_size >= c_src_size { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + let mut table = vec![0u32; 1 + (1usize << FSE_MAX_TABLELOG)]; + let error = fse_build_dtable(&mut table, &counters, max_symbol, table_log); + if ERR_isError(error) { + return error; + } + fse_decompress_using_dtable( + dst, + max_dst_size, + c_src.add(header_size), + c_src_size - header_size, + &table, + ) +} + +/* ****************************************** + * Huffman decoding + ********************************************/ + +#[repr(C)] +#[derive(Clone, Copy)] +struct HufDEltX2 { + byte: u8, + nb_bits: u8, +} + +#[allow(clippy::manual_div_ceil)] +unsafe fn huf_read_stats( + huff_weight: &mut [u8; HUF_MAX_SYMBOL_VALUE + 1], + rank_stats: &mut [u32; HUF_ABSOLUTE_MAX_TABLELOG + 1], + nb_symbols: &mut u32, + table_log: &mut u32, + src: *const u8, + src_size: usize, +) -> usize { + if src_size == 0 { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + let mut i_size = *src as usize; + let o_size: usize; + if i_size >= 128 { + if i_size >= 242 { + const RLE_LENGTHS: [usize; 14] = [1, 2, 3, 4, 7, 8, 15, 16, 31, 32, 63, 64, 127, 128]; + let index = i_size - 242; + if index >= RLE_LENGTHS.len() { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + o_size = RLE_LENGTHS[index]; + huff_weight.fill(1); + i_size = 0; + } else { + o_size = i_size - 127; + i_size = (o_size + 1) / 2; + if i_size + 1 > src_size { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + if o_size >= huff_weight.len() { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + let weights = src.add(1); + let mut n = 0; + while n < o_size { + huff_weight[n] = *weights.add(n / 2) >> 4; + if n + 1 < huff_weight.len() { + huff_weight[n + 1] = *weights.add(n / 2) & 15; + } + n += 2; + } + } + } else { + if i_size + 1 > src_size { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + let decoded = fse_decompress( + huff_weight.as_mut_ptr(), + huff_weight.len() - 1, + src.add(1), + i_size, + ); + if ERR_isError(decoded) { + return decoded; + } + o_size = decoded; + } + + rank_stats.fill(0); + let mut weight_total = 0u32; + for &weight in huff_weight.iter().take(o_size) { + if weight as usize >= HUF_ABSOLUTE_MAX_TABLELOG { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + rank_stats[weight as usize] += 1; + weight_total += (1u32 << weight) >> 1; + } + if weight_total == 0 { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + let calculated_log = highbit32(weight_total) + 1; + if calculated_log as usize > HUF_ABSOLUTE_MAX_TABLELOG { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + let total = 1u32 << calculated_log; + let rest = total - weight_total; + if rest == 0 || (1u32 << highbit32(rest)) != rest { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + let last_weight = highbit32(rest) + 1; + huff_weight[o_size] = last_weight as u8; + rank_stats[last_weight as usize] += 1; + if rank_stats[1] < 2 || (rank_stats[1] & 1) != 0 { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + *nb_symbols = (o_size + 1) as u32; + *table_log = calculated_log; + i_size + 1 +} + +#[allow(clippy::needless_range_loop)] +unsafe fn huf_read_dtable_x2( + dtable: &mut [u16; 1 + (1 << HUF_MAX_TABLELOG)], + src: *const u8, + src_size: usize, +) -> usize { + let mut huff_weight = [0u8; HUF_MAX_SYMBOL_VALUE + 1]; + let mut rank_val = [0u32; HUF_ABSOLUTE_MAX_TABLELOG + 1]; + let mut nb_symbols = 0u32; + let mut table_log = 0u32; + let i_size = huf_read_stats( + &mut huff_weight, + &mut rank_val, + &mut nb_symbols, + &mut table_log, + src, + src_size, + ); + if ERR_isError(i_size) { + return i_size; + } + if table_log as usize > dtable[0] as usize { + return ERROR(ZstdErrorCode::TableLogTooLarge); + } + dtable[0] = table_log as u16; + + let mut next_rank_start = 0u32; + for weight in 1..=table_log as usize { + let current = next_rank_start; + next_rank_start += rank_val[weight] << (weight - 1); + rank_val[weight] = current; + } + let cells = dtable.as_mut_ptr().add(1) as *mut HufDEltX2; + for (symbol, &weight) in huff_weight.iter().enumerate().take(nb_symbols as usize) { + let weight = weight as usize; + let length = (1u32 << weight) >> 1; + let entry = HufDEltX2 { + byte: symbol as u8, + nb_bits: (table_log + 1 - weight as u32) as u8, + }; + for index in rank_val[weight]..rank_val[weight] + length { + *cells.add(index as usize) = entry; + } + rank_val[weight] += length; + } + i_size +} + +#[inline] +unsafe fn huf_decode_symbol(stream: &mut DStream, table: *const HufDEltX2, table_log: u32) -> u8 { + let entry = *table.add(look_bits_fast(stream, table_log)); + skip_bits(stream, entry.nb_bits as u32); + entry.byte +} + +unsafe fn huf_decode_stream( + dst: *mut u8, + dst_size: usize, + stream: &mut DStream, + table: *const HufDEltX2, + table_log: u32, +) -> usize { + let start = dst; + let end = dst.add(dst_size); + let mut op = dst; + + /* The v0.5 C decoder uses a 4-symbol unrolled loop followed by a tail. + * Decoding one symbol at a time has the same state transitions and keeps + * the same stop-bit validation while remaining easy to audit. */ + while op < end { + let status = reload_dstream(stream); + if status == DSTREAM_TOO_FAR || (status == DSTREAM_COMPLETED && op < end) { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + *op = huf_decode_symbol(stream, table, table_log); + op = op.add(1); + } + if !end_of_dstream(stream) { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + (op as usize) - (start as usize) +} + +unsafe fn huf_decompress4x2_using_dtable( + dst: *mut u8, + dst_size: usize, + c_src: *const u8, + c_src_size: usize, + dtable: &[u16; 1 + (1 << HUF_MAX_TABLELOG)], +) -> usize { + if c_src_size < 10 { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + let length1 = read_le16(c_src) as usize; + let length2 = read_le16(c_src.add(2)) as usize; + let length3 = read_le16(c_src.add(4)) as usize; + let payload = length1 + .checked_add(length2) + .and_then(|v| v.checked_add(length3)) + .and_then(|v| v.checked_add(6)); + let payload = match payload { + Some(value) if value <= c_src_size => value, + _ => return ERROR(ZstdErrorCode::CorruptionDetected), + }; + let length4 = c_src_size - payload; + let stream1 = c_src.add(6); + let stream2 = stream1.add(length1); + let stream3 = stream2.add(length2); + let stream4 = stream3.add(length3); + let segment = dst_size.div_ceil(4); + let starts = [ + dst, + dst.add(segment), + dst.add(segment * 2), + dst.add(segment * 3), + ]; + let sizes = [ + segment.min(dst_size), + segment.min(dst_size.saturating_sub(segment)), + segment.min(dst_size.saturating_sub(segment * 2)), + dst_size.saturating_sub(segment * 3), + ]; + let lengths = [length1, length2, length3, length4]; + let sources = [stream1, stream2, stream3, stream4]; + let table = dtable.as_ptr().add(1) as *const HufDEltX2; + let table_log = dtable[0] as u32; + for index in 0..4 { + let mut stream = DStream { + bit_container: 0, + bits_consumed: 0, + ptr: ptr::null(), + start: ptr::null(), + }; + let error = init_dstream(&mut stream, sources[index], lengths[index]); + if ERR_isError(error) { + return error; + } + let decoded = huf_decode_stream(starts[index], sizes[index], &mut stream, table, table_log); + if ERR_isError(decoded) { + return decoded; + } + } + dst_size +} + +unsafe fn huf_decompress1x2_using_dtable( + dst: *mut u8, + dst_size: usize, + c_src: *const u8, + c_src_size: usize, + dtable: &[u16; 1 + (1 << HUF_MAX_TABLELOG)], +) -> usize { + if dst_size <= c_src_size { + return ERROR(ZstdErrorCode::DstSizeTooSmall); + } + let mut stream = DStream { + bit_container: 0, + bits_consumed: 0, + ptr: ptr::null(), + start: ptr::null(), + }; + let result = init_dstream(&mut stream, c_src, c_src_size); + if ERR_isError(result) { + return result; + } + let table = dtable.as_ptr().add(1) as *const HufDEltX2; + let decoded = huf_decode_stream(dst, dst_size, &mut stream, table, dtable[0] as u32); + if ERR_isError(decoded) { + return decoded; + } + if !end_of_dstream(&stream) { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + dst_size +} + +unsafe fn huf_decompress1x2( + dst: *mut u8, + dst_size: usize, + c_src: *const u8, + c_src_size: usize, +) -> usize { + let mut dtable = [0u16; 1 + (1 << HUF_MAX_TABLELOG)]; + dtable[0] = HUF_MAX_TABLELOG as u16; + let header_size = huf_read_dtable_x2(&mut dtable, c_src, c_src_size); + if ERR_isError(header_size) { + return header_size; + } + if header_size >= c_src_size { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + huf_decompress1x2_using_dtable( + dst, + dst_size, + c_src.add(header_size), + c_src_size - header_size, + &dtable, + ) +} + +#[repr(C)] +#[derive(Clone, Copy)] +struct HufDEltX4 { + sequence: u16, + nb_bits: u8, + length: u8, +} + +#[repr(C)] +#[derive(Clone, Copy)] +struct SortedSymbol { + symbol: u8, + weight: u8, +} + +type RankVal = [[u32; HUF_ABSOLUTE_MAX_TABLELOG + 1]; HUF_ABSOLUTE_MAX_TABLELOG]; + +#[inline] +unsafe fn huf_set_dtable_x4( + dtable: *mut HufDEltX4, + index: usize, + sequence: u16, + nb_bits: u32, + length: u8, +) { + let entry = dtable.add(index); + write_le16(entry.cast::(), sequence); + (*entry).nb_bits = nb_bits as u8; + (*entry).length = length; +} + +#[allow(clippy::too_many_arguments)] +unsafe fn huf_fill_dtable_x4_level2( + dtable: *mut HufDEltX4, + size_log: u32, + consumed: u32, + rank_val_origin: &[u32; HUF_ABSOLUTE_MAX_TABLELOG + 1], + min_weight: usize, + sorted_symbols: &[SortedSymbol; HUF_MAX_SYMBOL_VALUE + 1], + sorted_start: usize, + sorted_list_size: usize, + nb_bits_baseline: u32, + base_seq: u16, +) { + let mut rank_val = *rank_val_origin; + + if min_weight > 1 { + let skip_size = rank_val[min_weight] as usize; + for index in 0..skip_size { + huf_set_dtable_x4(dtable, index, base_seq, consumed, 1); + } + } + + for item in 0..sorted_list_size { + let sorted = sorted_symbols[sorted_start + item]; + let symbol = sorted.symbol as u32; + let weight = sorted.weight as usize; + let nb_bits = nb_bits_baseline - weight as u32; + let length = 1u32 << (size_log - nb_bits); + let start = rank_val[weight] as usize; + let end = start + length as usize; + let sequence = base_seq.wrapping_add((symbol << 8) as u16); + for index in start..end { + huf_set_dtable_x4(dtable, index, sequence, nb_bits + consumed, 2); + } + rank_val[weight] = rank_val[weight].wrapping_add(length); + } +} + +#[allow(clippy::too_many_arguments)] +unsafe fn huf_fill_dtable_x4( + dtable: *mut HufDEltX4, + target_log: u32, + sorted_list: &[SortedSymbol; HUF_MAX_SYMBOL_VALUE + 1], + sorted_list_size: usize, + rank_start0: &[u32; HUF_ABSOLUTE_MAX_TABLELOG + 2], + rank_val_origin: &RankVal, + max_weight: u32, + nb_bits_baseline: u32, +) { + let mut rank_val = rank_val_origin[0]; + let scale_log = nb_bits_baseline as i32 - target_log as i32; + let min_bits = nb_bits_baseline - max_weight; + + for item in 0..sorted_list_size { + let sorted = sorted_list[item]; + let symbol = sorted.symbol as u16; + let weight = sorted.weight as usize; + let nb_bits = nb_bits_baseline - weight as u32; + let start = rank_val[weight] as usize; + let length = 1u32 << (target_log - nb_bits); + + if target_log - nb_bits >= min_bits { + let mut min_weight = nb_bits as i32 + scale_log; + if min_weight < 1 { + min_weight = 1; + } + let min_weight = min_weight as usize; + let sorted_rank = rank_start0[min_weight + 1] as usize; + huf_fill_dtable_x4_level2( + dtable.add(start), + target_log - nb_bits, + nb_bits, + &rank_val_origin[nb_bits as usize], + min_weight, + sorted_list, + sorted_rank, + sorted_list_size - sorted_rank, + nb_bits_baseline, + symbol, + ); + } else { + let end = start + length as usize; + for index in start..end { + huf_set_dtable_x4(dtable, index, symbol, nb_bits, 1); + } + } + rank_val[weight] = rank_val[weight].wrapping_add(length); + } +} + +#[allow(clippy::needless_range_loop)] +unsafe fn huf_read_dtable_x4( + dtable: &mut [u32; 1 + (1 << HUF_MAX_TABLELOG)], + src: *const u8, + src_size: usize, +) -> usize { + let mut weight_list = [0u8; HUF_MAX_SYMBOL_VALUE + 1]; + let mut sorted_symbols = [SortedSymbol { + symbol: 0, + weight: 0, + }; HUF_MAX_SYMBOL_VALUE + 1]; + let mut rank_stats = [0u32; HUF_ABSOLUTE_MAX_TABLELOG + 1]; + let mut rank_start0 = [0u32; HUF_ABSOLUTE_MAX_TABLELOG + 2]; + let mut rank_val = [[0u32; HUF_ABSOLUTE_MAX_TABLELOG + 1]; HUF_ABSOLUTE_MAX_TABLELOG]; + let mut nb_symbols = 0u32; + let mut table_log = 0u32; + let mem_log = dtable[0]; + + if mem_log > HUF_ABSOLUTE_MAX_TABLELOG as u32 { + return ERROR(ZstdErrorCode::TableLogTooLarge); + } + + let i_size = huf_read_stats( + &mut weight_list, + &mut rank_stats, + &mut nb_symbols, + &mut table_log, + src, + src_size, + ); + if ERR_isError(i_size) { + return i_size; + } + if table_log > mem_log { + return ERROR(ZstdErrorCode::TableLogTooLarge); + } + + let mut max_weight = table_log as usize; + loop { + if rank_stats[max_weight] != 0 { + break; + } + if max_weight == 0 { + return ERROR(ZstdErrorCode::Generic); + } + max_weight -= 1; + } + + let mut next_rank_start = 0u32; + for weight in 1..=max_weight { + let current = next_rank_start; + next_rank_start = next_rank_start.wrapping_add(rank_stats[weight]); + rank_start0[weight + 1] = current; + } + rank_start0[0] = next_rank_start; + let size_of_sort = next_rank_start as usize; + + for symbol in 0..nb_symbols as usize { + let weight = weight_list[symbol] as usize; + let rank = rank_start0[weight + 1] as usize; + sorted_symbols[rank] = SortedSymbol { + symbol: symbol as u8, + weight: weight as u8, + }; + rank_start0[weight + 1] = rank as u32 + 1; + } + rank_start0[1] = 0; + + let min_bits = table_log + 1 - max_weight as u32; + let rescale = (mem_log as i32 - table_log as i32) - 1; + let mut next_rank_val = 0u32; + for weight in 1..=max_weight { + let current = next_rank_val; + let shift = (weight as i32 + rescale) as u32; + next_rank_val = next_rank_val.wrapping_add(rank_stats[weight] << shift); + rank_val[0][weight] = current; + } + if min_bits <= mem_log.saturating_sub(min_bits) { + for consumed in min_bits..=mem_log - min_bits { + for weight in 1..=max_weight { + rank_val[consumed as usize][weight] = rank_val[0][weight] >> consumed; + } + } + } + + let table = dtable.as_mut_ptr().add(1) as *mut HufDEltX4; + huf_fill_dtable_x4( + table, + mem_log, + &sorted_symbols, + size_of_sort, + &rank_start0, + &rank_val, + max_weight as u32, + table_log + 1, + ); + i_size +} + +#[inline] +unsafe fn huf_decode_symbol_x4( + op: &mut *mut u8, + stream: &mut DStream, + dtable: *const HufDEltX4, + table_log: u32, +) -> u32 { + let value = look_bits_fast(stream, table_log); + let entry = dtable.add(value); + ptr::copy(entry.cast::(), *op, 2); + skip_bits(stream, (*entry).nb_bits as u32); + let length = (*entry).length as u32; + *op = (*op).add(length as usize); + length +} + +#[inline] +unsafe fn huf_decode_last_symbol_x4( + op: *mut u8, + stream: &mut DStream, + dtable: *const HufDEltX4, + table_log: u32, +) -> u32 { + let value = look_bits_fast(stream, table_log); + let entry = dtable.add(value); + *op = read_le16(entry.cast::()) as u8; + if (*entry).length == 1 { + skip_bits(stream, (*entry).nb_bits as u32); + } else if stream.bits_consumed < USIZE_BITS { + skip_bits(stream, (*entry).nb_bits as u32); + if stream.bits_consumed > USIZE_BITS { + stream.bits_consumed = USIZE_BITS; + } + } + 1 +} + +#[inline] +unsafe fn huf_decode_symbol_x4_0( + op: &mut *mut u8, + stream: &mut DStream, + dtable: *const HufDEltX4, + table_log: u32, +) { + huf_decode_symbol_x4(op, stream, dtable, table_log); +} + +#[inline] +unsafe fn huf_decode_symbol_x4_1( + op: &mut *mut u8, + stream: &mut DStream, + dtable: *const HufDEltX4, + table_log: u32, +) { + if USIZE_BITS == 64 || HUF_MAX_TABLELOG <= 12 { + huf_decode_symbol_x4(op, stream, dtable, table_log); + } +} + +#[inline] +unsafe fn huf_decode_symbol_x4_2( + op: &mut *mut u8, + stream: &mut DStream, + dtable: *const HufDEltX4, + table_log: u32, +) { + if USIZE_BITS == 64 { + huf_decode_symbol_x4(op, stream, dtable, table_log); + } +} + +unsafe fn huf_decode_stream_x4( + mut p: *mut u8, + stream: &mut DStream, + p_end: *mut u8, + dtable: *const HufDEltX4, + table_log: u32, +) -> usize { + let p_start = p; + while reload_dstream(stream) == DSTREAM_UNFINISHED + && (p as usize) < (p_end as usize).wrapping_sub(7) + { + huf_decode_symbol_x4_2(&mut p, stream, dtable, table_log); + huf_decode_symbol_x4_1(&mut p, stream, dtable, table_log); + huf_decode_symbol_x4_2(&mut p, stream, dtable, table_log); + huf_decode_symbol_x4_0(&mut p, stream, dtable, table_log); + } + while reload_dstream(stream) == DSTREAM_UNFINISHED + && (p as usize) <= (p_end as usize).wrapping_sub(2) + { + huf_decode_symbol_x4_0(&mut p, stream, dtable, table_log); + } + while (p as usize) <= (p_end as usize).wrapping_sub(2) { + huf_decode_symbol_x4_0(&mut p, stream, dtable, table_log); + } + if (p as usize) < p_end as usize { + p = p.add(huf_decode_last_symbol_x4(p, stream, dtable, table_log) as usize); + } + (p as usize).wrapping_sub(p_start as usize) +} + +unsafe fn huf_decompress4x4_using_dtable( + dst: *mut u8, + dst_size: usize, + c_src: *const u8, + c_src_size: usize, + dtable: &[u32; 1 + (1 << HUF_MAX_TABLELOG)], +) -> usize { + if c_src_size < 10 { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + let length1 = read_le16(c_src) as usize; + let length2 = read_le16(c_src.add(2)) as usize; + let length3 = read_le16(c_src.add(4)) as usize; + let total = length1 + .wrapping_add(length2) + .wrapping_add(length3) + .wrapping_add(6); + let length4 = c_src_size.wrapping_sub(total); + if length4 > c_src_size { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + + let streams = [ + c_src.add(6), + c_src.add(6 + length1), + c_src.add(6 + length1 + length2), + c_src.add(6 + length1 + length2 + length3), + ]; + let lengths = [length1, length2, length3, length4]; + let segment = dst_size.wrapping_add(3) / 4; + let starts = [ + dst, + dst.add(segment), + dst.add(segment * 2), + dst.add(segment * 3), + ]; + let sizes = [ + segment.min(dst_size), + segment.min(dst_size.saturating_sub(segment)), + segment.min(dst_size.saturating_sub(segment * 2)), + dst_size.saturating_sub(segment * 3), + ]; + let table = dtable.as_ptr().add(1) as *const HufDEltX4; + let table_log = dtable[0]; + + for index in 0..4 { + let mut stream = DStream { + bit_container: 0, + bits_consumed: 0, + ptr: ptr::null(), + start: ptr::null(), + }; + let error = init_dstream(&mut stream, streams[index], lengths[index]); + if ERR_isError(error) { + return error; + } + let decoded = huf_decode_stream_x4( + starts[index], + &mut stream, + starts[index].add(sizes[index]), + table, + table_log, + ); + if decoded != sizes[index] { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + } + dst_size +} + +unsafe fn huf_decompress1x4_using_dtable( + dst: *mut u8, + dst_size: usize, + c_src: *const u8, + c_src_size: usize, + dtable: &[u32; 1 + (1 << HUF_MAX_TABLELOG)], +) -> usize { + let mut stream = DStream { + bit_container: 0, + bits_consumed: 0, + ptr: ptr::null(), + start: ptr::null(), + }; + let result = init_dstream(&mut stream, c_src, c_src_size); + if ERR_isError(result) { + return result; + } + let table = dtable.as_ptr().add(1) as *const HufDEltX4; + let decoded = huf_decode_stream_x4(dst, &mut stream, dst.add(dst_size), table, dtable[0]); + if decoded != dst_size || !end_of_dstream(&stream) { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + dst_size +} + +unsafe fn huf_decompress1x4( + dst: *mut u8, + dst_size: usize, + c_src: *const u8, + c_src_size: usize, +) -> usize { + let mut dtable = [0u32; 1 + (1 << HUF_MAX_TABLELOG)]; + dtable[0] = HUF_MAX_TABLELOG as u32; + let header_size = huf_read_dtable_x4(&mut dtable, c_src, c_src_size); + if ERR_isError(header_size) { + return header_size; + } + if header_size >= c_src_size { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + huf_decompress1x4_using_dtable( + dst, + dst_size, + c_src.add(header_size), + c_src_size - header_size, + &dtable, + ) +} + +unsafe fn huf_decompress4x4( + dst: *mut u8, + dst_size: usize, + c_src: *const u8, + c_src_size: usize, +) -> usize { + let mut dtable = [0u32; 1 + (1 << HUF_MAX_TABLELOG)]; + dtable[0] = HUF_MAX_TABLELOG as u32; + let header_size = huf_read_dtable_x4(&mut dtable, c_src, c_src_size); + if ERR_isError(header_size) { + return header_size; + } + if header_size >= c_src_size { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + huf_decompress4x4_using_dtable( + dst, + dst_size, + c_src.add(header_size), + c_src_size - header_size, + &dtable, + ) +} + +unsafe fn huf_decompress( + dst: *mut u8, + dst_size: usize, + c_src: *const u8, + c_src_size: usize, +) -> usize { + if dst_size == 0 { + return ERROR(ZstdErrorCode::DstSizeTooSmall); + } + if c_src_size >= dst_size { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + if c_src_size == 1 { + ptr::write_bytes(dst, *c_src, dst_size); + return dst_size; + } + + const ALGO_TIME: [[[u32; 2]; 3]; 16] = [ + [[0, 0], [1, 1], [2, 2]], + [[0, 0], [1, 1], [2, 2]], + [[38, 130], [1313, 74], [2151, 38]], + [[448, 128], [1353, 74], [2238, 41]], + [[556, 128], [1353, 74], [2238, 47]], + [[714, 128], [1418, 74], [2436, 53]], + [[883, 128], [1437, 74], [2464, 61]], + [[897, 128], [1515, 75], [2622, 68]], + [[926, 128], [1613, 75], [2730, 75]], + [[947, 128], [1729, 77], [3359, 77]], + [[1107, 128], [2083, 81], [4006, 84]], + [[1177, 128], [2379, 87], [4785, 88]], + [[1242, 128], [2415, 93], [5155, 84]], + [[1349, 128], [2644, 106], [5260, 106]], + [[1455, 128], [2422, 124], [4174, 124]], + [[722, 128], [1891, 145], [1936, 146]], + ]; + let q = c_src_size.wrapping_mul(16) / dst_size; + let d256 = (dst_size >> 8) as u32; + let mut dtime = [0u32; 3]; + for index in 0..3 { + dtime[index] = + ALGO_TIME[q][index][0].wrapping_add(ALGO_TIME[q][index][1].wrapping_mul(d256)); + } + dtime[1] = dtime[1].wrapping_add(dtime[1] >> 4); + dtime[2] = dtime[2].wrapping_add(dtime[2] >> 3); + + if dtime[1] < dtime[0] { + huf_decompress4x4(dst, dst_size, c_src, c_src_size) + } else { + let mut dtable = [0u16; 1 + (1 << HUF_MAX_TABLELOG)]; + dtable[0] = HUF_MAX_TABLELOG as u16; + let header_size = huf_read_dtable_x2(&mut dtable, c_src, c_src_size); + if ERR_isError(header_size) { + return header_size; + } + if header_size >= c_src_size { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + huf_decompress4x2_using_dtable( + dst, + dst_size, + c_src.add(header_size), + c_src_size - header_size, + &dtable, + ) + } +} + +/* ****************************************** + * v0.5 frame decoder + ********************************************/ + +const FRAME_HEADER_SIZE_MIN: usize = 5; +const FRAME_HEADER_SIZE_MAX: usize = 5; +const BLOCK_HEADER_SIZE: usize = 3; +const WINDOWLOG_ABSOLUTE_MIN: u32 = 11; + +const STAGE_GET_FRAME_HEADER_SIZE: u32 = 0; +const STAGE_DECODE_FRAME_HEADER: u32 = 1; +const STAGE_DECODE_BLOCK_HEADER: u32 = 2; +const STAGE_DECOMPRESS_BLOCK: u32 = 3; + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct ZstdParameters { + src_size: u64, + window_log: u32, + content_log: u32, + hash_log: u32, + search_log: u32, + search_length: u32, + target_length: u32, + strategy: u32, +} + +#[repr(C)] +pub struct ZSTDv05_Dctx { + ll_table: [u32; 1 + (1 << LL_FSE_LOG)], + off_table: [u32; 1 + (1 << OFF_FSE_LOG)], + ml_table: [u32; 1 + (1 << ML_FSE_LOG)], + huf_table_x4: [u32; 1 + (1 << HUF_MAX_TABLELOG)], + previous_dst_end: *const u8, + base: *const u8, + v_base: *const u8, + dict_end: *const u8, + expected: usize, + header_size: usize, + params: ZstdParameters, + b_type: u32, + stage: u32, + flag_static_tables: u32, + lit_ptr: *const u8, + lit_size: usize, + lit_buffer: [u8; BLOCKSIZE + 8], + header_buffer: [u8; FRAME_HEADER_SIZE_MAX], +} + +#[derive(Clone, Copy)] +struct BlockProperties { + block_type: u32, + orig_size: u32, +} + +#[inline] +unsafe fn decompress_begin(dctx: &mut ZSTDv05_Dctx) -> usize { + dctx.expected = FRAME_HEADER_SIZE_MIN; + dctx.stage = STAGE_GET_FRAME_HEADER_SIZE; + dctx.previous_dst_end = ptr::null(); + dctx.base = ptr::null(); + dctx.v_base = ptr::null(); + dctx.dict_end = ptr::null(); + dctx.huf_table_x4[0] = HUF_MAX_TABLELOG as u32; + dctx.flag_static_tables = 0; + 0 +} + +#[inline] +unsafe fn create_dctx() -> *mut ZSTDv05_Dctx { + let dctx = libc::malloc(std::mem::size_of::()) as *mut ZSTDv05_Dctx; + if dctx.is_null() { + return ptr::null_mut(); + } + decompress_begin(&mut *dctx); + dctx +} + +#[inline] +unsafe fn free_dctx(dctx: *mut ZSTDv05_Dctx) -> usize { + libc::free(dctx.cast::()); + 0 +} + +unsafe fn decode_frame_header_part1( + dctx: &mut ZSTDv05_Dctx, + src: *const u8, + src_size: usize, +) -> usize { + if src_size != FRAME_HEADER_SIZE_MIN { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + if read_le32(src) != ZSTD_MAGIC_NUMBER { + return ERROR(ZstdErrorCode::PrefixUnknown); + } + dctx.header_size = FRAME_HEADER_SIZE_MIN; + dctx.header_size +} + +unsafe fn get_frame_params(params: &mut ZstdParameters, src: *const u8, src_size: usize) -> usize { + if src_size < FRAME_HEADER_SIZE_MIN { + return FRAME_HEADER_SIZE_MAX; + } + if read_le32(src) != ZSTD_MAGIC_NUMBER { + return ERROR(ZstdErrorCode::PrefixUnknown); + } + *params = ZstdParameters { + src_size: 0, + window_log: 0, + content_log: 0, + hash_log: 0, + search_log: 0, + search_length: 0, + target_length: 0, + strategy: 0, + }; + let descriptor = *src.add(4); + params.window_log = (descriptor & 15) as u32 + WINDOWLOG_ABSOLUTE_MIN; + if descriptor >> 4 != 0 { + return ERROR(ZstdErrorCode::FrameParameterUnsupported); + } + 0 +} + +unsafe fn decode_frame_header_part2( + dctx: &mut ZSTDv05_Dctx, + src: *const u8, + src_size: usize, +) -> usize { + if src_size != dctx.header_size { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + let result = get_frame_params(&mut dctx.params, src, src_size); + if USIZE_BITS == 32 && dctx.params.window_log > 25 { + return ERROR(ZstdErrorCode::FrameParameterUnsupported); + } + result +} + +unsafe fn get_block_size( + src: *const u8, + src_size: usize, + properties: &mut BlockProperties, +) -> usize { + if src_size < BLOCK_HEADER_SIZE { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + let header_flags = *src; + let c_size = *src.add(2) as usize + | ((*src.add(1) as usize) << 8) + | (((header_flags as usize) & 7) << 16); + properties.block_type = (header_flags >> 6) as u32; + properties.orig_size = if properties.block_type == BT_RLE { + c_size as u32 + } else { + 0 + }; + if properties.block_type == BT_END { + return 0; + } + if properties.block_type == BT_RLE { + return 1; + } + c_size +} + +unsafe fn copy_raw_block( + dst: *mut u8, + max_dst_size: usize, + src: *const u8, + src_size: usize, +) -> usize { + if dst.is_null() { + return ERROR(ZstdErrorCode::DstSizeTooSmall); + } + if src_size > max_dst_size { + return ERROR(ZstdErrorCode::DstSizeTooSmall); + } + if src_size != 0 { + ptr::copy(src, dst, src_size); + } + src_size +} + +unsafe fn decode_literals_block(dctx: &mut ZSTDv05_Dctx, src: *const u8, src_size: usize) -> usize { + if src_size < MIN_CBLOCK_SIZE { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + let istart = src; + match *istart >> 6 { + IS_HUF => { + if src_size < 5 { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + let lit_size; + let lit_c_size; + let mut header_size = ((*istart >> 4) & 3) as usize; + let single_stream = if header_size <= 1 { + header_size = 3; + (*istart & 16) != 0 + } else { + false + }; + match header_size { + 3 => { + lit_size = (((*istart & 15) as usize) << 6) + ((*istart.add(1) as usize) >> 2); + lit_c_size = (((*istart.add(1) as usize) & 3) << 8) + *istart.add(2) as usize; + } + 4 => { + lit_size = (((*istart & 15) as usize) << 10) + + ((*istart.add(1) as usize) << 2) + + ((*istart.add(2) as usize) >> 6); + lit_c_size = (((*istart.add(2) as usize) & 63) << 8) + *istart.add(3) as usize; + } + 5 => { + lit_size = (((*istart & 15) as usize) << 14) + + ((*istart.add(1) as usize) << 6) + + ((*istart.add(2) as usize) >> 2); + lit_c_size = (((*istart.add(2) as usize) & 3) << 16) + + ((*istart.add(3) as usize) << 8) + + *istart.add(4) as usize; + } + _ => return ERROR(ZstdErrorCode::CorruptionDetected), + } + if lit_size > BLOCKSIZE || lit_c_size + header_size > src_size { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + let result = if single_stream { + huf_decompress1x2( + dctx.lit_buffer.as_mut_ptr(), + lit_size, + istart.add(header_size), + lit_c_size, + ) + } else { + huf_decompress( + dctx.lit_buffer.as_mut_ptr(), + lit_size, + istart.add(header_size), + lit_c_size, + ) + }; + if ERR_isError(result) { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + dctx.lit_ptr = dctx.lit_buffer.as_ptr(); + dctx.lit_size = lit_size; + dctx.lit_buffer[lit_size..lit_size + 8].fill(0); + header_size + lit_c_size + } + IS_PCH => { + let mut header_size = ((*istart >> 4) & 3) as usize; + if header_size != 1 || dctx.flag_static_tables == 0 { + return if dctx.flag_static_tables == 0 { + ERROR(ZstdErrorCode::DictionaryCorrupted) + } else { + ERROR(ZstdErrorCode::CorruptionDetected) + }; + } + header_size = 3; + let lit_size = (((*istart & 15) as usize) << 6) + ((*istart.add(1) as usize) >> 2); + let lit_c_size = (((*istart.add(1) as usize) & 3) << 8) + *istart.add(2) as usize; + if lit_c_size + header_size > src_size || lit_size > BLOCKSIZE { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + let result = huf_decompress1x4_using_dtable( + dctx.lit_buffer.as_mut_ptr(), + lit_size, + istart.add(header_size), + lit_c_size, + &dctx.huf_table_x4, + ); + if ERR_isError(result) { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + dctx.lit_ptr = dctx.lit_buffer.as_ptr(); + dctx.lit_size = lit_size; + dctx.lit_buffer[lit_size..lit_size + 8].fill(0); + header_size + lit_c_size + } + IS_RAW => { + let header_size = ((*istart >> 4) & 3) as usize; + let (header_size, lit_size) = match header_size { + 0 | 1 => (1, (*istart & 31) as usize), + 2 => ( + 2, + (((*istart & 15) as usize) << 8) + *istart.add(1) as usize, + ), + 3 => ( + 3, + (((*istart & 15) as usize) << 16) + + ((*istart.add(1) as usize) << 8) + + *istart.add(2) as usize, + ), + _ => unreachable!(), + }; + if header_size + lit_size > src_size || lit_size > BLOCKSIZE { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + if header_size + lit_size + 8 > src_size { + ptr::copy_nonoverlapping( + istart.add(header_size), + dctx.lit_buffer.as_mut_ptr(), + lit_size, + ); + dctx.lit_ptr = dctx.lit_buffer.as_ptr(); + dctx.lit_size = lit_size; + dctx.lit_buffer[lit_size..lit_size + 8].fill(0); + } else { + dctx.lit_ptr = istart.add(header_size); + dctx.lit_size = lit_size; + } + header_size + lit_size + } + IS_RLE => { + let header_size = ((*istart >> 4) & 3) as usize; + let (header_size, lit_size) = match header_size { + 0 | 1 => (1, (*istart & 31) as usize), + 2 => ( + 2, + (((*istart & 15) as usize) << 8) + *istart.add(1) as usize, + ), + 3 => { + if src_size < 4 { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + ( + 3, + (((*istart & 15) as usize) << 16) + + ((*istart.add(1) as usize) << 8) + + *istart.add(2) as usize, + ) + } + _ => unreachable!(), + }; + if lit_size > BLOCKSIZE { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + dctx.lit_buffer[..lit_size + 8].fill(*istart.add(header_size)); + dctx.lit_ptr = dctx.lit_buffer.as_ptr(); + dctx.lit_size = lit_size; + header_size + 1 + } + _ => ERROR(ZstdErrorCode::CorruptionDetected), + } +} + +unsafe fn decode_seq_headers( + dctx: &mut ZSTDv05_Dctx, + nb_seq: &mut i32, + dumps: &mut *const u8, + dumps_length: &mut usize, + src: *const u8, + src_size: usize, + flag_static_tables: u32, +) -> usize { + if src_size < MIN_SEQUENCES_SIZE { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + + let istart = src; + let iend = src.add(src_size); + let mut ip = src; + *nb_seq = *ip as i32; + ip = ip.add(1); + if *nb_seq == 0 { + return 1; + } + if *nb_seq >= 128 { + if ip >= iend { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + *nb_seq = ((*nb_seq - 128) << 8) + *ip as i32; + ip = ip.add(1); + } + if ip >= iend { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + + let types = *ip; + let ll_type = (types >> 6) as u32; + let off_type = ((types >> 4) & 3) as u32; + let ml_type = ((types >> 2) & 3) as u32; + let dump_size = if types & 2 != 0 { + if iend.offset_from(ip) < 3 { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + let size = *ip.add(2) as usize | ((*ip.add(1) as usize) << 8); + ip = ip.add(3); + size + } else { + if iend.offset_from(ip) < 2 { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + let size = *ip.add(1) as usize | (((*ip as usize) & 1) << 8); + ip = ip.add(2); + size + }; + + if dump_size > iend.offset_from(ip) as usize { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + *dumps = ip; + *dumps_length = dump_size; + ip = ip.add(dump_size); + if iend.offset_from(ip) < 3 { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + + let mut norm = [0i16; 256]; + + match ll_type { + FSE_ENCODING_RLE => { + if ip >= iend { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + let result = fse_build_dtable_rle(&mut dctx.ll_table, *ip); + if ERR_isError(result) { + return result; + } + ip = ip.add(1); + } + FSE_ENCODING_RAW => { + let result = fse_build_dtable_raw(&mut dctx.ll_table, LL_BITS); + if ERR_isError(result) { + return result; + } + } + FSE_ENCODING_STATIC => { + if flag_static_tables == 0 { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + } + FSE_ENCODING_DYNAMIC => { + let mut max = MAX_LL; + let mut log = 0; + let header_size = fse_read_ncount( + &mut norm, + &mut max, + &mut log, + ip, + iend.offset_from(ip) as usize, + ); + if ERR_isError(header_size) { + return ERROR(ZstdErrorCode::Generic); + } + if log > LL_FSE_LOG { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + ip = ip.add(header_size); + let result = fse_build_dtable(&mut dctx.ll_table, &norm, max, log); + if ERR_isError(result) { + return result; + } + } + _ => return ERROR(ZstdErrorCode::CorruptionDetected), + } + + match off_type { + FSE_ENCODING_RLE => { + if iend.offset_from(ip) < 2 { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + let result = fse_build_dtable_rle(&mut dctx.off_table, *ip & MAX_OFF as u8); + if ERR_isError(result) { + return result; + } + ip = ip.add(1); + } + FSE_ENCODING_RAW => { + let result = fse_build_dtable_raw(&mut dctx.off_table, OFF_BITS); + if ERR_isError(result) { + return result; + } + } + FSE_ENCODING_STATIC => { + if flag_static_tables == 0 { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + } + FSE_ENCODING_DYNAMIC => { + let mut max = MAX_OFF; + let mut log = 0; + let header_size = fse_read_ncount( + &mut norm, + &mut max, + &mut log, + ip, + iend.offset_from(ip) as usize, + ); + if ERR_isError(header_size) { + return ERROR(ZstdErrorCode::Generic); + } + if log > OFF_FSE_LOG { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + ip = ip.add(header_size); + let result = fse_build_dtable(&mut dctx.off_table, &norm, max, log); + if ERR_isError(result) { + return result; + } + } + _ => return ERROR(ZstdErrorCode::CorruptionDetected), + } + + match ml_type { + FSE_ENCODING_RLE => { + if iend.offset_from(ip) < 2 { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + let result = fse_build_dtable_rle(&mut dctx.ml_table, *ip); + if ERR_isError(result) { + return result; + } + ip = ip.add(1); + } + FSE_ENCODING_RAW => { + let result = fse_build_dtable_raw(&mut dctx.ml_table, ML_BITS); + if ERR_isError(result) { + return result; + } + } + FSE_ENCODING_STATIC => { + if flag_static_tables == 0 { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + } + FSE_ENCODING_DYNAMIC => { + let mut max = MAX_ML; + let mut log = 0; + let header_size = fse_read_ncount( + &mut norm, + &mut max, + &mut log, + ip, + iend.offset_from(ip) as usize, + ); + if ERR_isError(header_size) { + return ERROR(ZstdErrorCode::Generic); + } + if log > ML_FSE_LOG { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + ip = ip.add(header_size); + let result = fse_build_dtable(&mut dctx.ml_table, &norm, max, log); + if ERR_isError(result) { + return result; + } + } + _ => return ERROR(ZstdErrorCode::CorruptionDetected), + } + + (ip as usize).wrapping_sub(istart as usize) +} + +#[derive(Clone, Copy)] +struct Sequence { + lit_length: usize, + offset: usize, + match_length: usize, +} + +struct SequenceState { + stream: DStream, + state_ll: FseDState, + state_off: FseDState, + state_ml: FseDState, + prev_offset: usize, + dumps: *const u8, + dumps_end: *const u8, +} + +unsafe fn decode_sequence(sequence: &mut Sequence, state: &mut SequenceState) { + let mut dumps = state.dumps; + let dumps_end = state.dumps_end; + + let mut lit_length = fse_peak_symbol(&state.state_ll) as usize; + let previous_offset = if lit_length != 0 { + sequence.offset + } else { + state.prev_offset + }; + if lit_length == MAX_LL as usize { + let add = if dumps < dumps_end { + let value = *dumps as usize; + dumps = dumps.add(1); + value + } else { + 0 + }; + if add < 255 { + lit_length += add; + } else if dumps.wrapping_add(2) <= dumps_end { + lit_length = read_le16(dumps) as usize; + dumps = dumps.add(2); + if (lit_length & 1) != 0 && dumps < dumps_end { + lit_length += (*dumps as usize) << 16; + dumps = dumps.add(1); + } + lit_length >>= 1; + } + if dumps >= dumps_end { + dumps = dumps_end.wrapping_sub(1); + } + } + + let offset_code = fse_peak_symbol(&state.state_off) as u32; + let nb_bits = if offset_code == 0 { 0 } else { offset_code - 1 }; + let offset_prefix = [ + 1usize, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, + 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 1, 1, 1, 1, + 1, + ]; + let mut offset = + offset_prefix[offset_code as usize].wrapping_add(read_bits(&mut state.stream, nb_bits)); + if USIZE_BITS == 32 { + reload_dstream(&mut state.stream); + } + if offset_code == 0 { + offset = previous_offset; + } + if offset_code != 0 || lit_length == 0 { + state.prev_offset = sequence.offset; + } + fse_decode_symbol(&mut state.state_off, &mut state.stream, false); + + fse_decode_symbol(&mut state.state_ll, &mut state.stream, false); + if USIZE_BITS == 32 { + reload_dstream(&mut state.stream); + } + + let mut match_length = + fse_decode_symbol(&mut state.state_ml, &mut state.stream, false) as usize; + if match_length == MAX_ML as usize { + let add = if dumps < dumps_end { + let value = *dumps as usize; + dumps = dumps.add(1); + value + } else { + 0 + }; + if add < 255 { + match_length += add; + } else if dumps.wrapping_add(2) <= dumps_end { + match_length = read_le16(dumps) as usize; + dumps = dumps.add(2); + if (match_length & 1) != 0 && dumps < dumps_end { + match_length += (*dumps as usize) << 16; + dumps = dumps.add(1); + } + match_length >>= 1; + } + if dumps >= dumps_end { + dumps = dumps_end.wrapping_sub(1); + } + } + + sequence.lit_length = lit_length; + sequence.offset = offset; + sequence.match_length = match_length + MINMATCH; + state.dumps = dumps; +} + +#[allow(clippy::too_many_arguments)] +unsafe fn exec_sequence( + mut op: *mut u8, + mut sequence: Sequence, + lit_ptr: &mut *const u8, + lit_limit: *const u8, + base: *const u8, + v_base: *const u8, + dict_end: *const u8, + oend: *mut u8, +) -> usize { + let o_lit_end = (op as usize).wrapping_add(sequence.lit_length); + let sequence_length = sequence.lit_length.wrapping_add(sequence.match_length); + let o_match_end = o_lit_end.wrapping_add(sequence.match_length); + let oend_addr = oend as usize; + let oend_8 = oend_addr.wrapping_sub(8); + let lit_end = (*lit_ptr as usize).wrapping_add(sequence.lit_length); + let mut match_addr = o_lit_end.wrapping_sub(sequence.offset); + + if sequence_length > oend_addr.wrapping_sub(op as usize) { + return ERROR(ZstdErrorCode::DstSizeTooSmall); + } + if sequence.lit_length > (lit_limit as usize).wrapping_sub(*lit_ptr as usize) { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + if o_lit_end > oend_8 { + return ERROR(ZstdErrorCode::DstSizeTooSmall); + } + if o_match_end > oend_addr { + return ERROR(ZstdErrorCode::DstSizeTooSmall); + } + if lit_end > lit_limit as usize { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + + zstd_wildcopy(op, *lit_ptr, sequence.lit_length as isize); + op = o_lit_end as *mut u8; + *lit_ptr = lit_end as *const u8; + + if sequence.offset > o_lit_end.wrapping_sub(base as usize) { + if sequence.offset > o_lit_end.wrapping_sub(v_base as usize) { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + match_addr = (dict_end as usize).wrapping_sub((base as usize).wrapping_sub(match_addr)); + if match_addr.wrapping_add(sequence.match_length) <= dict_end as usize { + ptr::copy( + match_addr as *const u8, + o_lit_end as *mut u8, + sequence.match_length, + ); + return sequence_length; + } + + let length1 = (dict_end as usize).wrapping_sub(match_addr); + ptr::copy(match_addr as *const u8, o_lit_end as *mut u8, length1); + op = o_lit_end.wrapping_add(length1) as *mut u8; + sequence.match_length = sequence.match_length.wrapping_sub(length1); + match_addr = base as usize; + if (op as usize) > oend_8 || sequence.match_length < MINMATCH { + let mut out = op; + let mut m = match_addr as *const u8; + while (out as usize) < o_match_end { + *out = *m; + out = out.add(1); + m = m.add(1); + } + return sequence_length; + } + } + + if sequence.offset < 8 { + let dec32 = [0usize, 1, 2, 1, 4, 4, 4, 4]; + let dec64 = [8usize, 8, 8, 7, 8, 9, 10, 11]; + *op = *(match_addr as *const u8); + *op.add(1) = *(match_addr as *const u8).add(1); + *op.add(2) = *(match_addr as *const u8).add(2); + *op.add(3) = *(match_addr as *const u8).add(3); + let match_ptr = (match_addr as *const u8).add(dec32[sequence.offset]); + zstd_copy4(op.add(4), match_ptr); + match_addr = match_addr + .wrapping_add(8) + .wrapping_sub(dec64[sequence.offset]); + } else { + zstd_copy8(op, match_addr as *const u8); + match_addr = match_addr.wrapping_add(8); + } + op = op.add(8); + match_addr = match_addr.wrapping_add(8); + + if o_match_end > oend_addr.wrapping_sub(16 - MINMATCH) { + if (op as usize) < oend_8 { + let dist = oend_8 - op as usize; + zstd_wildcopy(op, match_addr as *const u8, dist as isize); + match_addr = match_addr.wrapping_add(dist); + op = oend_8 as *mut u8; + } + while (op as usize) < o_match_end { + *op = *(match_addr as *const u8); + op = op.add(1); + match_addr = match_addr.wrapping_add(1); + } + } else { + zstd_wildcopy( + op, + match_addr as *const u8, + sequence.match_length.wrapping_sub(8) as isize, + ); + } + sequence_length +} + +unsafe fn decompress_sequences( + dctx: &mut ZSTDv05_Dctx, + dst: *mut u8, + max_dst_size: usize, + seq_start: *const u8, + seq_size: usize, +) -> usize { + let ip = seq_start; + let iend = (seq_start as usize).wrapping_add(seq_size); + let ostart = dst; + let mut op = dst; + let oend = (dst as usize).wrapping_add(max_dst_size) as *mut u8; + let mut nb_seq = 0i32; + let mut dumps = ptr::null(); + let mut dumps_length = 0usize; + let header_size = decode_seq_headers( + dctx, + &mut nb_seq, + &mut dumps, + &mut dumps_length, + ip, + seq_size, + dctx.flag_static_tables, + ); + if ERR_isError(header_size) { + return header_size; + } + let sequence_start = ip.add(header_size); + let lit_limit = dctx.lit_ptr.add(dctx.lit_size); + + if nb_seq != 0 { + let mut state = SequenceState { + stream: DStream { + bit_container: 0, + bits_consumed: 0, + ptr: ptr::null(), + start: ptr::null(), + }, + state_ll: FseDState { + state: 0, + table: ptr::null(), + }, + state_off: FseDState { + state: 0, + table: ptr::null(), + }, + state_ml: FseDState { + state: 0, + table: ptr::null(), + }, + prev_offset: REPCODE_STARTVALUE, + dumps, + dumps_end: dumps.add(dumps_length), + }; + let compressed_size = iend.wrapping_sub(sequence_start as usize); + let error = init_dstream(&mut state.stream, sequence_start, compressed_size); + if ERR_isError(error) { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + fse_init_dstate( + &mut state.state_ll, + &mut state.stream, + dctx.ll_table.as_ptr(), + ); + fse_init_dstate( + &mut state.state_off, + &mut state.stream, + dctx.off_table.as_ptr(), + ); + fse_init_dstate( + &mut state.state_ml, + &mut state.stream, + dctx.ml_table.as_ptr(), + ); + + let mut sequence = Sequence { + lit_length: 0, + offset: REPCODE_STARTVALUE, + match_length: 0, + }; + while reload_dstream(&mut state.stream) <= DSTREAM_COMPLETED && nb_seq != 0 { + nb_seq -= 1; + decode_sequence(&mut sequence, &mut state); + let produced = exec_sequence( + op, + sequence, + &mut dctx.lit_ptr, + lit_limit, + dctx.base, + dctx.v_base, + dctx.dict_end, + oend, + ); + if ERR_isError(produced) { + return produced; + } + op = op.add(produced); + } + if nb_seq != 0 { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + } + + let last_literal_size = (lit_limit as usize).wrapping_sub(dctx.lit_ptr as usize); + if dctx.lit_ptr as usize > lit_limit as usize { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + if (op as usize).wrapping_add(last_literal_size) > oend as usize { + return ERROR(ZstdErrorCode::DstSizeTooSmall); + } + if last_literal_size != 0 { + ptr::copy(dctx.lit_ptr, op, last_literal_size); + op = op.add(last_literal_size); + } + (op as usize).wrapping_sub(ostart as usize) +} + +unsafe fn check_continuity(dctx: &mut ZSTDv05_Dctx, dst: *const u8) { + if dst != dctx.previous_dst_end { + dctx.dict_end = dctx.previous_dst_end; + let delta = (dctx.previous_dst_end as usize).wrapping_sub(dctx.base as usize); + dctx.v_base = (dst as usize).wrapping_sub(delta) as *const u8; + dctx.base = dst; + dctx.previous_dst_end = dst; + } +} + +unsafe fn decompress_block_internal( + dctx: &mut ZSTDv05_Dctx, + dst: *mut u8, + max_dst_size: usize, + src: *const u8, + src_size: usize, +) -> usize { + if src_size >= BLOCKSIZE { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + let literal_size = decode_literals_block(dctx, src, src_size); + if ERR_isError(literal_size) { + return literal_size; + } + decompress_sequences( + dctx, + dst, + max_dst_size, + src.add(literal_size), + src_size - literal_size, + ) +} + +unsafe fn ref_dict_content(dctx: &mut ZSTDv05_Dctx, dict: *const u8, dict_size: usize) { + dctx.dict_end = dctx.previous_dst_end; + let delta = (dctx.previous_dst_end as usize).wrapping_sub(dctx.base as usize); + dctx.v_base = (dict as usize).wrapping_sub(delta) as *const u8; + dctx.base = dict; + dctx.previous_dst_end = (dict as usize).wrapping_add(dict_size) as *const u8; +} + +unsafe fn load_entropy( + dctx: &mut ZSTDv05_Dctx, + mut dict: *const u8, + mut dict_size: usize, +) -> usize { + let h_size = huf_read_dtable_x4(&mut dctx.huf_table_x4, dict, dict_size); + if ERR_isError(h_size) || h_size > dict_size { + return ERROR(ZstdErrorCode::DictionaryCorrupted); + } + dict = dict.add(h_size); + dict_size -= h_size; + + let mut norm = [0i16; 256]; + + let mut off_max = MAX_OFF; + let mut off_log = 0; + let off_size = fse_read_ncount(&mut norm, &mut off_max, &mut off_log, dict, dict_size); + if ERR_isError(off_size) || off_log > OFF_FSE_LOG { + return ERROR(ZstdErrorCode::DictionaryCorrupted); + } + let result = fse_build_dtable(&mut dctx.off_table, &norm, off_max, off_log); + if ERR_isError(result) || off_size > dict_size { + return ERROR(ZstdErrorCode::DictionaryCorrupted); + } + dict = dict.add(off_size); + dict_size -= off_size; + + let mut ml_max = MAX_ML; + let mut ml_log = 0; + let ml_size = fse_read_ncount(&mut norm, &mut ml_max, &mut ml_log, dict, dict_size); + if ERR_isError(ml_size) || ml_log > ML_FSE_LOG { + return ERROR(ZstdErrorCode::DictionaryCorrupted); + } + let result = fse_build_dtable(&mut dctx.ml_table, &norm, ml_max, ml_log); + if ERR_isError(result) || ml_size > dict_size { + return ERROR(ZstdErrorCode::DictionaryCorrupted); + } + dict = dict.add(ml_size); + dict_size -= ml_size; + + let mut ll_max = MAX_LL; + let mut ll_log = 0; + let ll_size = fse_read_ncount(&mut norm, &mut ll_max, &mut ll_log, dict, dict_size); + if ERR_isError(ll_size) || ll_log > LL_FSE_LOG { + return ERROR(ZstdErrorCode::DictionaryCorrupted); + } + let result = fse_build_dtable(&mut dctx.ll_table, &norm, ll_max, ll_log); + if ERR_isError(result) || ll_size > dict_size { + return ERROR(ZstdErrorCode::DictionaryCorrupted); + } + + dctx.flag_static_tables = 1; + h_size + off_size + ml_size + ll_size +} + +unsafe fn decompress_insert_dictionary( + dctx: &mut ZSTDv05_Dctx, + dict: *const u8, + dict_size: usize, +) -> usize { + if dict_size < 4 { + return ERROR(ZstdErrorCode::DictionaryCorrupted); + } + if read_le32(dict) != ZSTD_DICT_MAGIC { + ref_dict_content(dctx, dict, dict_size); + return 0; + } + + let dict = dict.add(4); + let dict_size = dict_size - 4; + let entropy_size = load_entropy(dctx, dict, dict_size); + if ERR_isError(entropy_size) || entropy_size > dict_size { + return ERROR(ZstdErrorCode::DictionaryCorrupted); + } + ref_dict_content(dctx, dict.add(entropy_size), dict_size - entropy_size); + 0 +} + +unsafe fn decompress_begin_using_dict( + dctx: &mut ZSTDv05_Dctx, + dict: *const u8, + dict_size: usize, +) -> usize { + let result = decompress_begin(dctx); + if ERR_isError(result) { + return result; + } + if !dict.is_null() && dict_size != 0 { + let result = decompress_insert_dictionary(dctx, dict, dict_size); + if ERR_isError(result) { + return ERROR(ZstdErrorCode::DictionaryCorrupted); + } + } + 0 +} + +unsafe fn decompress_continue_dctx( + ctx: &mut ZSTDv05_Dctx, + dst: *mut u8, + max_dst_size: usize, + src: *const u8, + src_size: usize, +) -> usize { + let mut ip = src; + let mut remaining_size = src_size; + let ostart = dst; + let mut op = dst; + let oend_addr = (dst as usize).wrapping_add(max_dst_size); + let mut block_properties = BlockProperties { + block_type: BT_END, + orig_size: 0, + }; + + if src_size < FRAME_HEADER_SIZE_MIN + BLOCK_HEADER_SIZE { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + let header_size = decode_frame_header_part1(ctx, src, FRAME_HEADER_SIZE_MIN); + if ERR_isError(header_size) { + return header_size; + } + if src_size < header_size + BLOCK_HEADER_SIZE { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + ip = ip.add(header_size); + remaining_size -= header_size; + let result = decode_frame_header_part2(ctx, src, header_size); + if ERR_isError(result) { + return result; + } + + loop { + let block_size = get_block_size(ip, remaining_size, &mut block_properties); + if ERR_isError(block_size) { + return block_size; + } + ip = ip.add(BLOCK_HEADER_SIZE); + remaining_size -= BLOCK_HEADER_SIZE; + if block_size > remaining_size { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + + let decoded_size = match block_properties.block_type { + BT_COMPRESSED => decompress_block_internal( + ctx, + op, + oend_addr.wrapping_sub(op as usize), + ip, + block_size, + ), + BT_RAW => copy_raw_block(op, oend_addr.wrapping_sub(op as usize), ip, block_size), + BT_RLE => return ERROR(ZstdErrorCode::Generic), + BT_END => { + if remaining_size != 0 { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + 0 + } + _ => return ERROR(ZstdErrorCode::Generic), + }; + + if block_size == 0 { + break; + } + if ERR_isError(decoded_size) { + return decoded_size; + } + op = op.add(decoded_size); + ip = ip.add(block_size); + remaining_size -= block_size; + } + + (op as usize).wrapping_sub(ostart as usize) +} + +unsafe fn decompress_using_dict( + ctx: &mut ZSTDv05_Dctx, + dst: *mut u8, + max_dst_size: usize, + src: *const u8, + src_size: usize, + dict: *const u8, + dict_size: usize, +) -> usize { + let _ = decompress_begin_using_dict(ctx, dict, dict_size); + check_continuity(ctx, dst); + decompress_continue_dctx(ctx, dst, max_dst_size, src, src_size) +} + +unsafe fn error_frame_size_info(c_size: *mut usize, d_bound: *mut u64, ret: usize) { + *c_size = ret; + *d_bound = ZSTD_CONTENTSIZE_ERROR; +} + +unsafe fn find_frame_size_info( + src: *const u8, + src_size: usize, + c_size: *mut usize, + d_bound: *mut u64, +) { + let mut ip = src; + let mut remaining_size = src_size; + let mut nb_blocks = 0usize; + let mut block_properties = BlockProperties { + block_type: BT_END, + orig_size: 0, + }; + + if src_size < FRAME_HEADER_SIZE_MIN { + error_frame_size_info(c_size, d_bound, ERROR(ZstdErrorCode::SrcSizeWrong)); + return; + } + if read_le32(src) != ZSTD_MAGIC_NUMBER { + error_frame_size_info(c_size, d_bound, ERROR(ZstdErrorCode::PrefixUnknown)); + return; + } + ip = ip.add(FRAME_HEADER_SIZE_MIN); + remaining_size -= FRAME_HEADER_SIZE_MIN; + + loop { + let block_size = get_block_size(ip, remaining_size, &mut block_properties); + if ERR_isError(block_size) { + error_frame_size_info(c_size, d_bound, block_size); + return; + } + ip = ip.add(BLOCK_HEADER_SIZE); + remaining_size -= BLOCK_HEADER_SIZE; + if block_size > remaining_size { + error_frame_size_info(c_size, d_bound, ERROR(ZstdErrorCode::SrcSizeWrong)); + return; + } + if block_size == 0 { + break; + } + ip = ip.add(block_size); + remaining_size -= block_size; + nb_blocks = nb_blocks.wrapping_add(1); + } + *c_size = (ip as usize).wrapping_sub(src as usize); + *d_bound = (nb_blocks.wrapping_mul(BLOCKSIZE)) as u64; +} + +unsafe fn next_src_size_to_decompress(dctx: &ZSTDv05_Dctx) -> usize { + dctx.expected +} + +unsafe fn decompress_continue( + ctx: &mut ZSTDv05_Dctx, + dst: *mut u8, + max_dst_size: usize, + src: *const u8, + src_size: usize, +) -> usize { + if src_size != ctx.expected { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + check_continuity(ctx, dst); + + match ctx.stage { + STAGE_GET_FRAME_HEADER_SIZE => { + if src_size != FRAME_HEADER_SIZE_MIN { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + ctx.header_size = decode_frame_header_part1(ctx, src, FRAME_HEADER_SIZE_MIN); + if ERR_isError(ctx.header_size) { + return ctx.header_size; + } + ptr::copy_nonoverlapping(src, ctx.header_buffer.as_mut_ptr(), FRAME_HEADER_SIZE_MIN); + if ctx.header_size > FRAME_HEADER_SIZE_MIN { + return ERROR(ZstdErrorCode::Generic); + } + ctx.expected = 0; + let result = + decode_frame_header_part2(ctx, ctx.header_buffer.as_ptr(), ctx.header_size); + if ERR_isError(result) { + return result; + } + ctx.expected = BLOCK_HEADER_SIZE; + ctx.stage = STAGE_DECODE_BLOCK_HEADER; + 0 + } + STAGE_DECODE_FRAME_HEADER => { + let result = + decode_frame_header_part2(ctx, ctx.header_buffer.as_ptr(), ctx.header_size); + if ERR_isError(result) { + return result; + } + ctx.expected = BLOCK_HEADER_SIZE; + ctx.stage = STAGE_DECODE_BLOCK_HEADER; + 0 + } + STAGE_DECODE_BLOCK_HEADER => { + let mut properties = BlockProperties { + block_type: BT_END, + orig_size: 0, + }; + let block_size = get_block_size(src, BLOCK_HEADER_SIZE, &mut properties); + if ERR_isError(block_size) { + return block_size; + } + if properties.block_type == BT_END { + ctx.expected = 0; + ctx.stage = STAGE_GET_FRAME_HEADER_SIZE; + } else { + ctx.expected = block_size; + ctx.b_type = properties.block_type; + ctx.stage = STAGE_DECOMPRESS_BLOCK; + } + 0 + } + STAGE_DECOMPRESS_BLOCK => { + let result = match ctx.b_type { + BT_COMPRESSED => decompress_block_internal(ctx, dst, max_dst_size, src, src_size), + BT_RAW => copy_raw_block(dst, max_dst_size, src, src_size), + BT_RLE => return ERROR(ZstdErrorCode::Generic), + BT_END => 0, + _ => return ERROR(ZstdErrorCode::Generic), + }; + ctx.stage = STAGE_DECODE_BLOCK_HEADER; + ctx.expected = BLOCK_HEADER_SIZE; + if ERR_isError(result) { + return result; + } + ctx.previous_dst_end = (dst as usize).wrapping_add(result) as *const u8; + result + } + _ => ERROR(ZstdErrorCode::Generic), + } +} + +#[repr(C)] +pub struct ZBUFFv05_DCtx { + zc: *mut ZSTDv05_Dctx, + params: ZstdParameters, + in_buff: *mut u8, + in_buff_size: usize, + in_pos: usize, + out_buff: *mut u8, + out_buff_size: usize, + out_start: usize, + out_end: usize, + h_pos: usize, + stage: u32, + header_buffer: [u8; FRAME_HEADER_SIZE_MAX], +} + +const BUFF_INIT: u32 = 0; +const BUFF_READ_HEADER: u32 = 1; +const BUFF_LOAD_HEADER: u32 = 2; +const BUFF_DECODE_HEADER: u32 = 3; +const BUFF_READ: u32 = 4; +const BUFF_LOAD: u32 = 5; +const BUFF_FLUSH: u32 = 6; + +unsafe fn buff_create_dctx() -> *mut ZBUFFv05_DCtx { + let zbc = libc::malloc(std::mem::size_of::()) as *mut ZBUFFv05_DCtx; + if zbc.is_null() { + return ptr::null_mut(); + } + ptr::write_bytes(zbc.cast::(), 0, std::mem::size_of::()); + (*zbc).zc = create_dctx(); + (*zbc).stage = BUFF_INIT; + zbc +} + +unsafe fn buff_free_dctx(zbc: *mut ZBUFFv05_DCtx) -> usize { + if zbc.is_null() { + return 0; + } + free_dctx((*zbc).zc); + libc::free((*zbc).in_buff.cast::()); + libc::free((*zbc).out_buff.cast::()); + libc::free(zbc.cast::()); + 0 +} + +unsafe fn buff_decompress_init(zbc: &mut ZBUFFv05_DCtx) -> usize { + zbc.stage = BUFF_READ_HEADER; + zbc.h_pos = 0; + zbc.in_pos = 0; + zbc.out_start = 0; + zbc.out_end = 0; + decompress_begin(&mut *zbc.zc) +} + +unsafe fn buff_decompress_init_dictionary( + zbc: &mut ZBUFFv05_DCtx, + dict: *const u8, + dict_size: usize, +) -> usize { + zbc.stage = BUFF_READ_HEADER; + zbc.h_pos = 0; + zbc.in_pos = 0; + zbc.out_start = 0; + zbc.out_end = 0; + decompress_begin_using_dict(&mut *zbc.zc, dict, dict_size) +} + +unsafe fn buff_limit_copy( + dst: *mut u8, + max_dst_size: usize, + src: *const u8, + src_size: usize, +) -> usize { + let length = max_dst_size.min(src_size); + if length != 0 { + ptr::copy(src, dst, length); + } + length +} + +unsafe fn buff_decompress_continue( + zbc: &mut ZBUFFv05_DCtx, + dst: *mut u8, + max_dst_size_ptr: *mut usize, + src: *const u8, + src_size_ptr: *mut usize, +) -> usize { + let istart = src as usize; + let mut ip = istart; + let iend = istart.wrapping_add(*src_size_ptr); + let ostart = dst as usize; + let mut op = ostart; + let oend = ostart.wrapping_add(*max_dst_size_ptr); + let mut not_done = true; + + while not_done { + match zbc.stage { + BUFF_INIT => return ERROR(ZstdErrorCode::InitMissing), + BUFF_READ_HEADER => { + let header_size = get_frame_params(&mut zbc.params, src, *src_size_ptr); + if ERR_isError(header_size) { + return header_size; + } + if header_size != 0 { + ptr::copy( + src, + zbc.header_buffer.as_mut_ptr().add(zbc.h_pos), + *src_size_ptr, + ); + zbc.h_pos += *src_size_ptr; + *max_dst_size_ptr = 0; + zbc.stage = BUFF_LOAD_HEADER; + return header_size - zbc.h_pos; + } + zbc.stage = BUFF_DECODE_HEADER; + } + BUFF_LOAD_HEADER => { + let header_size = buff_limit_copy( + zbc.header_buffer.as_mut_ptr().add(zbc.h_pos), + FRAME_HEADER_SIZE_MAX - zbc.h_pos, + src, + *src_size_ptr, + ); + zbc.h_pos += header_size; + ip = ip.wrapping_add(header_size); + let header_size = + get_frame_params(&mut zbc.params, zbc.header_buffer.as_ptr(), zbc.h_pos); + if ERR_isError(header_size) { + return header_size; + } + if header_size != 0 { + *max_dst_size_ptr = 0; + return header_size - zbc.h_pos; + } + zbc.stage = BUFF_DECODE_HEADER; + } + BUFF_DECODE_HEADER => { + let needed_out_size = 1usize << zbc.params.window_log; + let needed_in_size = BLOCKSIZE; + if zbc.in_buff_size < needed_in_size { + libc::free(zbc.in_buff.cast::()); + zbc.in_buff_size = needed_in_size; + zbc.in_buff = libc::malloc(needed_in_size) as *mut u8; + if zbc.in_buff.is_null() { + return ERROR(ZstdErrorCode::MemoryAllocation); + } + } + if zbc.out_buff_size < needed_out_size { + libc::free(zbc.out_buff.cast::()); + zbc.out_buff_size = needed_out_size; + zbc.out_buff = libc::malloc(needed_out_size) as *mut u8; + if zbc.out_buff.is_null() { + return ERROR(ZstdErrorCode::MemoryAllocation); + } + } + if zbc.h_pos != 0 { + ptr::copy(zbc.header_buffer.as_ptr(), zbc.in_buff, zbc.h_pos); + zbc.in_pos = zbc.h_pos; + zbc.h_pos = 0; + zbc.stage = BUFF_LOAD; + } else { + zbc.stage = BUFF_READ; + } + } + BUFF_READ => { + let needed_in_size = next_src_size_to_decompress(&*zbc.zc); + if needed_in_size == 0 { + zbc.stage = BUFF_INIT; + not_done = false; + continue; + } + if iend.wrapping_sub(ip) >= needed_in_size { + let decoded_size = decompress_continue( + &mut *zbc.zc, + zbc.out_buff.add(zbc.out_start), + zbc.out_buff_size - zbc.out_start, + ip as *const u8, + needed_in_size, + ); + if ERR_isError(decoded_size) { + return decoded_size; + } + ip = ip.wrapping_add(needed_in_size); + if decoded_size == 0 { + continue; + } + zbc.out_end = zbc.out_start + decoded_size; + zbc.stage = BUFF_FLUSH; + continue; + } + if ip == iend { + not_done = false; + continue; + } + zbc.stage = BUFF_LOAD; + } + BUFF_LOAD => { + let needed_in_size = next_src_size_to_decompress(&*zbc.zc); + let to_load = needed_in_size.wrapping_sub(zbc.in_pos); + if to_load > zbc.in_buff_size.wrapping_sub(zbc.in_pos) { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + let loaded_size = buff_limit_copy( + zbc.in_buff.add(zbc.in_pos), + to_load, + ip as *const u8, + iend.wrapping_sub(ip), + ); + ip = ip.wrapping_add(loaded_size); + zbc.in_pos += loaded_size; + if loaded_size < to_load { + not_done = false; + continue; + } + let decoded_size = decompress_continue( + &mut *zbc.zc, + zbc.out_buff.add(zbc.out_start), + zbc.out_buff_size - zbc.out_start, + zbc.in_buff, + needed_in_size, + ); + if ERR_isError(decoded_size) { + return decoded_size; + } + zbc.in_pos = 0; + if decoded_size == 0 { + zbc.stage = BUFF_READ; + continue; + } + zbc.out_end = zbc.out_start + decoded_size; + zbc.stage = BUFF_FLUSH; + } + BUFF_FLUSH => { + let to_flush_size = zbc.out_end.wrapping_sub(zbc.out_start); + let flushed_size = buff_limit_copy( + op as *mut u8, + oend.wrapping_sub(op), + zbc.out_buff.add(zbc.out_start), + to_flush_size, + ); + op = op.wrapping_add(flushed_size); + zbc.out_start += flushed_size; + if flushed_size == to_flush_size { + zbc.stage = BUFF_READ; + if zbc.out_start + BLOCKSIZE > zbc.out_buff_size { + zbc.out_start = 0; + zbc.out_end = 0; + } + } else { + not_done = false; + } + } + _ => return ERROR(ZstdErrorCode::Generic), + } + } + + *src_size_ptr = ip.wrapping_sub(istart); + *max_dst_size_ptr = op.wrapping_sub(ostart); + let mut next_src_size_hint = next_src_size_to_decompress(&*zbc.zc); + if next_src_size_hint > 3 { + next_src_size_hint = next_src_size_hint.wrapping_add(3); + } + next_src_size_hint.wrapping_sub(zbc.in_pos) +} + +#[no_mangle] +pub extern "C" fn ZSTDv05_isError(code: usize) -> c_uint { + ERR_isError(code) as c_uint +} + +#[no_mangle] +pub extern "C" fn ZSTDv05_getErrorName(code: usize) -> *const c_char { + ERR_getErrorName(code) +} + +#[no_mangle] +pub unsafe extern "C" fn ZSTDv05_decompress( + dst: *mut c_void, + max_original_size: usize, + src: *const c_void, + compressed_size: usize, +) -> usize { + let dctx = create_dctx(); + if dctx.is_null() { + return ERROR(ZstdErrorCode::MemoryAllocation); + } + let result = decompress_using_dict( + &mut *dctx, + dst.cast::(), + max_original_size, + src.cast::(), + compressed_size, + ptr::null(), + 0, + ); + free_dctx(dctx); + result +} + +#[no_mangle] +pub unsafe extern "C" fn ZSTDv05_decompressDCtx( + dctx: *mut ZSTDv05_Dctx, + dst: *mut c_void, + max_original_size: usize, + src: *const c_void, + compressed_size: usize, +) -> usize { + decompress_using_dict( + &mut *dctx, + dst.cast::(), + max_original_size, + src.cast::(), + compressed_size, + ptr::null(), + 0, + ) +} + +#[no_mangle] +pub unsafe extern "C" fn ZSTDv05_decompress_usingDict( + dctx: *mut ZSTDv05_Dctx, + dst: *mut c_void, + max_dst_size: usize, + src: *const c_void, + src_size: usize, + dict: *const c_void, + dict_size: usize, +) -> usize { + decompress_using_dict( + &mut *dctx, + dst.cast::(), + max_dst_size, + src.cast::(), + src_size, + dict.cast::(), + dict_size, + ) +} + +#[no_mangle] +pub unsafe extern "C" fn ZSTDv05_getFrameParams( + params: *mut ZstdParameters, + src: *const c_void, + src_size: usize, +) -> usize { + get_frame_params(&mut *params, src.cast::(), src_size) +} + +#[no_mangle] +pub unsafe extern "C" fn ZSTDv05_findFrameSizeInfoLegacy( + src: *const c_void, + src_size: usize, + c_size: *mut usize, + d_bound: *mut u64, +) { + find_frame_size_info(src.cast::(), src_size, c_size, d_bound); +} + +#[no_mangle] +pub unsafe extern "C" fn ZSTDv05_decompressBegin(dctx: *mut ZSTDv05_Dctx) -> usize { + decompress_begin(&mut *dctx) +} + +#[no_mangle] +pub unsafe extern "C" fn ZSTDv05_decompressBegin_usingDict( + dctx: *mut ZSTDv05_Dctx, + dict: *const c_void, + dict_size: usize, +) -> usize { + decompress_begin_using_dict(&mut *dctx, dict.cast::(), dict_size) +} + +#[no_mangle] +pub unsafe extern "C" fn ZSTDv05_copyDCtx(dst: *mut ZSTDv05_Dctx, src: *const ZSTDv05_Dctx) { + let size = std::mem::size_of::() - (BLOCKSIZE + 8 + FRAME_HEADER_SIZE_MAX); + ptr::copy_nonoverlapping(src.cast::(), dst.cast::(), size); +} + +#[no_mangle] +pub extern "C" fn ZSTDv05_sizeofDCtx() -> usize { + std::mem::size_of::() +} + +#[no_mangle] +pub unsafe extern "C" fn ZSTDv05_createDCtx() -> *mut ZSTDv05_Dctx { + create_dctx() +} + +#[no_mangle] +pub unsafe extern "C" fn ZSTDv05_freeDCtx(dctx: *mut ZSTDv05_Dctx) -> usize { + free_dctx(dctx) +} + +#[no_mangle] +pub unsafe extern "C" fn ZSTDv05_nextSrcSizeToDecompress(dctx: *mut ZSTDv05_Dctx) -> usize { + next_src_size_to_decompress(&*dctx) +} + +#[no_mangle] +pub unsafe extern "C" fn ZSTDv05_decompressContinue( + dctx: *mut ZSTDv05_Dctx, + dst: *mut c_void, + max_dst_size: usize, + src: *const c_void, + src_size: usize, +) -> usize { + decompress_continue( + &mut *dctx, + dst.cast::(), + max_dst_size, + src.cast::(), + src_size, + ) +} + +#[no_mangle] +pub unsafe extern "C" fn ZSTDv05_decompressBlock( + dctx: *mut ZSTDv05_Dctx, + dst: *mut c_void, + dst_capacity: usize, + src: *const c_void, + src_size: usize, +) -> usize { + check_continuity(&mut *dctx, dst.cast::()); + decompress_block_internal( + &mut *dctx, + dst.cast::(), + dst_capacity, + src.cast::(), + src_size, + ) +} + +#[no_mangle] +pub unsafe extern "C" fn ZSTDv05_decompress_usingPreparedDCtx( + dctx: *mut ZSTDv05_Dctx, + prepared_dctx: *const ZSTDv05_Dctx, + dst: *mut c_void, + dst_capacity: usize, + src: *const c_void, + src_size: usize, +) -> usize { + ZSTDv05_copyDCtx(dctx, prepared_dctx); + check_continuity(&mut *dctx, dst.cast::()); + decompress_continue_dctx( + &mut *dctx, + dst.cast::(), + dst_capacity, + src.cast::(), + src_size, + ) +} + +#[no_mangle] +pub extern "C" fn ZBUFFv05_isError(code: usize) -> c_uint { + ERR_isError(code) as c_uint +} + +#[no_mangle] +pub extern "C" fn ZBUFFv05_getErrorName(code: usize) -> *const c_char { + ERR_getErrorName(code) +} + +#[no_mangle] +pub extern "C" fn ZBUFFv05_recommendedDInSize() -> usize { + BLOCKSIZE + 3 +} + +#[no_mangle] +pub extern "C" fn ZBUFFv05_recommendedDOutSize() -> usize { + BLOCKSIZE +} + +#[no_mangle] +pub unsafe extern "C" fn ZBUFFv05_createDCtx() -> *mut ZBUFFv05_DCtx { + buff_create_dctx() +} + +#[no_mangle] +pub unsafe extern "C" fn ZBUFFv05_freeDCtx(dctx: *mut ZBUFFv05_DCtx) -> usize { + buff_free_dctx(dctx) +} + +#[no_mangle] +pub unsafe extern "C" fn ZBUFFv05_decompressInit(dctx: *mut ZBUFFv05_DCtx) -> usize { + buff_decompress_init(&mut *dctx) +} + +#[no_mangle] +pub unsafe extern "C" fn ZBUFFv05_decompressInitDictionary( + dctx: *mut ZBUFFv05_DCtx, + dict: *const c_void, + dict_size: usize, +) -> usize { + buff_decompress_init_dictionary(&mut *dctx, dict.cast::(), dict_size) +} + +#[no_mangle] +pub unsafe extern "C" fn ZBUFFv05_decompressContinue( + dctx: *mut ZBUFFv05_DCtx, + dst: *mut c_void, + max_dst_size_ptr: *mut usize, + src: *const c_void, + src_size_ptr: *mut usize, +) -> usize { + buff_decompress_continue( + &mut *dctx, + dst.cast::(), + max_dst_size_ptr, + src.cast::(), + src_size_ptr, + ) +} + +#[no_mangle] +pub extern "C" fn FSEv05_isError(code: usize) -> c_uint { + ERR_isError(code) as c_uint +} + +#[no_mangle] +pub extern "C" fn FSEv05_getErrorName(code: usize) -> *const c_char { + ERR_getErrorName(code) +} + +#[no_mangle] +pub unsafe extern "C" fn FSEv05_createDTable(table_log: c_uint) -> *mut u32 { + let table_log = table_log.min(FSE_TABLELOG_ABSOLUTE_MAX) as usize; + libc::malloc((1 + (1usize << table_log)) * std::mem::size_of::()) as *mut u32 +} + +#[no_mangle] +pub unsafe extern "C" fn FSEv05_freeDTable(table: *mut u32) { + libc::free(table.cast::()); +} + +#[no_mangle] +pub unsafe extern "C" fn FSEv05_readNCount( + normalized_counter: *mut i16, + max_symbol_value: *mut c_uint, + table_log: *mut c_uint, + src: *const c_void, + src_size: usize, +) -> usize { + fse_read_ncount( + &mut *(normalized_counter as *mut [i16; 256]), + &mut *max_symbol_value, + &mut *table_log, + src.cast::(), + src_size, + ) +} + +#[no_mangle] +pub unsafe extern "C" fn FSEv05_buildDTable( + table: *mut u32, + normalized_counter: *const i16, + max_symbol_value: c_uint, + table_log: c_uint, +) -> usize { + let len = 1usize << (table_log as usize).min(FSE_TABLELOG_ABSOLUTE_MAX as usize); + fse_build_dtable( + slice::from_raw_parts_mut(table, 1 + len), + &*(normalized_counter as *const [i16; 256]), + max_symbol_value, + table_log, + ) +} + +#[no_mangle] +pub unsafe extern "C" fn FSEv05_buildDTable_rle(table: *mut u32, symbol: u8) -> usize { + fse_build_dtable_rle( + slice::from_raw_parts_mut(table, 1 + (1usize << FSE_MAX_TABLELOG)), + symbol, + ) +} + +#[no_mangle] +pub unsafe extern "C" fn FSEv05_buildDTable_raw(table: *mut u32, nb_bits: c_uint) -> usize { + fse_build_dtable_raw( + slice::from_raw_parts_mut(table, 1 + (1usize << FSE_MAX_TABLELOG)), + nb_bits, + ) +} + +#[no_mangle] +pub unsafe extern "C" fn FSEv05_decompress_usingDTable( + dst: *mut c_void, + dst_capacity: usize, + src: *const c_void, + src_size: usize, + table: *const u32, +) -> usize { + fse_decompress_using_dtable( + dst.cast::(), + dst_capacity, + src.cast::(), + src_size, + slice::from_raw_parts(table, 1 + (1usize << FSE_MAX_TABLELOG)), + ) +} + +#[no_mangle] +pub unsafe extern "C" fn FSEv05_decompress( + dst: *mut c_void, + max_dst_size: usize, + src: *const c_void, + src_size: usize, +) -> usize { + fse_decompress(dst.cast::(), max_dst_size, src.cast::(), src_size) +} + +#[no_mangle] +pub extern "C" fn HUFv05_isError(code: usize) -> c_uint { + ERR_isError(code) as c_uint +} + +#[no_mangle] +pub extern "C" fn HUFv05_getErrorName(code: usize) -> *const c_char { + ERR_getErrorName(code) +} + +#[no_mangle] +pub unsafe extern "C" fn HUFv05_readDTableX2( + table: *mut u16, + src: *const c_void, + src_size: usize, +) -> usize { + huf_read_dtable_x2( + &mut *(table as *mut [u16; 1 + (1 << HUF_MAX_TABLELOG)]), + src.cast::(), + src_size, + ) +} + +#[no_mangle] +pub unsafe extern "C" fn HUFv05_readDTableX4( + table: *mut u32, + src: *const c_void, + src_size: usize, +) -> usize { + huf_read_dtable_x4( + &mut *(table as *mut [u32; 1 + (1 << HUF_MAX_TABLELOG)]), + src.cast::(), + src_size, + ) +} + +#[no_mangle] +pub unsafe extern "C" fn HUFv05_decompress1X2_usingDTable( + dst: *mut c_void, + dst_size: usize, + src: *const c_void, + src_size: usize, + table: *const u16, +) -> usize { + huf_decompress1x2_using_dtable( + dst.cast::(), + dst_size, + src.cast::(), + src_size, + &*(table as *const [u16; 1 + (1 << HUF_MAX_TABLELOG)]), + ) +} + +#[no_mangle] +pub unsafe extern "C" fn HUFv05_decompress1X2( + dst: *mut c_void, + dst_size: usize, + src: *const c_void, + src_size: usize, +) -> usize { + huf_decompress1x2(dst.cast::(), dst_size, src.cast::(), src_size) +} + +#[no_mangle] +pub unsafe extern "C" fn HUFv05_decompress4X2_usingDTable( + dst: *mut c_void, + dst_size: usize, + src: *const c_void, + src_size: usize, + table: *const u16, +) -> usize { + huf_decompress4x2_using_dtable( + dst.cast::(), + dst_size, + src.cast::(), + src_size, + &*(table as *const [u16; 1 + (1 << HUF_MAX_TABLELOG)]), + ) +} + +#[no_mangle] +pub unsafe extern "C" fn HUFv05_decompress4X2( + dst: *mut c_void, + dst_size: usize, + src: *const c_void, + src_size: usize, +) -> usize { + let mut table = [0u16; 1 + (1 << HUF_MAX_TABLELOG)]; + table[0] = HUF_MAX_TABLELOG as u16; + let header_size = huf_read_dtable_x2(&mut table, src.cast::(), src_size); + if ERR_isError(header_size) { + return header_size; + } + if header_size >= src_size { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + huf_decompress4x2_using_dtable( + dst.cast::(), + dst_size, + src.cast::().add(header_size), + src_size - header_size, + &table, + ) +} + +#[no_mangle] +pub unsafe extern "C" fn HUFv05_decompress1X4_usingDTable( + dst: *mut c_void, + dst_size: usize, + src: *const c_void, + src_size: usize, + table: *const u32, +) -> usize { + huf_decompress1x4_using_dtable( + dst.cast::(), + dst_size, + src.cast::(), + src_size, + &*(table as *const [u32; 1 + (1 << HUF_MAX_TABLELOG)]), + ) +} + +#[no_mangle] +pub unsafe extern "C" fn HUFv05_decompress1X4( + dst: *mut c_void, + dst_size: usize, + src: *const c_void, + src_size: usize, +) -> usize { + huf_decompress1x4(dst.cast::(), dst_size, src.cast::(), src_size) +} + +#[no_mangle] +pub unsafe extern "C" fn HUFv05_decompress4X4_usingDTable( + dst: *mut c_void, + dst_size: usize, + src: *const c_void, + src_size: usize, + table: *const u32, +) -> usize { + huf_decompress4x4_using_dtable( + dst.cast::(), + dst_size, + src.cast::(), + src_size, + &*(table as *const [u32; 1 + (1 << HUF_MAX_TABLELOG)]), + ) +} + +#[no_mangle] +pub unsafe extern "C" fn HUFv05_decompress4X4( + dst: *mut c_void, + dst_size: usize, + src: *const c_void, + src_size: usize, +) -> usize { + huf_decompress4x4(dst.cast::(), dst_size, src.cast::(), src_size) +} + +#[no_mangle] +pub unsafe extern "C" fn HUFv05_decompress( + dst: *mut c_void, + dst_size: usize, + src: *const c_void, + src_size: usize, +) -> usize { + huf_decompress(dst.cast::(), dst_size, src.cast::(), src_size) +} +#[cfg(test)] +mod tests { + use super::*; + + const V05_FRAME: &[u8] = &[ + 0x25, 0xB5, 0x2F, 0xFD, 0x00, 0x00, 0x00, 0xAD, 0x12, 0xB0, 0x7D, 0x1E, 0xB0, 0x01, 0x02, + 0x00, 0x00, 0x80, 0x00, 0xE8, 0x92, 0x34, 0x12, 0x97, 0xC8, 0xDF, 0xE9, 0xF3, 0xEF, 0x53, + 0xEA, 0x1D, 0x27, 0x4F, 0x0C, 0x44, 0x90, 0x0C, 0x8D, 0xF1, 0xB4, 0x89, 0x03, 0x01, 0x50, + 0x67, 0x56, 0xF5, 0x9F, 0x35, 0x84, 0x60, 0xA0, 0x60, 0x91, 0xC9, 0x0A, 0xDC, 0xAB, 0xAB, + 0xE0, 0xE2, 0x81, 0xFA, 0xCF, 0xC6, 0xBA, 0xEB, 0xA8, 0xD1, 0x40, 0x39, 0x90, 0x4C, 0x64, + 0xF8, 0xEB, 0x53, 0xE6, 0x18, 0x0B, 0x67, 0x12, 0xAD, 0xB8, 0x99, 0xB3, 0x5A, 0x6F, 0x8A, + 0xF9, 0x63, 0x0C, 0xB8, 0xFA, 0x58, 0xE7, 0xF5, 0xE6, 0xE2, 0xE3, 0x67, 0xCC, 0x5D, 0x94, + 0xC6, 0x56, 0xDC, 0x7F, 0x0C, 0x84, 0x4B, 0xA8, 0xF8, 0x63, 0x2E, 0x3E, 0x4E, 0x67, 0xCD, + 0x9E, 0xAC, 0x04, 0x1E, 0x17, 0x27, 0xE4, 0x43, 0xF6, 0xA4, 0x56, 0xE4, 0x84, 0xC7, 0x9E, + 0x34, 0x0E, 0x00, 0x00, 0x32, 0x40, 0x80, 0xA8, 0x00, 0x01, 0x49, 0x81, 0xE0, 0x3C, 0x01, + 0x29, 0x1D, 0x00, 0x87, 0xCE, 0x80, 0x75, 0x08, 0x80, 0x72, 0x24, 0x00, 0x7B, 0x52, 0x00, + 0x94, 0x00, 0x20, 0xCC, 0x01, 0x86, 0xD2, 0x00, 0x81, 0x09, 0x83, 0xC1, 0x34, 0xA0, 0x88, + 0x01, 0xC0, 0x00, 0x00, + ]; + + const EXPECTED: &[u8] = + b"snowden is snowed in / he's now then in his snow den / when does the snow end?\n\ +goodbye little dog / you dug some holes in your day / they'll be hard to fill.\n\ +when life shuts a door, / just open it. it\xE2\x80\x99s a door. / that is how doors work.\n"; + + unsafe fn decode(frame: &[u8], capacity: usize) -> Result, usize> { + let mut output = vec![0u8; capacity]; + let size = ZSTDv05_decompress( + output.as_mut_ptr().cast::(), + output.len(), + frame.as_ptr().cast::(), + frame.len(), + ); + if ZSTDv05_isError(size) != 0 { + Err(size) + } else { + output.truncate(size); + Ok(output) + } + } + + #[test] + fn decodes_repository_v05_frame() { + unsafe { + assert_eq!(decode(V05_FRAME, EXPECTED.len()).unwrap(), EXPECTED); + } + } + + #[test] + fn reports_frame_params_and_size() { + unsafe { + let mut params = ZstdParameters { + src_size: 99, + window_log: 99, + content_log: 99, + hash_log: 99, + search_log: 99, + search_length: 99, + target_length: 99, + strategy: 99, + }; + assert_eq!( + get_frame_params(&mut params, V05_FRAME.as_ptr(), V05_FRAME.len()), + 0 + ); + assert_eq!(params.window_log, 11); + + let mut c_size = 0; + let mut bound = 0; + ZSTDv05_findFrameSizeInfoLegacy( + V05_FRAME.as_ptr().cast::(), + V05_FRAME.len(), + &mut c_size, + &mut bound, + ); + assert_eq!(c_size, V05_FRAME.len()); + assert_eq!(bound, BLOCKSIZE as u64); + } + } + + #[test] + fn reports_frozen_error_behavior() { + unsafe { + let mut bad = V05_FRAME.to_vec(); + bad[0] ^= 1; + assert_eq!( + decode(&bad, EXPECTED.len()).unwrap_err(), + ERROR(ZstdErrorCode::PrefixUnknown) + ); + assert_eq!( + decode(&V05_FRAME[..V05_FRAME.len() - 1], EXPECTED.len()).unwrap_err(), + ERROR(ZstdErrorCode::SrcSizeWrong) + ); + assert_eq!( + decode(V05_FRAME, EXPECTED.len() - 1).unwrap_err(), + ERROR(ZstdErrorCode::DstSizeTooSmall) + ); + } + } + + #[test] + fn direct_streaming_matches_one_shot() { + let mut output = vec![0u8; EXPECTED.len()]; + let mut input_offset = 0; + let mut output_offset = 0; + unsafe { + let dctx = ZSTDv05_createDCtx(); + assert!(!dctx.is_null()); + loop { + let needed = ZSTDv05_nextSrcSizeToDecompress(dctx); + if needed == 0 { + break; + } + assert!(input_offset + needed <= V05_FRAME.len()); + let produced = ZSTDv05_decompressContinue( + dctx, + output.as_mut_ptr().add(output_offset).cast::(), + output.len() - output_offset, + V05_FRAME.as_ptr().add(input_offset).cast::(), + needed, + ); + assert_eq!(ZSTDv05_isError(produced), 0); + input_offset += needed; + output_offset += produced; + } + assert_eq!(ZSTDv05_freeDCtx(dctx), 0); + } + assert_eq!(input_offset, V05_FRAME.len()); + assert_eq!(output_offset, EXPECTED.len()); + assert_eq!(output, EXPECTED); + } + + #[test] + fn buffered_streaming_handles_small_input_and_output() { + let mut output = vec![0u8; EXPECTED.len()]; + let mut input_offset = 0; + let mut output_offset = 0; + unsafe { + let dctx = ZBUFFv05_createDCtx(); + assert!(!dctx.is_null()); + assert_eq!(ZBUFFv05_decompressInit(dctx), 0); + while input_offset < V05_FRAME.len() || output_offset < EXPECTED.len() { + let input_len = (V05_FRAME.len() - input_offset).min(2); + let mut src_size = input_len; + let output_len = (EXPECTED.len() - output_offset).min(7); + let mut dst_size = output_len; + let hint = ZBUFFv05_decompressContinue( + dctx, + output.as_mut_ptr().add(output_offset).cast::(), + &mut dst_size, + V05_FRAME.as_ptr().add(input_offset).cast::(), + &mut src_size, + ); + assert_eq!(ZBUFFv05_isError(hint), 0); + input_offset += src_size; + output_offset += dst_size; + if src_size == 0 && dst_size == 0 { + panic!("buffered decoder made no progress"); + } + } + assert_eq!(ZBUFFv05_freeDCtx(dctx), 0); + assert_eq!(ZBUFFv05_freeDCtx(ptr::null_mut()), 0); + } + assert_eq!(input_offset, V05_FRAME.len()); + assert_eq!(&output, EXPECTED); + } +} diff --git a/rust/src/legacy/zstd_v06.rs b/rust/src/legacy/zstd_v06.rs new file mode 100644 index 000000000..021adfbd5 --- /dev/null +++ b/rust/src/legacy/zstd_v06.rs @@ -0,0 +1,3754 @@ +#![allow(non_snake_case)] + +//! Frozen decoder for the zstd v0.6 format. +//! +//! `lib/legacy/zstd_v06.c` is an old, self-contained decoder. This module +//! keeps that boundary: it owns its FSE, bit-stream, and Huffman state rather +//! than depending on the current entropy implementations. The public entry +//! points below retain the C ABI and the context is deliberately malloc/free +//! allocated so C callers can continue to own an opaque `ZSTDv06_Dctx`. + +use crate::errors::{ERR_getErrorName, ERR_isError, ZstdErrorCode, ERROR}; +use std::os::raw::{c_char, c_uint, c_void}; +use std::ptr; +use std::slice; + +const ZSTD_MAGIC_NUMBER: u32 = 0xFD2F_B526; +const ZSTD_CONTENTSIZE_ERROR: u64 = u64::MAX - 1; + +const BLOCKSIZE: usize = 128 * 1024; +const MIN_SEQUENCES_SIZE: usize = 1; +const MIN_CBLOCK_SIZE: usize = 1 + 1 + MIN_SEQUENCES_SIZE; +const MINMATCH: usize = 3; +const MAX_ML: u32 = 52; +const MAX_LL: u32 = 35; +const MAX_OFF: u32 = 28; +const ML_FSE_LOG: u32 = 9; +const LL_FSE_LOG: u32 = 9; +const OFF_FSE_LOG: u32 = 8; + +const REPCODE_NUM: usize = 3; +const REPCODE_STARTVALUE: usize = 1; +const REPCODE_MOVE: usize = REPCODE_NUM - 1; +const LONG_NB_SEQ: i32 = 0x7f00; + +const IS_HUF: u8 = 0; +const IS_PCH: u8 = 1; +const IS_RAW: u8 = 2; +const IS_RLE: u8 = 3; + +const FSE_ENCODING_RAW: u32 = 0; +const FSE_ENCODING_RLE: u32 = 1; +const FSE_ENCODING_STATIC: u32 = 2; +const FSE_ENCODING_DYNAMIC: u32 = 3; + +const ZSTD_DICT_MAGIC: u32 = 0xec30_a436; +const ZSTD_WINDOWLOG_ABSOLUTE_MIN: u32 = 12; +const FRAME_HEADER_SIZE_MIN: usize = 5; +const FRAME_HEADER_SIZE_MAX: usize = 13; +const BLOCK_HEADER_SIZE: usize = 3; +const WILDCOPY_OVERLENGTH: usize = 8; + +const FSE_MAX_MEMORY_USAGE: u32 = 14; +const FSE_MAX_SYMBOL_VALUE: u32 = 255; +const FSE_MAX_TABLELOG: u32 = FSE_MAX_MEMORY_USAGE - 2; +const FSE_MIN_TABLELOG: u32 = 5; +const FSE_TABLELOG_ABSOLUTE_MAX: u32 = 15; + +const HUF_MAX_SYMBOL_VALUE: usize = 255; +const HUF_MAX_TABLELOG: usize = 12; +const HUF_ABSOLUTE_MAX_TABLELOG: usize = 16; + +const BT_COMPRESSED: u32 = 0; +const BT_RAW: u32 = 1; +const BT_RLE: u32 = 2; +const BT_END: u32 = 3; + +const DSTREAM_UNFINISHED: u32 = 0; +const DSTREAM_END_OF_BUFFER: u32 = 1; +const DSTREAM_COMPLETED: u32 = 2; +const DSTREAM_TOO_FAR: u32 = 3; + +const USIZE_BITS: u32 = usize::BITS; + +const LL_BITS_TABLE: [u32; MAX_LL as usize + 1] = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, +]; +const ML_BITS_TABLE: [u32; MAX_ML as usize + 1] = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, +]; +const OF_DEFAULT_NORM: [i16; MAX_OFF as usize + 1] = [ + 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, +]; +const LL_DEFAULT_NORM: [i16; MAX_LL as usize + 1] = [ + 4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1, + -1, -1, -1, -1, +]; +const ML_DEFAULT_NORM: [i16; MAX_ML as usize + 1] = [ + 1, 4, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, +]; +const LL_DEFAULT_LOG: u32 = 6; +const ML_DEFAULT_LOG: u32 = 6; +const OF_DEFAULT_LOG: u32 = 5; + +#[repr(C)] +#[derive(Clone, Copy)] +struct FseDecode { + new_state: u16, + symbol: u8, + nb_bits: u8, +} + +#[repr(C)] +struct FseDTableHeader { + table_log: u16, + fast_mode: u16, +} + +#[derive(Clone, Copy)] +struct DStream { + bit_container: usize, + bits_consumed: u32, + ptr: *const u8, + start: *const u8, +} + +#[derive(Clone, Copy)] +struct FseDState { + state: usize, + table: *const FseDecode, +} + +#[inline] +fn highbit32(value: u32) -> u32 { + value.leading_zeros() ^ 31 +} + +#[inline] +unsafe fn write_le16(dst: *mut u8, value: u16) { + let bytes = value.to_le_bytes(); + ptr::copy_nonoverlapping(bytes.as_ptr(), dst, 2); +} + +#[inline] +unsafe fn zstd_copy8(dst: *mut u8, src: *const u8) { + ptr::copy(src, dst, 8); +} + +#[inline] +unsafe fn zstd_copy4(dst: *mut u8, src: *const u8) { + ptr::copy(src, dst, 4); +} + +unsafe fn zstd_wildcopy(dst: *mut u8, src: *const u8, length: isize) { + let mut op = dst; + let mut ip = src; + let end = if length >= 0 { + (dst as usize).wrapping_add(length as usize) + } else { + (dst as usize).wrapping_sub(length.wrapping_neg() as usize) + }; + loop { + zstd_copy8(op, ip); + op = op.add(8); + ip = ip.add(8); + if (op as usize) >= end { + break; + } + } +} + +#[inline] +unsafe fn read_le16(ptr: *const u8) -> u16 { + u16::from_le_bytes(std::ptr::read_unaligned(ptr as *const [u8; 2])) +} + +#[inline] +unsafe fn read_le32(ptr: *const u8) -> u32 { + u32::from_le_bytes(std::ptr::read_unaligned(ptr as *const [u8; 4])) +} + +#[inline] +unsafe fn read_le64(ptr: *const u8) -> u64 { + u64::from_le_bytes(std::ptr::read_unaligned(ptr as *const [u8; 8])) +} + +#[inline] +unsafe fn read_le_size(ptr: *const u8) -> usize { + if std::mem::size_of::() == 4 { + read_le32(ptr) as usize + } else { + u64::from_le_bytes(std::ptr::read_unaligned(ptr as *const [u8; 8])) as usize + } +} + +/* ****************************************** + * Backward bit stream (the v0.6 snapshot) + ********************************************/ + +unsafe fn init_dstream(stream: &mut DStream, src: *const u8, src_size: usize) -> usize { + let word = std::mem::size_of::(); + if src_size == 0 { + *stream = DStream { + bit_container: 0, + bits_consumed: 0, + ptr: ptr::null(), + start: ptr::null(), + }; + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + + stream.start = src; + if src_size >= word { + stream.ptr = src.add(src_size - word); + stream.bit_container = read_le_size(stream.ptr); + let end_byte = *src.add(src_size - 1) as u32; + if end_byte == 0 { + return ERROR(ZstdErrorCode::Generic); + } + stream.bits_consumed = 8 - highbit32(end_byte); + } else { + stream.ptr = src; + stream.bit_container = *src as usize; + if src_size >= 7 { + stream.bit_container += (*src.add(6) as usize) << (USIZE_BITS as usize - 16); + } + if src_size >= 6 { + stream.bit_container += (*src.add(5) as usize) << (USIZE_BITS as usize - 24); + } + if src_size >= 5 { + stream.bit_container += (*src.add(4) as usize) << (USIZE_BITS as usize - 32); + } + if src_size >= 4 { + stream.bit_container += (*src.add(3) as usize) << 24; + } + if src_size >= 3 { + stream.bit_container += (*src.add(2) as usize) << 16; + } + if src_size >= 2 { + stream.bit_container += (*src.add(1) as usize) << 8; + } + let end_byte = *src.add(src_size - 1) as u32; + if end_byte == 0 { + return ERROR(ZstdErrorCode::Generic); + } + stream.bits_consumed = 8 - highbit32(end_byte); + stream.bits_consumed += ((word - src_size) * 8) as u32; + } + src_size +} + +#[inline] +unsafe fn look_bits(stream: &DStream, nb_bits: u32) -> usize { + let mask = USIZE_BITS - 1; + ((stream.bit_container << (stream.bits_consumed & mask)) >> 1) + >> (mask.wrapping_sub(nb_bits) & mask) +} + +#[inline] +unsafe fn look_bits_fast(stream: &DStream, nb_bits: u32) -> usize { + let mask = USIZE_BITS - 1; + (stream.bit_container << (stream.bits_consumed & mask)) + >> ((mask + 1).wrapping_sub(nb_bits) & mask) +} + +#[inline] +fn skip_bits(stream: &mut DStream, nb_bits: u32) { + stream.bits_consumed = stream.bits_consumed.wrapping_add(nb_bits); +} + +#[inline] +unsafe fn read_bits(stream: &mut DStream, nb_bits: u32) -> usize { + let value = look_bits(stream, nb_bits); + skip_bits(stream, nb_bits); + value +} + +#[inline] +unsafe fn read_bits_fast(stream: &mut DStream, nb_bits: u32) -> usize { + let value = look_bits_fast(stream, nb_bits); + skip_bits(stream, nb_bits); + value +} + +unsafe fn reload_dstream(stream: &mut DStream) -> u32 { + let word = std::mem::size_of::(); + if stream.bits_consumed > (word * 8) as u32 { + return DSTREAM_TOO_FAR; + } + if (stream.ptr as usize) >= (stream.start as usize).wrapping_add(word) { + stream.ptr = stream.ptr.sub((stream.bits_consumed >> 3) as usize); + stream.bits_consumed &= 7; + stream.bit_container = read_le_size(stream.ptr); + return DSTREAM_UNFINISHED; + } + if stream.ptr == stream.start { + if stream.bits_consumed < (word * 8) as u32 { + return DSTREAM_END_OF_BUFFER; + } + return DSTREAM_COMPLETED; + } + + let mut nb_bytes = stream.bits_consumed >> 3; + let mut result = DSTREAM_UNFINISHED; + if (stream.ptr as usize).wrapping_sub(nb_bytes as usize) < stream.start as usize { + nb_bytes = (stream.ptr as usize - stream.start as usize) as u32; + result = DSTREAM_END_OF_BUFFER; + } + stream.ptr = stream.ptr.sub(nb_bytes as usize); + stream.bits_consumed -= nb_bytes * 8; + stream.bit_container = read_le_size(stream.ptr); + result +} + +#[inline] +fn end_of_dstream(stream: &DStream) -> bool { + stream.ptr == stream.start && stream.bits_consumed == USIZE_BITS +} + +/* ****************************************** + * FSE decoding + ********************************************/ + +#[inline] +fn fse_table_step(table_size: u32) -> u32 { + (table_size >> 1) + (table_size >> 3) + 3 +} + +#[allow(clippy::needless_range_loop)] +unsafe fn fse_build_dtable( + dt: &mut [u32], + normalized_counter: &[i16], + max_symbol_value: u32, + table_log: u32, +) -> usize { + if max_symbol_value > FSE_MAX_SYMBOL_VALUE { + return ERROR(ZstdErrorCode::MaxSymbolValueTooLarge); + } + if table_log > FSE_MAX_TABLELOG { + return ERROR(ZstdErrorCode::TableLogTooLarge); + } + + let table_size = 1u32 << table_log; + let table_mask = table_size - 1; + let step = fse_table_step(table_size); + let mut symbol_next = [0u16; 256]; + let table_header = dt.as_mut_ptr() as *mut FseDTableHeader; + let table_decode = dt.as_mut_ptr().add(1) as *mut FseDecode; + let mut position = 0u32; + let mut high_threshold = table_size - 1; + let large_limit = (1i32 << (table_log - 1)) as i16; + let mut no_large = 1u16; + + (*table_header).table_log = table_log as u16; + for symbol in 0..=max_symbol_value as usize { + let count = normalized_counter[symbol]; + if count == -1 { + (*table_decode.add(high_threshold as usize)).symbol = symbol as u8; + high_threshold = high_threshold.wrapping_sub(1); + symbol_next[symbol] = 1; + } else { + if count >= large_limit { + no_large = 0; + } + symbol_next[symbol] = count as u16; + } + } + + for symbol in 0..=max_symbol_value as usize { + let count = normalized_counter[symbol]; + for _ in 0..count.max(0) { + (*table_decode.add(position as usize)).symbol = symbol as u8; + position = (position + step) & table_mask; + while position > high_threshold { + position = (position + step) & table_mask; + } + } + } + if position != 0 { + return ERROR(ZstdErrorCode::Generic); + } + + for index in 0..table_size as usize { + let symbol = (*table_decode.add(index)).symbol as usize; + let next_state = symbol_next[symbol]; + symbol_next[symbol] = symbol_next[symbol].wrapping_add(1); + let nb_bits = (table_log - highbit32(next_state as u32)) as u8; + (*table_decode.add(index)).nb_bits = nb_bits; + (*table_decode.add(index)).new_state = + (((next_state as u32) << nb_bits).wrapping_sub(table_size)) as u16; + } + (*table_header).fast_mode = no_large; + 0 +} + +unsafe fn fse_read_ncount( + normalized_counter: &mut [i16; 256], + max_sv: &mut u32, + table_log: &mut u32, + header: *const u8, + header_size: usize, +) -> usize { + if header_size < 4 { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + let start = header as usize; + let end = start.wrapping_add(header_size); + let mut ip = header; + let mut char_num = 0u32; + let mut previous_zero = false; + let mut bit_stream = read_le32(ip); + let mut nb_bits = ((bit_stream & 0xF) + FSE_MIN_TABLELOG) as i32; + if nb_bits > FSE_TABLELOG_ABSOLUTE_MAX as i32 { + return ERROR(ZstdErrorCode::TableLogTooLarge); + } + bit_stream >>= 4; + let mut bit_count = 4i32; + *table_log = nb_bits as u32; + let mut remaining = (1i32 << nb_bits) + 1; + let mut threshold = 1i32 << nb_bits; + nb_bits += 1; + + while remaining > 1 && char_num <= *max_sv { + if previous_zero { + let mut n0 = char_num; + while bit_stream & 0xFFFF == 0xFFFF { + n0 += 24; + if (ip as usize) < end.wrapping_sub(5) { + ip = ip.add(2); + bit_stream = read_le32(ip) >> bit_count; + } else { + bit_stream >>= 16; + bit_count += 16; + } + } + while bit_stream & 3 == 3 { + n0 += 3; + bit_stream >>= 2; + bit_count += 2; + } + n0 += bit_stream & 3; + bit_count += 2; + if n0 > *max_sv { + return ERROR(ZstdErrorCode::MaxSymbolValueTooSmall); + } + while char_num < n0 { + normalized_counter[char_num as usize] = 0; + char_num += 1; + } + if (ip as usize) <= end.wrapping_sub(7) + || (ip as usize).wrapping_add((bit_count >> 3) as usize) <= end.wrapping_sub(4) + { + ip = ip.add((bit_count >> 3) as usize); + bit_count &= 7; + bit_stream = read_le32(ip) >> bit_count; + } else { + bit_stream >>= 2; + } + } + + let max = ((2 * threshold - 1) - remaining) as i16; + let mut count: i16; + if (bit_stream & (threshold - 1) as u32) < max as i32 as u32 { + count = (bit_stream & (threshold - 1) as u32) as u16 as i16; + bit_count += nb_bits - 1; + } else { + count = (bit_stream & (2 * threshold - 1) as u32) as u16 as i16; + if count as i32 >= threshold { + count = (count as i32 - max as i32) as i16; + } + bit_count += nb_bits; + } + count = count.wrapping_sub(1); + remaining -= (count as i32).abs(); + normalized_counter[char_num as usize] = count; + char_num += 1; + previous_zero = count == 0; + while remaining < threshold { + nb_bits -= 1; + threshold >>= 1; + } + + if (ip as usize) <= end.wrapping_sub(7) + || (ip as usize).wrapping_add((bit_count >> 3) as usize) <= end.wrapping_sub(4) + { + ip = ip.add((bit_count >> 3) as usize); + bit_count &= 7; + } else { + bit_count -= (8 * (end.wrapping_sub(4) as isize - ip as usize as isize)) as i32; + ip = (end - 4) as *const u8; + } + bit_stream = read_le32(ip) >> (bit_count & 31); + } + + if remaining != 1 { + return ERROR(ZstdErrorCode::Generic); + } + *max_sv = char_num - 1; + ip = ip.add(((bit_count + 7) >> 3) as usize); + if (ip as usize).wrapping_sub(start) > header_size { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + (ip as usize).wrapping_sub(start) +} + +unsafe fn fse_build_dtable_rle(dt: &mut [u32], symbol: u8) -> usize { + let header = dt.as_mut_ptr() as *mut FseDTableHeader; + let cell = dt.as_mut_ptr().add(1) as *mut FseDecode; + (*header).table_log = 0; + (*header).fast_mode = 0; + (*cell).new_state = 0; + (*cell).symbol = symbol; + (*cell).nb_bits = 0; + 0 +} + +unsafe fn fse_build_dtable_raw(dt: &mut [u32], nb_bits: u32) -> usize { + if nb_bits < 1 { + return ERROR(ZstdErrorCode::Generic); + } + let header = dt.as_mut_ptr() as *mut FseDTableHeader; + let cells = dt.as_mut_ptr().add(1) as *mut FseDecode; + let table_size = 1u32 << nb_bits; + (*header).table_log = nb_bits as u16; + (*header).fast_mode = 1; + for symbol in 0..table_size { + let cell = cells.add(symbol as usize); + (*cell).new_state = 0; + (*cell).symbol = symbol as u8; + (*cell).nb_bits = nb_bits as u8; + } + 0 +} + +unsafe fn fse_init_dstate(state: &mut FseDState, stream: &mut DStream, dt: *const u32) { + let header = dt as *const FseDTableHeader; + state.state = read_bits(stream, (*header).table_log as u32); + reload_dstream(stream); + state.table = dt.add(1) as *const FseDecode; +} + +#[inline] +unsafe fn fse_peek_symbol(state: &FseDState) -> u8 { + (*state.table.add(state.state)).symbol +} + +#[inline] +unsafe fn fse_update_state(state: &mut FseDState, stream: &mut DStream) { + let info = *state.table.add(state.state); + let low_bits = read_bits(stream, info.nb_bits as u32); + state.state = (info.new_state as usize).wrapping_add(low_bits); +} + +#[inline] +unsafe fn fse_decode_symbol(state: &mut FseDState, stream: &mut DStream, fast: bool) -> u8 { + let info = *state.table.add(state.state); + let low_bits = if fast { + read_bits_fast(stream, info.nb_bits as u32) + } else { + read_bits(stream, info.nb_bits as u32) + }; + state.state = (info.new_state as usize).wrapping_add(low_bits); + info.symbol +} + +unsafe fn fse_decompress_using_dtable( + dst: *mut u8, + max_dst_size: usize, + c_src: *const u8, + c_src_size: usize, + dt: &[u32], +) -> usize { + let header = &*(dt.as_ptr() as *const FseDTableHeader); + let fast = header.fast_mode != 0; + let start = dst; + let end_addr = (dst as usize).wrapping_add(max_dst_size); + let limit_addr = end_addr.wrapping_sub(3); + let mut op = dst; + let mut stream = DStream { + bit_container: 0, + bits_consumed: 0, + ptr: ptr::null(), + start: ptr::null(), + }; + let mut state1 = FseDState { + state: 0, + table: ptr::null(), + }; + let mut state2 = state1; + let error = init_dstream(&mut stream, c_src, c_src_size); + if ERR_isError(error) { + return error; + } + fse_init_dstate(&mut state1, &mut stream, dt.as_ptr()); + fse_init_dstate(&mut state2, &mut stream, dt.as_ptr()); + + const RELOAD_2: bool = FSE_MAX_TABLELOG * 2 + 7 > USIZE_BITS; + const RELOAD_4: bool = FSE_MAX_TABLELOG * 4 + 7 > USIZE_BITS; + while reload_dstream(&mut stream) == DSTREAM_UNFINISHED && (op as usize) < limit_addr { + *op = fse_decode_symbol(&mut state1, &mut stream, fast); + if RELOAD_2 { + reload_dstream(&mut stream); + } + *op.add(1) = fse_decode_symbol(&mut state2, &mut stream, fast); + if RELOAD_4 && reload_dstream(&mut stream) > DSTREAM_UNFINISHED { + op = op.add(2); + break; + } + *op.add(2) = fse_decode_symbol(&mut state1, &mut stream, fast); + if RELOAD_2 { + reload_dstream(&mut stream); + } + *op.add(3) = fse_decode_symbol(&mut state2, &mut stream, fast); + op = op.add(4); + } + + /* The v0.6 decoder's tail deliberately decodes through the end marker. + * The overflow reload after each state pair is the termination test. */ + loop { + if (op as usize) > end_addr.wrapping_sub(2) { + return ERROR(ZstdErrorCode::DstSizeTooSmall); + } + *op = fse_decode_symbol(&mut state1, &mut stream, fast); + op = op.add(1); + + if reload_dstream(&mut stream) == DSTREAM_TOO_FAR { + *op = fse_decode_symbol(&mut state2, &mut stream, fast); + op = op.add(1); + break; + } + + if (op as usize) > end_addr.wrapping_sub(2) { + return ERROR(ZstdErrorCode::DstSizeTooSmall); + } + *op = fse_decode_symbol(&mut state2, &mut stream, fast); + op = op.add(1); + + if reload_dstream(&mut stream) == DSTREAM_TOO_FAR { + *op = fse_decode_symbol(&mut state1, &mut stream, fast); + op = op.add(1); + break; + } + } + + (op as usize) - (start as usize) +} + +unsafe fn fse_decompress( + dst: *mut u8, + max_dst_size: usize, + c_src: *const u8, + c_src_size: usize, +) -> usize { + if c_src_size < 2 { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + let mut counters = [0i16; 256]; + let mut max_symbol = FSE_MAX_SYMBOL_VALUE; + let mut table_log = 0; + let header_size = fse_read_ncount( + &mut counters, + &mut max_symbol, + &mut table_log, + c_src, + c_src_size, + ); + if ERR_isError(header_size) { + return header_size; + } + if header_size >= c_src_size { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + let mut table = vec![0u32; 1 + (1usize << FSE_MAX_TABLELOG)]; + let error = fse_build_dtable(&mut table, &counters, max_symbol, table_log); + if ERR_isError(error) { + return error; + } + fse_decompress_using_dtable( + dst, + max_dst_size, + c_src.add(header_size), + c_src_size - header_size, + &table, + ) +} + +/* ****************************************** + * Huffman decoding + ********************************************/ + +#[repr(C)] +#[derive(Clone, Copy)] +struct HufDEltX2 { + byte: u8, + nb_bits: u8, +} + +#[allow(clippy::manual_div_ceil)] +unsafe fn huf_read_stats( + huff_weight: &mut [u8; HUF_MAX_SYMBOL_VALUE + 1], + rank_stats: &mut [u32; HUF_ABSOLUTE_MAX_TABLELOG + 1], + nb_symbols: &mut u32, + table_log: &mut u32, + src: *const u8, + src_size: usize, +) -> usize { + if src_size == 0 { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + let mut i_size = *src as usize; + let o_size: usize; + if i_size >= 128 { + if i_size >= 242 { + const RLE_LENGTHS: [usize; 14] = [1, 2, 3, 4, 7, 8, 15, 16, 31, 32, 63, 64, 127, 128]; + let index = i_size - 242; + if index >= RLE_LENGTHS.len() { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + o_size = RLE_LENGTHS[index]; + huff_weight.fill(1); + i_size = 0; + } else { + o_size = i_size - 127; + i_size = (o_size + 1) / 2; + if i_size + 1 > src_size { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + if o_size >= huff_weight.len() { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + let weights = src.add(1); + let mut n = 0; + while n < o_size { + huff_weight[n] = *weights.add(n / 2) >> 4; + if n + 1 < huff_weight.len() { + huff_weight[n + 1] = *weights.add(n / 2) & 15; + } + n += 2; + } + } + } else { + if i_size + 1 > src_size { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + let decoded = fse_decompress( + huff_weight.as_mut_ptr(), + huff_weight.len() - 1, + src.add(1), + i_size, + ); + if ERR_isError(decoded) { + return decoded; + } + o_size = decoded; + } + + rank_stats.fill(0); + let mut weight_total = 0u32; + for &weight in huff_weight.iter().take(o_size) { + if weight as usize >= HUF_ABSOLUTE_MAX_TABLELOG { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + rank_stats[weight as usize] += 1; + weight_total += (1u32 << weight) >> 1; + } + if weight_total == 0 { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + let calculated_log = highbit32(weight_total) + 1; + if calculated_log as usize > HUF_ABSOLUTE_MAX_TABLELOG { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + let total = 1u32 << calculated_log; + let rest = total - weight_total; + if rest == 0 || (1u32 << highbit32(rest)) != rest { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + let last_weight = highbit32(rest) + 1; + huff_weight[o_size] = last_weight as u8; + rank_stats[last_weight as usize] += 1; + if rank_stats[1] < 2 || (rank_stats[1] & 1) != 0 { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + *nb_symbols = (o_size + 1) as u32; + *table_log = calculated_log; + i_size + 1 +} + +#[allow(clippy::needless_range_loop)] +unsafe fn huf_read_dtable_x2( + dtable: &mut [u16; 1 + (1 << HUF_MAX_TABLELOG)], + src: *const u8, + src_size: usize, +) -> usize { + let mut huff_weight = [0u8; HUF_MAX_SYMBOL_VALUE + 1]; + let mut rank_val = [0u32; HUF_ABSOLUTE_MAX_TABLELOG + 1]; + let mut nb_symbols = 0u32; + let mut table_log = 0u32; + let i_size = huf_read_stats( + &mut huff_weight, + &mut rank_val, + &mut nb_symbols, + &mut table_log, + src, + src_size, + ); + if ERR_isError(i_size) { + return i_size; + } + if table_log as usize > dtable[0] as usize { + return ERROR(ZstdErrorCode::TableLogTooLarge); + } + dtable[0] = table_log as u16; + + let mut next_rank_start = 0u32; + for weight in 1..=table_log as usize { + let current = next_rank_start; + next_rank_start += rank_val[weight] << (weight - 1); + rank_val[weight] = current; + } + let cells = dtable.as_mut_ptr().add(1) as *mut HufDEltX2; + for (symbol, &weight) in huff_weight.iter().enumerate().take(nb_symbols as usize) { + let weight = weight as usize; + let length = (1u32 << weight) >> 1; + let entry = HufDEltX2 { + byte: symbol as u8, + nb_bits: (table_log + 1 - weight as u32) as u8, + }; + for index in rank_val[weight]..rank_val[weight] + length { + *cells.add(index as usize) = entry; + } + rank_val[weight] += length; + } + i_size +} + +#[inline] +unsafe fn huf_decode_symbol(stream: &mut DStream, table: *const HufDEltX2, table_log: u32) -> u8 { + let entry = *table.add(look_bits_fast(stream, table_log)); + skip_bits(stream, entry.nb_bits as u32); + entry.byte +} + +unsafe fn huf_decode_stream( + dst: *mut u8, + dst_size: usize, + stream: &mut DStream, + table: *const HufDEltX2, + table_log: u32, +) -> usize { + let start = dst; + let end = (dst as usize).wrapping_add(dst_size); + let mut op = dst as usize; + + while reload_dstream(stream) == DSTREAM_UNFINISHED && op <= end.wrapping_sub(4) { + if USIZE_BITS == 64 { + *(op as *mut u8) = huf_decode_symbol(stream, table, table_log); + op += 1; + } + if USIZE_BITS == 64 || HUF_MAX_TABLELOG <= 12 { + *(op as *mut u8) = huf_decode_symbol(stream, table, table_log); + op += 1; + } + if USIZE_BITS == 64 { + *(op as *mut u8) = huf_decode_symbol(stream, table, table_log); + op += 1; + } + *(op as *mut u8) = huf_decode_symbol(stream, table, table_log); + op += 1; + } + + while reload_dstream(stream) == DSTREAM_UNFINISHED && op < end { + *(op as *mut u8) = huf_decode_symbol(stream, table, table_log); + op += 1; + } + + while op < end { + *(op as *mut u8) = huf_decode_symbol(stream, table, table_log); + op += 1; + } + + op.wrapping_sub(start as usize) +} + +unsafe fn huf_decompress4x2_using_dtable( + dst: *mut u8, + dst_size: usize, + c_src: *const u8, + c_src_size: usize, + dtable: &[u16; 1 + (1 << HUF_MAX_TABLELOG)], +) -> usize { + if c_src_size < 10 { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + let length1 = read_le16(c_src) as usize; + let length2 = read_le16(c_src.add(2)) as usize; + let length3 = read_le16(c_src.add(4)) as usize; + let payload = length1 + .checked_add(length2) + .and_then(|v| v.checked_add(length3)) + .and_then(|v| v.checked_add(6)); + let payload = match payload { + Some(value) if value <= c_src_size => value, + _ => return ERROR(ZstdErrorCode::CorruptionDetected), + }; + let length4 = c_src_size - payload; + let stream1 = c_src.add(6); + let stream2 = stream1.add(length1); + let stream3 = stream2.add(length2); + let stream4 = stream3.add(length3); + let segment = dst_size.div_ceil(4); + let starts = [ + dst, + dst.add(segment), + dst.add(segment * 2), + dst.add(segment * 3), + ]; + let sizes = [ + segment.min(dst_size), + segment.min(dst_size.saturating_sub(segment)), + segment.min(dst_size.saturating_sub(segment * 2)), + dst_size.saturating_sub(segment * 3), + ]; + let lengths = [length1, length2, length3, length4]; + let sources = [stream1, stream2, stream3, stream4]; + let table = dtable.as_ptr().add(1) as *const HufDEltX2; + let table_log = dtable[0] as u32; + for index in 0..4 { + let mut stream = DStream { + bit_container: 0, + bits_consumed: 0, + ptr: ptr::null(), + start: ptr::null(), + }; + let error = init_dstream(&mut stream, sources[index], lengths[index]); + if ERR_isError(error) { + return error; + } + let decoded = huf_decode_stream(starts[index], sizes[index], &mut stream, table, table_log); + if ERR_isError(decoded) || !end_of_dstream(&stream) { + return if ERR_isError(decoded) { + decoded + } else { + ERROR(ZstdErrorCode::CorruptionDetected) + }; + } + } + dst_size +} + +unsafe fn huf_decompress1x2_using_dtable( + dst: *mut u8, + dst_size: usize, + c_src: *const u8, + c_src_size: usize, + dtable: &[u16; 1 + (1 << HUF_MAX_TABLELOG)], +) -> usize { + let stream = DStream { + bit_container: 0, + bits_consumed: 0, + ptr: ptr::null(), + start: ptr::null(), + }; + let mut stream = stream; + let error = init_dstream(&mut stream, c_src, c_src_size); + if ERR_isError(error) { + return error; + } + let table = dtable.as_ptr().add(1) as *const HufDEltX2; + let decoded = huf_decode_stream(dst, dst_size, &mut stream, table, dtable[0] as u32); + if ERR_isError(decoded) { + return decoded; + } + if !end_of_dstream(&stream) { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + dst_size +} + +unsafe fn huf_decompress1x2( + dst: *mut u8, + dst_size: usize, + c_src: *const u8, + c_src_size: usize, +) -> usize { + let mut dtable = [0u16; 1 + (1 << HUF_MAX_TABLELOG)]; + dtable[0] = HUF_MAX_TABLELOG as u16; + let header_size = huf_read_dtable_x2(&mut dtable, c_src, c_src_size); + if ERR_isError(header_size) { + return header_size; + } + if header_size >= c_src_size { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + huf_decompress1x2_using_dtable( + dst, + dst_size, + c_src.add(header_size), + c_src_size - header_size, + &dtable, + ) +} + +#[repr(C)] +#[derive(Clone, Copy)] +struct HufDEltX4 { + sequence: u16, + nb_bits: u8, + length: u8, +} + +#[repr(C)] +#[derive(Clone, Copy)] +struct SortedSymbol { + symbol: u8, + weight: u8, +} + +type RankVal = [[u32; HUF_ABSOLUTE_MAX_TABLELOG + 1]; HUF_ABSOLUTE_MAX_TABLELOG]; + +#[inline] +unsafe fn huf_set_dtable_x4( + dtable: *mut HufDEltX4, + index: usize, + sequence: u16, + nb_bits: u32, + length: u8, +) { + let entry = dtable.add(index); + write_le16(entry.cast::(), sequence); + (*entry).nb_bits = nb_bits as u8; + (*entry).length = length; +} + +#[allow(clippy::too_many_arguments)] +unsafe fn huf_fill_dtable_x4_level2( + dtable: *mut HufDEltX4, + size_log: u32, + consumed: u32, + rank_val_origin: &[u32; HUF_ABSOLUTE_MAX_TABLELOG + 1], + min_weight: usize, + sorted_symbols: &[SortedSymbol; HUF_MAX_SYMBOL_VALUE + 1], + sorted_start: usize, + sorted_list_size: usize, + nb_bits_baseline: u32, + base_seq: u16, +) { + let mut rank_val = *rank_val_origin; + + if min_weight > 1 { + let skip_size = rank_val[min_weight] as usize; + for index in 0..skip_size { + huf_set_dtable_x4(dtable, index, base_seq, consumed, 1); + } + } + + for item in 0..sorted_list_size { + let sorted = sorted_symbols[sorted_start + item]; + let symbol = sorted.symbol as u32; + let weight = sorted.weight as usize; + let nb_bits = nb_bits_baseline - weight as u32; + let length = 1u32 << (size_log - nb_bits); + let start = rank_val[weight] as usize; + let end = start + length as usize; + let sequence = base_seq.wrapping_add((symbol << 8) as u16); + for index in start..end { + huf_set_dtable_x4(dtable, index, sequence, nb_bits + consumed, 2); + } + rank_val[weight] = rank_val[weight].wrapping_add(length); + } +} + +#[allow(clippy::too_many_arguments)] +unsafe fn huf_fill_dtable_x4( + dtable: *mut HufDEltX4, + target_log: u32, + sorted_list: &[SortedSymbol; HUF_MAX_SYMBOL_VALUE + 1], + sorted_list_size: usize, + rank_start0: &[u32; HUF_ABSOLUTE_MAX_TABLELOG + 2], + rank_val_origin: &RankVal, + max_weight: u32, + nb_bits_baseline: u32, +) { + let mut rank_val = rank_val_origin[0]; + let scale_log = nb_bits_baseline as i32 - target_log as i32; + let min_bits = nb_bits_baseline - max_weight; + + for item in 0..sorted_list_size { + let sorted = sorted_list[item]; + let symbol = sorted.symbol as u16; + let weight = sorted.weight as usize; + let nb_bits = nb_bits_baseline - weight as u32; + let start = rank_val[weight] as usize; + let length = 1u32 << (target_log - nb_bits); + + if target_log - nb_bits >= min_bits { + let mut min_weight = nb_bits as i32 + scale_log; + if min_weight < 1 { + min_weight = 1; + } + let min_weight = min_weight as usize; + let sorted_rank = rank_start0[min_weight + 1] as usize; + huf_fill_dtable_x4_level2( + dtable.add(start), + target_log - nb_bits, + nb_bits, + &rank_val_origin[nb_bits as usize], + min_weight, + sorted_list, + sorted_rank, + sorted_list_size - sorted_rank, + nb_bits_baseline, + symbol, + ); + } else { + let end = start + length as usize; + for index in start..end { + huf_set_dtable_x4(dtable, index, symbol, nb_bits, 1); + } + } + rank_val[weight] = rank_val[weight].wrapping_add(length); + } +} + +#[allow(clippy::needless_range_loop)] +unsafe fn huf_read_dtable_x4( + dtable: &mut [u32; 1 + (1 << HUF_MAX_TABLELOG)], + src: *const u8, + src_size: usize, +) -> usize { + let mut weight_list = [0u8; HUF_MAX_SYMBOL_VALUE + 1]; + let mut sorted_symbols = [SortedSymbol { + symbol: 0, + weight: 0, + }; HUF_MAX_SYMBOL_VALUE + 1]; + let mut rank_stats = [0u32; HUF_ABSOLUTE_MAX_TABLELOG + 1]; + let mut rank_start0 = [0u32; HUF_ABSOLUTE_MAX_TABLELOG + 2]; + let mut rank_val = [[0u32; HUF_ABSOLUTE_MAX_TABLELOG + 1]; HUF_ABSOLUTE_MAX_TABLELOG]; + let mut nb_symbols = 0u32; + let mut table_log = 0u32; + let mem_log = dtable[0]; + + if mem_log > HUF_ABSOLUTE_MAX_TABLELOG as u32 { + return ERROR(ZstdErrorCode::TableLogTooLarge); + } + + let i_size = huf_read_stats( + &mut weight_list, + &mut rank_stats, + &mut nb_symbols, + &mut table_log, + src, + src_size, + ); + if ERR_isError(i_size) { + return i_size; + } + if table_log > mem_log { + return ERROR(ZstdErrorCode::TableLogTooLarge); + } + + let mut max_weight = table_log as usize; + loop { + if rank_stats[max_weight] != 0 { + break; + } + if max_weight == 0 { + return ERROR(ZstdErrorCode::Generic); + } + max_weight -= 1; + } + + let mut next_rank_start = 0u32; + for weight in 1..=max_weight { + let current = next_rank_start; + next_rank_start = next_rank_start.wrapping_add(rank_stats[weight]); + rank_start0[weight + 1] = current; + } + rank_start0[0] = next_rank_start; + let size_of_sort = next_rank_start as usize; + + for symbol in 0..nb_symbols as usize { + let weight = weight_list[symbol] as usize; + let rank = rank_start0[weight + 1] as usize; + sorted_symbols[rank] = SortedSymbol { + symbol: symbol as u8, + weight: weight as u8, + }; + rank_start0[weight + 1] = rank as u32 + 1; + } + rank_start0[1] = 0; + + let min_bits = table_log + 1 - max_weight as u32; + let rescale = (mem_log as i32 - table_log as i32) - 1; + let mut next_rank_val = 0u32; + for weight in 1..=max_weight { + let current = next_rank_val; + let shift = (weight as i32 + rescale) as u32; + next_rank_val = next_rank_val.wrapping_add(rank_stats[weight] << shift); + rank_val[0][weight] = current; + } + if min_bits <= mem_log.saturating_sub(min_bits) { + for consumed in min_bits..=mem_log - min_bits { + for weight in 1..=max_weight { + rank_val[consumed as usize][weight] = rank_val[0][weight] >> consumed; + } + } + } + + let table = dtable.as_mut_ptr().add(1) as *mut HufDEltX4; + huf_fill_dtable_x4( + table, + mem_log, + &sorted_symbols, + size_of_sort, + &rank_start0, + &rank_val, + max_weight as u32, + table_log + 1, + ); + i_size +} + +#[inline] +unsafe fn huf_decode_symbol_x4( + op: &mut *mut u8, + stream: &mut DStream, + dtable: *const HufDEltX4, + table_log: u32, +) -> u32 { + let value = look_bits_fast(stream, table_log); + let entry = dtable.add(value); + ptr::copy(entry.cast::(), *op, 2); + skip_bits(stream, (*entry).nb_bits as u32); + let length = (*entry).length as u32; + *op = (*op).add(length as usize); + length +} + +#[inline] +unsafe fn huf_decode_last_symbol_x4( + op: *mut u8, + stream: &mut DStream, + dtable: *const HufDEltX4, + table_log: u32, +) -> u32 { + let value = look_bits_fast(stream, table_log); + let entry = dtable.add(value); + *op = read_le16(entry.cast::()) as u8; + if (*entry).length == 1 { + skip_bits(stream, (*entry).nb_bits as u32); + } else if stream.bits_consumed < USIZE_BITS { + skip_bits(stream, (*entry).nb_bits as u32); + if stream.bits_consumed > USIZE_BITS { + stream.bits_consumed = USIZE_BITS; + } + } + 1 +} + +#[inline] +unsafe fn huf_decode_symbol_x4_0( + op: &mut *mut u8, + stream: &mut DStream, + dtable: *const HufDEltX4, + table_log: u32, +) { + huf_decode_symbol_x4(op, stream, dtable, table_log); +} + +#[inline] +unsafe fn huf_decode_symbol_x4_1( + op: &mut *mut u8, + stream: &mut DStream, + dtable: *const HufDEltX4, + table_log: u32, +) { + if USIZE_BITS == 64 || HUF_MAX_TABLELOG <= 12 { + huf_decode_symbol_x4(op, stream, dtable, table_log); + } +} + +#[inline] +unsafe fn huf_decode_symbol_x4_2( + op: &mut *mut u8, + stream: &mut DStream, + dtable: *const HufDEltX4, + table_log: u32, +) { + if USIZE_BITS == 64 { + huf_decode_symbol_x4(op, stream, dtable, table_log); + } +} + +unsafe fn huf_decode_stream_x4( + mut p: *mut u8, + stream: &mut DStream, + p_end: *mut u8, + dtable: *const HufDEltX4, + table_log: u32, +) -> usize { + let p_start = p; + while reload_dstream(stream) == DSTREAM_UNFINISHED + && (p as usize) < (p_end as usize).wrapping_sub(7) + { + huf_decode_symbol_x4_2(&mut p, stream, dtable, table_log); + huf_decode_symbol_x4_1(&mut p, stream, dtable, table_log); + huf_decode_symbol_x4_2(&mut p, stream, dtable, table_log); + huf_decode_symbol_x4_0(&mut p, stream, dtable, table_log); + } + while reload_dstream(stream) == DSTREAM_UNFINISHED + && (p as usize) <= (p_end as usize).wrapping_sub(2) + { + huf_decode_symbol_x4_0(&mut p, stream, dtable, table_log); + } + while (p as usize) <= (p_end as usize).wrapping_sub(2) { + huf_decode_symbol_x4_0(&mut p, stream, dtable, table_log); + } + if (p as usize) < p_end as usize { + p = p.add(huf_decode_last_symbol_x4(p, stream, dtable, table_log) as usize); + } + (p as usize).wrapping_sub(p_start as usize) +} + +unsafe fn huf_decompress4x4_using_dtable( + dst: *mut u8, + dst_size: usize, + c_src: *const u8, + c_src_size: usize, + dtable: &[u32; 1 + (1 << HUF_MAX_TABLELOG)], +) -> usize { + if c_src_size < 10 { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + let length1 = read_le16(c_src) as usize; + let length2 = read_le16(c_src.add(2)) as usize; + let length3 = read_le16(c_src.add(4)) as usize; + let total = length1 + .wrapping_add(length2) + .wrapping_add(length3) + .wrapping_add(6); + let length4 = c_src_size.wrapping_sub(total); + if length4 > c_src_size { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + + let streams = [ + c_src.add(6), + c_src.add(6 + length1), + c_src.add(6 + length1 + length2), + c_src.add(6 + length1 + length2 + length3), + ]; + let lengths = [length1, length2, length3, length4]; + let segment = dst_size.wrapping_add(3) / 4; + let starts = [ + dst, + dst.add(segment), + dst.add(segment * 2), + dst.add(segment * 3), + ]; + let sizes = [ + segment.min(dst_size), + segment.min(dst_size.saturating_sub(segment)), + segment.min(dst_size.saturating_sub(segment * 2)), + dst_size.saturating_sub(segment * 3), + ]; + let table = dtable.as_ptr().add(1) as *const HufDEltX4; + let table_log = dtable[0]; + + for index in 0..4 { + let mut stream = DStream { + bit_container: 0, + bits_consumed: 0, + ptr: ptr::null(), + start: ptr::null(), + }; + let error = init_dstream(&mut stream, streams[index], lengths[index]); + if ERR_isError(error) { + return error; + } + let decoded = huf_decode_stream_x4( + starts[index], + &mut stream, + starts[index].add(sizes[index]), + table, + table_log, + ); + if decoded != sizes[index] || !end_of_dstream(&stream) { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + } + dst_size +} + +unsafe fn huf_decompress1x4_using_dtable( + dst: *mut u8, + dst_size: usize, + c_src: *const u8, + c_src_size: usize, + dtable: &[u32; 1 + (1 << HUF_MAX_TABLELOG)], +) -> usize { + let mut stream = DStream { + bit_container: 0, + bits_consumed: 0, + ptr: ptr::null(), + start: ptr::null(), + }; + let error = init_dstream(&mut stream, c_src, c_src_size); + if ERR_isError(error) { + return error; + } + let table = dtable.as_ptr().add(1) as *const HufDEltX4; + let decoded = huf_decode_stream_x4(dst, &mut stream, dst.add(dst_size), table, dtable[0]); + if decoded != dst_size || !end_of_dstream(&stream) { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + dst_size +} + +unsafe fn huf_decompress1x4( + dst: *mut u8, + dst_size: usize, + c_src: *const u8, + c_src_size: usize, +) -> usize { + let mut dtable = [0u32; 1 + (1 << HUF_MAX_TABLELOG)]; + dtable[0] = HUF_MAX_TABLELOG as u32; + let header_size = huf_read_dtable_x4(&mut dtable, c_src, c_src_size); + if ERR_isError(header_size) { + return header_size; + } + if header_size >= c_src_size { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + huf_decompress1x4_using_dtable( + dst, + dst_size, + c_src.add(header_size), + c_src_size - header_size, + &dtable, + ) +} + +unsafe fn huf_decompress4x4( + dst: *mut u8, + dst_size: usize, + c_src: *const u8, + c_src_size: usize, +) -> usize { + let mut dtable = [0u32; 1 + (1 << HUF_MAX_TABLELOG)]; + dtable[0] = HUF_MAX_TABLELOG as u32; + let header_size = huf_read_dtable_x4(&mut dtable, c_src, c_src_size); + if ERR_isError(header_size) { + return header_size; + } + if header_size >= c_src_size { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + huf_decompress4x4_using_dtable( + dst, + dst_size, + c_src.add(header_size), + c_src_size - header_size, + &dtable, + ) +} + +unsafe fn huf_decompress( + dst: *mut u8, + dst_size: usize, + c_src: *const u8, + c_src_size: usize, +) -> usize { + if dst_size == 0 { + return ERROR(ZstdErrorCode::DstSizeTooSmall); + } + if c_src_size > dst_size { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + if c_src_size == dst_size { + ptr::copy(c_src, dst, dst_size); + return dst_size; + } + if c_src_size == 1 { + ptr::write_bytes(dst, *c_src, dst_size); + return dst_size; + } + + const ALGO_TIME: [[[u32; 2]; 3]; 16] = [ + [[0, 0], [1, 1], [2, 2]], + [[0, 0], [1, 1], [2, 2]], + [[38, 130], [1313, 74], [2151, 38]], + [[448, 128], [1353, 74], [2238, 41]], + [[556, 128], [1353, 74], [2238, 47]], + [[714, 128], [1418, 74], [2436, 53]], + [[883, 128], [1437, 74], [2464, 61]], + [[897, 128], [1515, 75], [2622, 68]], + [[926, 128], [1613, 75], [2730, 75]], + [[947, 128], [1729, 77], [3359, 77]], + [[1107, 128], [2083, 81], [4006, 84]], + [[1177, 128], [2379, 87], [4785, 88]], + [[1242, 128], [2415, 93], [5155, 84]], + [[1349, 128], [2644, 106], [5260, 106]], + [[1455, 128], [2422, 124], [4174, 124]], + [[722, 128], [1891, 145], [1936, 146]], + ]; + let q = c_src_size.wrapping_mul(16) / dst_size; + let d256 = (dst_size >> 8) as u32; + let mut dtime = [0u32; 3]; + for index in 0..3 { + dtime[index] = + ALGO_TIME[q][index][0].wrapping_add(ALGO_TIME[q][index][1].wrapping_mul(d256)); + } + dtime[1] = dtime[1].wrapping_add(dtime[1] >> 4); + dtime[2] = dtime[2].wrapping_add(dtime[2] >> 3); + + if dtime[1] < dtime[0] { + huf_decompress4x4(dst, dst_size, c_src, c_src_size) + } else { + let mut dtable = [0u16; 1 + (1 << HUF_MAX_TABLELOG)]; + dtable[0] = HUF_MAX_TABLELOG as u16; + let header_size = huf_read_dtable_x2(&mut dtable, c_src, c_src_size); + if ERR_isError(header_size) { + return header_size; + } + if header_size >= c_src_size { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + huf_decompress4x2_using_dtable( + dst, + dst_size, + c_src.add(header_size), + c_src_size - header_size, + &dtable, + ) + } +} + +/* ****************************************** + * v0.6 frame decoder + ********************************************/ + +const STAGE_GET_FRAME_HEADER_SIZE: u32 = 0; +const STAGE_DECODE_FRAME_HEADER: u32 = 1; +const STAGE_DECODE_BLOCK_HEADER: u32 = 2; +const STAGE_DECOMPRESS_BLOCK: u32 = 3; + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct ZSTDv06_frameParams { + pub frame_content_size: u64, + pub window_log: c_uint, +} + +#[repr(C)] +pub struct ZSTDv06_Dctx { + ll_table: [u32; 1 + (1 << LL_FSE_LOG)], + off_table: [u32; 1 + (1 << OFF_FSE_LOG)], + ml_table: [u32; 1 + (1 << ML_FSE_LOG)], + huf_table_x4: [u32; 1 + (1 << HUF_MAX_TABLELOG)], + previous_dst_end: *const u8, + base: *const u8, + v_base: *const u8, + dict_end: *const u8, + expected: usize, + header_size: usize, + f_params: ZSTDv06_frameParams, + b_type: u32, + stage: u32, + flag_repeat_table: u32, + lit_ptr: *const u8, + lit_size: usize, + lit_buffer: [u8; BLOCKSIZE + WILDCOPY_OVERLENGTH], + header_buffer: [u8; FRAME_HEADER_SIZE_MAX], +} + +#[derive(Clone, Copy)] +struct BlockProperties { + block_type: u32, + orig_size: u32, +} + +#[inline] +unsafe fn decompress_begin(dctx: &mut ZSTDv06_Dctx) -> usize { + dctx.expected = FRAME_HEADER_SIZE_MIN; + dctx.stage = STAGE_GET_FRAME_HEADER_SIZE; + dctx.previous_dst_end = ptr::null(); + dctx.base = ptr::null(); + dctx.v_base = ptr::null(); + dctx.dict_end = ptr::null(); + dctx.huf_table_x4[0] = HUF_MAX_TABLELOG as u32; + dctx.flag_repeat_table = 0; + 0 +} + +#[inline] +unsafe fn create_dctx() -> *mut ZSTDv06_Dctx { + let dctx = libc::malloc(std::mem::size_of::()) as *mut ZSTDv06_Dctx; + if dctx.is_null() { + return ptr::null_mut(); + } + decompress_begin(&mut *dctx); + dctx +} + +#[inline] +unsafe fn free_dctx(dctx: *mut ZSTDv06_Dctx) -> usize { + libc::free(dctx.cast::()); + 0 +} + +unsafe fn copy_dctx(dst: *mut ZSTDv06_Dctx, src: *const ZSTDv06_Dctx) { + let workspace_size = BLOCKSIZE + WILDCOPY_OVERLENGTH + FRAME_HEADER_SIZE_MAX; + let copy_size = std::mem::size_of::() - workspace_size; + ptr::copy_nonoverlapping(src.cast::(), dst.cast::(), copy_size); +} + +unsafe fn frame_header_size(src: *const u8, src_size: usize) -> usize { + if src_size < FRAME_HEADER_SIZE_MIN { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + let fcs_field_size = [0usize, 1, 2, 8][(*src.add(4) >> 6) as usize]; + FRAME_HEADER_SIZE_MIN + fcs_field_size +} + +unsafe fn get_frame_params( + params: &mut ZSTDv06_frameParams, + src: *const u8, + src_size: usize, +) -> usize { + if src_size < FRAME_HEADER_SIZE_MIN { + return FRAME_HEADER_SIZE_MIN; + } + if read_le32(src) != ZSTD_MAGIC_NUMBER { + return ERROR(ZstdErrorCode::PrefixUnknown); + } + + let header_size = frame_header_size(src, src_size); + if src_size < header_size { + return header_size; + } + + *params = ZSTDv06_frameParams { + frame_content_size: 0, + window_log: 0, + }; + let frame_desc = *src.add(4); + params.window_log = (frame_desc & 0x0f) as u32 + ZSTD_WINDOWLOG_ABSOLUTE_MIN; + if frame_desc & 0x20 != 0 { + return ERROR(ZstdErrorCode::FrameParameterUnsupported); + } + params.frame_content_size = match frame_desc >> 6 { + 0 => 0, + 1 => *src.add(5) as u64, + 2 => read_le16(src.add(5)) as u64 + 256, + 3 => read_le64(src.add(5)), + _ => unreachable!(), + }; + 0 +} + +unsafe fn decode_frame_header(dctx: &mut ZSTDv06_Dctx, src: *const u8, src_size: usize) -> usize { + let result = get_frame_params(&mut dctx.f_params, src, src_size); + if USIZE_BITS == 32 && dctx.f_params.window_log > 25 { + return ERROR(ZstdErrorCode::FrameParameterUnsupported); + } + result +} + +unsafe fn get_block_size( + src: *const u8, + src_size: usize, + properties: &mut BlockProperties, +) -> usize { + if src_size < BLOCK_HEADER_SIZE { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + let first = *src; + let c_size = + *src.add(2) as usize | ((*src.add(1) as usize) << 8) | (((first & 7) as usize) << 16); + properties.block_type = (first >> 6) as u32; + properties.orig_size = if properties.block_type == BT_RLE { + c_size as u32 + } else { + 0 + }; + if properties.block_type == BT_END { + 0 + } else if properties.block_type == BT_RLE { + 1 + } else { + c_size + } +} + +unsafe fn copy_raw_block( + dst: *mut u8, + dst_capacity: usize, + src: *const u8, + src_size: usize, +) -> usize { + if dst.is_null() || src_size > dst_capacity { + return ERROR(ZstdErrorCode::DstSizeTooSmall); + } + ptr::copy(src, dst, src_size); + src_size +} + +unsafe fn decode_literals_block(dctx: &mut ZSTDv06_Dctx, src: *const u8, src_size: usize) -> usize { + if src_size < MIN_CBLOCK_SIZE { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + + match *src >> 6 { + IS_HUF => { + let mut lit_header_size = ((*src >> 4) & 3) as usize; + if src_size < 5 { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + let single_stream; + let (lit_size, lit_c_size); + match lit_header_size { + 0 | 1 => { + lit_header_size = 3; + single_stream = *src & 16 != 0; + let first = *src; + let second = *src.add(1); + let third = *src.add(2); + lit_size = ((first & 15) as usize) << 6 | (second as usize >> 2); + lit_c_size = ((second as usize & 3) << 8) | third as usize; + } + 2 => { + lit_header_size = 4; + single_stream = false; + let first = *src; + let second = *src.add(1); + let third = *src.add(2); + let fourth = *src.add(3); + lit_size = ((first & 15) as usize) << 10 + | (second as usize) << 2 + | (third as usize >> 6); + lit_c_size = ((third as usize & 63) << 8) | fourth as usize; + } + 3 => { + lit_header_size = 5; + single_stream = false; + let first = *src; + let second = *src.add(1); + let third = *src.add(2); + let fourth = *src.add(3); + let fifth = *src.add(4); + lit_size = ((first & 15) as usize) << 14 + | (second as usize) << 6 + | (third as usize >> 2); + lit_c_size = + ((third as usize & 3) << 16) | (fourth as usize) << 8 | fifth as usize; + } + _ => unreachable!(), + } + if lit_size > BLOCKSIZE || lit_c_size + lit_header_size > src_size { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + let decoded = if single_stream { + huf_decompress1x2( + dctx.lit_buffer.as_mut_ptr(), + lit_size, + src.add(lit_header_size), + lit_c_size, + ) + } else { + huf_decompress( + dctx.lit_buffer.as_mut_ptr(), + lit_size, + src.add(lit_header_size), + lit_c_size, + ) + }; + if ERR_isError(decoded) { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + dctx.lit_ptr = dctx.lit_buffer.as_ptr(); + dctx.lit_size = lit_size; + dctx.lit_buffer[lit_size..lit_size + WILDCOPY_OVERLENGTH].fill(0); + lit_c_size + lit_header_size + } + IS_PCH => { + let lit_header_size = ((*src >> 4) & 3) as usize; + if lit_header_size != 1 { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + if dctx.flag_repeat_table == 0 { + return ERROR(ZstdErrorCode::DictionaryCorrupted); + } + let lit_size = ((*src & 15) as usize) << 6 | (*src.add(1) as usize >> 2); + let lit_c_size = ((*src.add(1) as usize & 3) << 8) | *src.add(2) as usize; + if lit_size > BLOCKSIZE || lit_c_size + 3 > src_size { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + let decoded = huf_decompress1x4_using_dtable( + dctx.lit_buffer.as_mut_ptr(), + lit_size, + src.add(3), + lit_c_size, + &dctx.huf_table_x4, + ); + if ERR_isError(decoded) { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + dctx.lit_ptr = dctx.lit_buffer.as_ptr(); + dctx.lit_size = lit_size; + dctx.lit_buffer[lit_size..lit_size + WILDCOPY_OVERLENGTH].fill(0); + lit_c_size + 3 + } + IS_RAW => { + let mut lit_header_size = ((*src >> 4) & 3) as usize; + let lit_size = match lit_header_size { + 0 | 1 => { + lit_header_size = 1; + (*src & 31) as usize + } + 2 => ((*src & 15) as usize) << 8 | *src.add(1) as usize, + 3 => { + ((*src & 15) as usize) << 16 + | ((*src.add(1) as usize) << 8) + | *src.add(2) as usize + } + _ => unreachable!(), + }; + if lit_size > BLOCKSIZE { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + if lit_header_size + lit_size + WILDCOPY_OVERLENGTH > src_size { + if lit_header_size + lit_size > src_size { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + ptr::copy( + src.add(lit_header_size), + dctx.lit_buffer.as_mut_ptr(), + lit_size, + ); + dctx.lit_ptr = dctx.lit_buffer.as_ptr(); + dctx.lit_size = lit_size; + dctx.lit_buffer[lit_size..lit_size + WILDCOPY_OVERLENGTH].fill(0); + } else { + dctx.lit_ptr = src.add(lit_header_size); + dctx.lit_size = lit_size; + } + lit_header_size + lit_size + } + IS_RLE => { + let mut lit_header_size = ((*src >> 4) & 3) as usize; + let lit_size = match lit_header_size { + 0 | 1 => { + lit_header_size = 1; + (*src & 31) as usize + } + 2 => ((*src & 15) as usize) << 8 | *src.add(1) as usize, + 3 => { + if src_size < 4 { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + ((*src & 15) as usize) << 16 + | ((*src.add(1) as usize) << 8) + | *src.add(2) as usize + } + _ => unreachable!(), + }; + if lit_size > BLOCKSIZE { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + ptr::write_bytes( + dctx.lit_buffer.as_mut_ptr(), + *src.add(lit_header_size), + lit_size + WILDCOPY_OVERLENGTH, + ); + dctx.lit_ptr = dctx.lit_buffer.as_ptr(); + dctx.lit_size = lit_size; + lit_header_size + 1 + } + _ => ERROR(ZstdErrorCode::CorruptionDetected), + } +} + +#[allow(clippy::too_many_arguments)] +unsafe fn build_seq_table( + table: &mut [u32], + encoding: u32, + max_symbol: u32, + max_log: u32, + src: *const u8, + src_size: usize, + default_norm: &[i16], + default_log: u32, + repeat_table: u32, +) -> usize { + match encoding { + FSE_ENCODING_RLE => { + if src_size == 0 { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + let symbol = *src; + if symbol as u32 > max_symbol { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + fse_build_dtable_rle(table, symbol); + 1 + } + FSE_ENCODING_RAW => { + let result = fse_build_dtable(table, default_norm, max_symbol, default_log); + if ERR_isError(result) { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + 0 + } + FSE_ENCODING_STATIC => { + if repeat_table == 0 { + ERROR(ZstdErrorCode::CorruptionDetected) + } else { + 0 + } + } + FSE_ENCODING_DYNAMIC => { + let mut norm = [0i16; 256]; + let mut max = max_symbol; + let mut table_log = 0; + let header_size = fse_read_ncount(&mut norm, &mut max, &mut table_log, src, src_size); + if ERR_isError(header_size) || table_log > max_log { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + let result = fse_build_dtable(table, &norm, max, table_log); + if ERR_isError(result) { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + header_size + } + _ => unreachable!(), + } +} + +unsafe fn decode_seq_headers( + dctx: &mut ZSTDv06_Dctx, + nb_seq: &mut i32, + src: *const u8, + src_size: usize, +) -> usize { + if src_size < MIN_SEQUENCES_SIZE { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + let start = src as usize; + let end = start.wrapping_add(src_size); + let mut ip = src; + let first = *ip; + ip = ip.add(1); + let mut count = first as i32; + if count != 0 { + if count > 0x7f { + if count == 0xff { + if (ip as usize).wrapping_add(2) > end { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + count = read_le16(ip) as i32 + LONG_NB_SEQ; + ip = ip.add(2); + } else { + if ip as usize >= end { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + count = ((count - 0x80) << 8) + *ip as i32; + ip = ip.add(1); + } + } + *nb_seq = count; + } else { + *nb_seq = 0; + return 1; + } + + if (ip as usize).wrapping_add(4) > end { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + let types = *ip; + ip = ip.add(1); + let ll_type = (types >> 6) as u32; + let off_type = ((types >> 4) & 3) as u32; + let ml_type = ((types >> 2) & 3) as u32; + + let used = build_seq_table( + &mut dctx.ll_table, + ll_type, + MAX_LL, + LL_FSE_LOG, + ip, + end.wrapping_sub(ip as usize), + &LL_DEFAULT_NORM, + LL_DEFAULT_LOG, + dctx.flag_repeat_table, + ); + if ERR_isError(used) { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + ip = ip.add(used); + + let used = build_seq_table( + &mut dctx.off_table, + off_type, + MAX_OFF, + OFF_FSE_LOG, + ip, + end.wrapping_sub(ip as usize), + &OF_DEFAULT_NORM, + OF_DEFAULT_LOG, + dctx.flag_repeat_table, + ); + if ERR_isError(used) { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + ip = ip.add(used); + + let used = build_seq_table( + &mut dctx.ml_table, + ml_type, + MAX_ML, + ML_FSE_LOG, + ip, + end.wrapping_sub(ip as usize), + &ML_DEFAULT_NORM, + ML_DEFAULT_LOG, + dctx.flag_repeat_table, + ); + if ERR_isError(used) { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + ip = ip.add(used); + + (ip as usize).wrapping_sub(start) +} + +#[derive(Clone, Copy)] +struct Sequence { + lit_length: usize, + match_length: usize, + offset: usize, +} + +struct SequenceState { + stream: DStream, + state_ll: FseDState, + state_off: FseDState, + state_ml: FseDState, + prev_offset: [usize; REPCODE_NUM], +} + +unsafe fn decode_sequence(sequence: &mut Sequence, state: &mut SequenceState) { + let ll_code = fse_peek_symbol(&state.state_ll) as usize; + let ml_code = fse_peek_symbol(&state.state_ml) as usize; + let off_code = fse_peek_symbol(&state.state_off) as usize; + let ll_bits = LL_BITS_TABLE[ll_code]; + let ml_bits = ML_BITS_TABLE[ml_code]; + let total_bits = ll_bits + ml_bits + off_code as u32; + + const LL_BASE: [usize; MAX_LL as usize + 1] = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 22, 24, 28, 32, 40, 48, + 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000, + ]; + const ML_BASE: [usize; MAX_ML as usize + 1] = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 34, 36, 38, 40, 44, 48, 56, 64, 80, 96, 0x80, 0x100, 0x200, + 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000, + ]; + const OF_BASE: [usize; MAX_OFF as usize + 1] = [ + 0, 1, 3, 7, 0xf, 0x1f, 0x3f, 0x7f, 0xff, 0x1ff, 0x3ff, 0x7ff, 0xfff, 0x1fff, 0x3fff, + 0x7fff, 0xffff, 0x1ffff, 0x3ffff, 0x7ffff, 0xfffff, 0x1fffff, 0x3fffff, 0x7fffff, 0xffffff, + 0x1ffffff, 0x3ffffff, 1, 1, + ]; + + let mut offset = if off_code == 0 { + 0 + } else { + OF_BASE[off_code] + read_bits(&mut state.stream, off_code as u32) + }; + if USIZE_BITS == 32 { + reload_dstream(&mut state.stream); + } + + if offset < REPCODE_NUM { + if ll_code == 0 && offset <= 1 { + offset = 1 - offset; + } + if offset != 0 { + let temp = state.prev_offset[offset]; + if offset != 1 { + state.prev_offset[2] = state.prev_offset[1]; + } + state.prev_offset[1] = state.prev_offset[0]; + state.prev_offset[0] = temp; + offset = temp; + } else { + offset = state.prev_offset[0]; + } + } else { + offset -= REPCODE_MOVE; + state.prev_offset[2] = state.prev_offset[1]; + state.prev_offset[1] = state.prev_offset[0]; + state.prev_offset[0] = offset; + } + sequence.offset = offset; + + sequence.match_length = ML_BASE[ml_code] + + MINMATCH + + if ml_code > 31 { + read_bits(&mut state.stream, ml_bits) + } else { + 0 + }; + if USIZE_BITS == 32 && ml_bits + ll_bits > 24 { + reload_dstream(&mut state.stream); + } + + sequence.lit_length = LL_BASE[ll_code] + + if ll_code > 15 { + read_bits(&mut state.stream, ll_bits) + } else { + 0 + }; + if USIZE_BITS == 32 || total_bits > 64 - 7 - (LL_FSE_LOG + ML_FSE_LOG + OFF_FSE_LOG) { + reload_dstream(&mut state.stream); + } + + fse_update_state(&mut state.state_ll, &mut state.stream); + fse_update_state(&mut state.state_ml, &mut state.stream); + if USIZE_BITS == 32 { + reload_dstream(&mut state.stream); + } + fse_update_state(&mut state.state_off, &mut state.stream); +} + +#[allow(clippy::too_many_arguments)] +unsafe fn exec_sequence( + mut op: *mut u8, + mut sequence: Sequence, + lit_ptr: &mut *const u8, + lit_limit: *const u8, + base: *const u8, + v_base: *const u8, + dict_end: *const u8, + oend: *mut u8, +) -> usize { + let o_lit_end = (op as usize).wrapping_add(sequence.lit_length); + let sequence_length = sequence.lit_length.wrapping_add(sequence.match_length); + let o_match_end = o_lit_end.wrapping_add(sequence.match_length); + let oend_addr = oend as usize; + let oend_8 = oend_addr.wrapping_sub(8); + let lit_end = (*lit_ptr as usize).wrapping_add(sequence.lit_length); + let mut match_addr = o_lit_end.wrapping_sub(sequence.offset); + + if sequence_length > oend_addr.wrapping_sub(op as usize) { + return ERROR(ZstdErrorCode::DstSizeTooSmall); + } + if sequence.lit_length > (lit_limit as usize).wrapping_sub(*lit_ptr as usize) { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + if o_lit_end > oend_8 { + return ERROR(ZstdErrorCode::DstSizeTooSmall); + } + if o_match_end > oend_addr { + return ERROR(ZstdErrorCode::DstSizeTooSmall); + } + if lit_end > lit_limit as usize { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + + zstd_wildcopy(op, *lit_ptr, sequence.lit_length as isize); + op = o_lit_end as *mut u8; + *lit_ptr = lit_end as *const u8; + + if sequence.offset > o_lit_end.wrapping_sub(base as usize) { + if sequence.offset > o_lit_end.wrapping_sub(v_base as usize) { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + match_addr = (dict_end as usize).wrapping_sub((base as usize).wrapping_sub(match_addr)); + if match_addr.wrapping_add(sequence.match_length) <= dict_end as usize { + ptr::copy( + match_addr as *const u8, + o_lit_end as *mut u8, + sequence.match_length, + ); + return sequence_length; + } + + let length1 = (dict_end as usize).wrapping_sub(match_addr); + ptr::copy(match_addr as *const u8, o_lit_end as *mut u8, length1); + op = o_lit_end.wrapping_add(length1) as *mut u8; + sequence.match_length = sequence.match_length.wrapping_sub(length1); + match_addr = base as usize; + if (op as usize) > oend_8 || sequence.match_length < MINMATCH { + let mut out = op; + let mut m = match_addr as *const u8; + while (out as usize) < o_match_end { + *out = *m; + out = out.add(1); + m = m.add(1); + } + return sequence_length; + } + } + + if sequence.offset < 8 { + let dec32 = [0usize, 1, 2, 1, 4, 4, 4, 4]; + let dec64 = [8usize, 8, 8, 7, 8, 9, 10, 11]; + let match_ptr = match_addr as *const u8; + *op = *match_ptr; + *op.add(1) = *match_ptr.add(1); + *op.add(2) = *match_ptr.add(2); + *op.add(3) = *match_ptr.add(3); + let match_ptr = match_ptr.add(dec32[sequence.offset]); + zstd_copy4(op.add(4), match_ptr); + match_addr = match_addr + .wrapping_add(8) + .wrapping_sub(dec64[sequence.offset]); + } else { + zstd_copy8(op, match_addr as *const u8); + match_addr = match_addr.wrapping_add(8); + } + op = op.add(8); + match_addr = match_addr.wrapping_add(8); + + if o_match_end > oend_addr.wrapping_sub(16 - MINMATCH) { + if (op as usize) < oend_8 { + let dist = oend_8 - op as usize; + zstd_wildcopy(op, match_addr as *const u8, dist as isize); + match_addr = match_addr.wrapping_add(dist); + op = oend_8 as *mut u8; + } + while (op as usize) < o_match_end { + *op = *(match_addr as *const u8); + op = op.add(1); + match_addr = match_addr.wrapping_add(1); + } + } else { + zstd_wildcopy( + op, + match_addr as *const u8, + sequence.match_length.wrapping_sub(8) as isize, + ); + } + sequence_length +} + +unsafe fn decompress_sequences( + dctx: &mut ZSTDv06_Dctx, + dst: *mut u8, + max_dst_size: usize, + seq_start: *const u8, + seq_size: usize, +) -> usize { + let ip = seq_start; + let iend = (seq_start as usize).wrapping_add(seq_size) as *const u8; + let ostart = dst; + let oend = (dst as usize).wrapping_add(max_dst_size) as *mut u8; + let mut op = dst; + let mut nb_seq = 0i32; + let header_size = decode_seq_headers(dctx, &mut nb_seq, ip, seq_size); + if ERR_isError(header_size) { + return header_size; + } + let ip = ip.add(header_size); + dctx.flag_repeat_table = 0; + + let lit_limit = dctx.lit_ptr.add(dctx.lit_size); + let mut lit_ptr = dctx.lit_ptr; + if nb_seq != 0 { + let mut state = SequenceState { + stream: DStream { + bit_container: 0, + bits_consumed: 0, + ptr: ptr::null(), + start: ptr::null(), + }, + state_ll: FseDState { + state: 0, + table: ptr::null(), + }, + state_off: FseDState { + state: 0, + table: ptr::null(), + }, + state_ml: FseDState { + state: 0, + table: ptr::null(), + }, + prev_offset: [REPCODE_STARTVALUE; REPCODE_NUM], + }; + let error = init_dstream( + &mut state.stream, + ip, + iend.wrapping_sub(ip as usize) as usize, + ); + if ERR_isError(error) { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + fse_init_dstate( + &mut state.state_ll, + &mut state.stream, + dctx.ll_table.as_ptr(), + ); + fse_init_dstate( + &mut state.state_off, + &mut state.stream, + dctx.off_table.as_ptr(), + ); + fse_init_dstate( + &mut state.state_ml, + &mut state.stream, + dctx.ml_table.as_ptr(), + ); + + let mut sequence = Sequence { + lit_length: 0, + match_length: 0, + offset: REPCODE_STARTVALUE, + }; + while reload_dstream(&mut state.stream) <= DSTREAM_COMPLETED && nb_seq != 0 { + nb_seq -= 1; + decode_sequence(&mut sequence, &mut state); + let produced = exec_sequence( + op, + sequence, + &mut lit_ptr, + lit_limit, + dctx.base, + dctx.v_base, + dctx.dict_end, + oend, + ); + if ERR_isError(produced) { + return produced; + } + op = op.add(produced); + } + if nb_seq != 0 { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + } + + let last_literal_size = (lit_limit as usize).wrapping_sub(lit_ptr as usize); + if lit_ptr as usize > lit_limit as usize { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + if (op as usize).wrapping_add(last_literal_size) > oend as usize { + return ERROR(ZstdErrorCode::DstSizeTooSmall); + } + if last_literal_size != 0 { + ptr::copy(lit_ptr, op, last_literal_size); + op = op.add(last_literal_size); + } + (op as usize).wrapping_sub(ostart as usize) +} + +unsafe fn check_continuity(dctx: &mut ZSTDv06_Dctx, dst: *const u8) { + if dst != dctx.previous_dst_end { + dctx.dict_end = dctx.previous_dst_end; + let delta = (dctx.previous_dst_end as usize).wrapping_sub(dctx.base as usize); + dctx.v_base = (dst as usize).wrapping_sub(delta) as *const u8; + dctx.base = dst; + dctx.previous_dst_end = dst; + } +} + +unsafe fn decompress_block_internal( + dctx: &mut ZSTDv06_Dctx, + dst: *mut u8, + dst_capacity: usize, + src: *const u8, + src_size: usize, +) -> usize { + if src_size >= BLOCKSIZE { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + let literal_size = decode_literals_block(dctx, src, src_size); + if ERR_isError(literal_size) { + return literal_size; + } + decompress_sequences( + dctx, + dst, + dst_capacity, + src.add(literal_size), + src_size - literal_size, + ) +} + +unsafe fn decompress_frame( + dctx: &mut ZSTDv06_Dctx, + dst: *mut u8, + dst_capacity: usize, + src: *const u8, + src_size: usize, +) -> usize { + if src_size < FRAME_HEADER_SIZE_MIN + BLOCK_HEADER_SIZE { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + let header_size = frame_header_size(src, FRAME_HEADER_SIZE_MIN); + if ERR_isError(header_size) { + return header_size; + } + if src_size < header_size + BLOCK_HEADER_SIZE { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + + let mut ip = src.add(header_size); + let iend = src.add(src_size); + let mut remaining = src_size - header_size; + if decode_frame_header(dctx, src, header_size) != 0 { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + + let ostart = dst; + let mut op = dst; + let oend = (dst as usize).wrapping_add(dst_capacity) as *mut u8; + let mut properties = BlockProperties { + block_type: BT_COMPRESSED, + orig_size: 0, + }; + loop { + let block_size = get_block_size( + ip, + (iend as usize).wrapping_sub(ip as usize), + &mut properties, + ); + if ERR_isError(block_size) { + return block_size; + } + ip = ip.add(BLOCK_HEADER_SIZE); + remaining -= BLOCK_HEADER_SIZE; + if block_size > remaining { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + let decoded = match properties.block_type { + BT_COMPRESSED => decompress_block_internal( + dctx, + op, + (oend as usize).wrapping_sub(op as usize), + ip, + block_size, + ), + BT_RAW => copy_raw_block( + op, + (oend as usize).wrapping_sub(op as usize), + ip, + block_size, + ), + BT_RLE => return ERROR(ZstdErrorCode::Generic), + BT_END => { + if remaining != 0 { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + 0 + } + _ => return ERROR(ZstdErrorCode::Generic), + }; + if block_size == 0 { + break; + } + if ERR_isError(decoded) { + return decoded; + } + op = op.add(decoded); + ip = ip.add(block_size); + remaining -= block_size; + } + (op as usize).wrapping_sub(ostart as usize) +} + +unsafe fn ref_dict_content(dctx: &mut ZSTDv06_Dctx, dict: *const u8, dict_size: usize) { + dctx.dict_end = dctx.previous_dst_end; + let delta = (dctx.previous_dst_end as usize).wrapping_sub(dctx.base as usize); + dctx.v_base = (dict as usize).wrapping_sub(delta) as *const u8; + dctx.base = dict; + dctx.previous_dst_end = (dict as usize).wrapping_add(dict_size) as *const u8; +} + +unsafe fn load_entropy( + dctx: &mut ZSTDv06_Dctx, + mut dict: *const u8, + mut dict_size: usize, +) -> usize { + let h_size = huf_read_dtable_x4(&mut dctx.huf_table_x4, dict, dict_size); + if ERR_isError(h_size) || h_size > dict_size { + return ERROR(ZstdErrorCode::DictionaryCorrupted); + } + dict = dict.add(h_size); + dict_size -= h_size; + + let mut off_norm = [0i16; 256]; + let mut off_max = MAX_OFF; + let mut off_log = 0; + let off_size = fse_read_ncount(&mut off_norm, &mut off_max, &mut off_log, dict, dict_size); + if ERR_isError(off_size) || off_log > OFF_FSE_LOG { + return ERROR(ZstdErrorCode::DictionaryCorrupted); + } + let result = fse_build_dtable(&mut dctx.off_table, &off_norm, off_max, off_log); + if ERR_isError(result) { + return ERROR(ZstdErrorCode::DictionaryCorrupted); + } + dict = dict.add(off_size); + dict_size -= off_size; + + let mut ml_norm = [0i16; 256]; + let mut ml_max = MAX_ML; + let mut ml_log = 0; + let ml_size = fse_read_ncount(&mut ml_norm, &mut ml_max, &mut ml_log, dict, dict_size); + if ERR_isError(ml_size) || ml_log > ML_FSE_LOG { + return ERROR(ZstdErrorCode::DictionaryCorrupted); + } + let result = fse_build_dtable(&mut dctx.ml_table, &ml_norm, ml_max, ml_log); + if ERR_isError(result) { + return ERROR(ZstdErrorCode::DictionaryCorrupted); + } + dict = dict.add(ml_size); + dict_size -= ml_size; + + let mut ll_norm = [0i16; 256]; + let mut ll_max = MAX_LL; + let mut ll_log = 0; + let ll_size = fse_read_ncount(&mut ll_norm, &mut ll_max, &mut ll_log, dict, dict_size); + if ERR_isError(ll_size) || ll_log > LL_FSE_LOG { + return ERROR(ZstdErrorCode::DictionaryCorrupted); + } + let result = fse_build_dtable(&mut dctx.ll_table, &ll_norm, ll_max, ll_log); + if ERR_isError(result) { + return ERROR(ZstdErrorCode::DictionaryCorrupted); + } + + dctx.flag_repeat_table = 1; + h_size + off_size + ml_size + ll_size +} + +unsafe fn insert_dictionary(dctx: &mut ZSTDv06_Dctx, dict: *const u8, dict_size: usize) -> usize { + if dict_size < 4 || read_le32(dict) != ZSTD_DICT_MAGIC { + ref_dict_content(dctx, dict, dict_size); + return 0; + } + let mut dict_ptr = dict.add(4); + let mut remaining = dict_size - 4; + let entropy_size = load_entropy(dctx, dict_ptr, remaining); + if ERR_isError(entropy_size) { + return ERROR(ZstdErrorCode::DictionaryCorrupted); + } + dict_ptr = dict_ptr.add(entropy_size); + remaining -= entropy_size; + ref_dict_content(dctx, dict_ptr, remaining); + 0 +} + +unsafe fn decompress_begin_using_dict( + dctx: &mut ZSTDv06_Dctx, + dict: *const u8, + dict_size: usize, +) -> usize { + let result = decompress_begin(dctx); + if ERR_isError(result) { + return result; + } + if !dict.is_null() && dict_size != 0 { + let result = insert_dictionary(dctx, dict, dict_size); + if ERR_isError(result) { + return ERROR(ZstdErrorCode::DictionaryCorrupted); + } + } + 0 +} + +unsafe fn decompress_using_prepared( + dctx: &mut ZSTDv06_Dctx, + ref_dctx: *const ZSTDv06_Dctx, + dst: *mut u8, + dst_capacity: usize, + src: *const u8, + src_size: usize, +) -> usize { + copy_dctx(dctx, ref_dctx); + check_continuity(dctx, dst); + decompress_frame(dctx, dst, dst_capacity, src, src_size) +} + +unsafe fn decompress_using_dict( + dctx: &mut ZSTDv06_Dctx, + dst: *mut u8, + dst_capacity: usize, + src: *const u8, + src_size: usize, + dict: *const u8, + dict_size: usize, +) -> usize { + let _ = decompress_begin_using_dict(dctx, dict, dict_size); + check_continuity(dctx, dst); + decompress_frame(dctx, dst, dst_capacity, src, src_size) +} + +unsafe fn decompress_dctx( + dctx: &mut ZSTDv06_Dctx, + dst: *mut u8, + dst_capacity: usize, + src: *const u8, + src_size: usize, +) -> usize { + decompress_using_dict(dctx, dst, dst_capacity, src, src_size, ptr::null(), 0) +} + +unsafe fn decompress_one_shot( + dst: *mut u8, + dst_capacity: usize, + src: *const u8, + src_size: usize, +) -> usize { + let dctx = create_dctx(); + if dctx.is_null() { + return ERROR(ZstdErrorCode::MemoryAllocation); + } + let result = decompress_dctx(&mut *dctx, dst, dst_capacity, src, src_size); + free_dctx(dctx); + result +} + +unsafe fn error_frame_size_info(c_size: *mut usize, d_bound: *mut u64, result: usize) { + *c_size = result; + *d_bound = ZSTD_CONTENTSIZE_ERROR; +} + +unsafe fn find_frame_size_info( + src: *const u8, + src_size: usize, + c_size: *mut usize, + d_bound: *mut u64, +) { + let mut ip = src; + let mut remaining = src_size; + let mut nb_blocks = 0usize; + let mut properties = BlockProperties { + block_type: BT_COMPRESSED, + orig_size: 0, + }; + + let header_size = frame_header_size(src, src_size); + if ERR_isError(header_size) { + error_frame_size_info(c_size, d_bound, header_size); + return; + } + if read_le32(src) != ZSTD_MAGIC_NUMBER { + error_frame_size_info(c_size, d_bound, ERROR(ZstdErrorCode::PrefixUnknown)); + return; + } + if src_size < header_size + BLOCK_HEADER_SIZE { + error_frame_size_info(c_size, d_bound, ERROR(ZstdErrorCode::SrcSizeWrong)); + return; + } + ip = ip.add(header_size); + remaining -= header_size; + + loop { + let block_size = get_block_size(ip, remaining, &mut properties); + if ERR_isError(block_size) { + error_frame_size_info(c_size, d_bound, block_size); + return; + } + ip = ip.add(BLOCK_HEADER_SIZE); + remaining -= BLOCK_HEADER_SIZE; + if block_size > remaining { + error_frame_size_info(c_size, d_bound, ERROR(ZstdErrorCode::SrcSizeWrong)); + return; + } + if block_size == 0 { + break; + } + ip = ip.add(block_size); + remaining -= block_size; + nb_blocks = nb_blocks.wrapping_add(1); + } + *c_size = (ip as usize).wrapping_sub(src as usize); + *d_bound = nb_blocks.wrapping_mul(BLOCKSIZE) as u64; +} + +unsafe fn next_src_size_to_decompress(dctx: &ZSTDv06_Dctx) -> usize { + dctx.expected +} + +unsafe fn decompress_continue( + dctx: &mut ZSTDv06_Dctx, + dst: *mut u8, + dst_capacity: usize, + src: *const u8, + src_size: usize, +) -> usize { + if src_size != dctx.expected { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + if dst_capacity != 0 { + check_continuity(dctx, dst); + } + + if dctx.stage == STAGE_GET_FRAME_HEADER_SIZE { + let header_size = frame_header_size(src, src_size); + if ERR_isError(header_size) { + return header_size; + } + ptr::copy_nonoverlapping(src, dctx.header_buffer.as_mut_ptr(), FRAME_HEADER_SIZE_MIN); + dctx.header_size = header_size; + if header_size > FRAME_HEADER_SIZE_MIN { + dctx.expected = header_size - FRAME_HEADER_SIZE_MIN; + dctx.stage = STAGE_DECODE_FRAME_HEADER; + return 0; + } + dctx.expected = 0; + dctx.stage = STAGE_DECODE_FRAME_HEADER; + } + + if dctx.stage == STAGE_DECODE_FRAME_HEADER { + ptr::copy_nonoverlapping( + src, + dctx.header_buffer.as_mut_ptr().add(FRAME_HEADER_SIZE_MIN), + dctx.expected, + ); + let result = decode_frame_header(dctx, dctx.header_buffer.as_ptr(), dctx.header_size); + if ERR_isError(result) { + return result; + } + dctx.expected = BLOCK_HEADER_SIZE; + dctx.stage = STAGE_DECODE_BLOCK_HEADER; + return 0; + } + + match dctx.stage { + STAGE_DECODE_BLOCK_HEADER => { + let mut properties = BlockProperties { + block_type: BT_COMPRESSED, + orig_size: 0, + }; + let block_size = get_block_size(src, BLOCK_HEADER_SIZE, &mut properties); + if ERR_isError(block_size) { + return block_size; + } + if properties.block_type == BT_END { + dctx.expected = 0; + dctx.stage = STAGE_GET_FRAME_HEADER_SIZE; + } else { + dctx.expected = block_size; + dctx.b_type = properties.block_type; + dctx.stage = STAGE_DECOMPRESS_BLOCK; + } + 0 + } + STAGE_DECOMPRESS_BLOCK => { + let result = match dctx.b_type { + BT_COMPRESSED => decompress_block_internal(dctx, dst, dst_capacity, src, src_size), + BT_RAW => copy_raw_block(dst, dst_capacity, src, src_size), + BT_RLE => ERROR(ZstdErrorCode::Generic), + BT_END => 0, + _ => ERROR(ZstdErrorCode::Generic), + }; + dctx.stage = STAGE_DECODE_BLOCK_HEADER; + dctx.expected = BLOCK_HEADER_SIZE; + if ERR_isError(result) { + return result; + } + dctx.previous_dst_end = (dst as usize).wrapping_add(result) as *const u8; + result + } + _ => ERROR(ZstdErrorCode::Generic), + } +} + +#[repr(C)] +pub struct ZBUFFv06_DCtx { + zd: *mut ZSTDv06_Dctx, + f_params: ZSTDv06_frameParams, + stage: u32, + in_buff: *mut u8, + in_buff_size: usize, + in_pos: usize, + out_buff: *mut u8, + out_buff_size: usize, + out_start: usize, + out_end: usize, + block_size: usize, + header_buffer: [u8; FRAME_HEADER_SIZE_MAX], + lh_size: usize, +} + +const BUFF_INIT: u32 = 0; +const BUFF_LOAD_HEADER: u32 = 1; +const BUFF_READ: u32 = 2; +const BUFF_LOAD: u32 = 3; +const BUFF_FLUSH: u32 = 4; + +unsafe fn buff_create_dctx() -> *mut ZBUFFv06_DCtx { + let zbd = libc::malloc(std::mem::size_of::()) as *mut ZBUFFv06_DCtx; + if zbd.is_null() { + return ptr::null_mut(); + } + ptr::write_bytes(zbd.cast::(), 0, std::mem::size_of::()); + (*zbd).zd = create_dctx(); + if (*zbd).zd.is_null() { + buff_free_dctx(zbd); + return ptr::null_mut(); + } + (*zbd).stage = BUFF_INIT; + zbd +} + +unsafe fn buff_free_dctx(zbd: *mut ZBUFFv06_DCtx) -> usize { + if zbd.is_null() { + return 0; + } + free_dctx((*zbd).zd); + libc::free((*zbd).in_buff.cast::()); + libc::free((*zbd).out_buff.cast::()); + libc::free(zbd.cast::()); + 0 +} + +unsafe fn buff_decompress_init_dictionary( + zbd: &mut ZBUFFv06_DCtx, + dict: *const u8, + dict_size: usize, +) -> usize { + zbd.stage = BUFF_LOAD_HEADER; + zbd.lh_size = 0; + zbd.in_pos = 0; + zbd.out_start = 0; + zbd.out_end = 0; + decompress_begin_using_dict(&mut *zbd.zd, dict, dict_size) +} + +unsafe fn buff_limit_copy( + dst: *mut u8, + dst_capacity: usize, + src: *const u8, + src_size: usize, +) -> usize { + let length = dst_capacity.min(src_size); + if length != 0 { + ptr::copy(src, dst, length); + } + length +} + +unsafe fn buff_decompress_continue( + zbd: &mut ZBUFFv06_DCtx, + dst: *mut u8, + dst_capacity_ptr: *mut usize, + src: *const u8, + src_size_ptr: *mut usize, +) -> usize { + let istart = src as usize; + let mut ip = istart; + let iend = istart.wrapping_add(*src_size_ptr); + let ostart = dst as usize; + let mut op = ostart; + let oend = ostart.wrapping_add(*dst_capacity_ptr); + let mut not_done = true; + + while not_done { + match zbd.stage { + BUFF_INIT => return ERROR(ZstdErrorCode::InitMissing), + BUFF_LOAD_HEADER => { + let header_size = + get_frame_params(&mut zbd.f_params, zbd.header_buffer.as_ptr(), zbd.lh_size); + if header_size != 0 { + let to_load = header_size.wrapping_sub(zbd.lh_size); + if ERR_isError(header_size) { + return header_size; + } + let available = iend.wrapping_sub(ip); + if to_load > available { + if available != 0 { + ptr::copy( + src.add(ip.wrapping_sub(istart)), + zbd.header_buffer.as_mut_ptr().add(zbd.lh_size), + available, + ); + } + zbd.lh_size += available; + *dst_capacity_ptr = 0; + return (header_size - zbd.lh_size) + BLOCK_HEADER_SIZE; + } + if to_load != 0 { + ptr::copy( + src.add(ip.wrapping_sub(istart)), + zbd.header_buffer.as_mut_ptr().add(zbd.lh_size), + to_load, + ); + } + zbd.lh_size = header_size; + ip = ip.wrapping_add(to_load); + continue; + } + + let h1_size = next_src_size_to_decompress(&*zbd.zd); + let h1_result = decompress_continue( + &mut *zbd.zd, + ptr::null_mut(), + 0, + zbd.header_buffer.as_ptr(), + h1_size, + ); + if ERR_isError(h1_result) { + return h1_result; + } + if h1_size < zbd.lh_size { + let h2_size = next_src_size_to_decompress(&*zbd.zd); + let h2_result = decompress_continue( + &mut *zbd.zd, + ptr::null_mut(), + 0, + zbd.header_buffer.as_ptr().add(h1_size), + h2_size, + ); + if ERR_isError(h2_result) { + return h2_result; + } + } + + let block_size = (1usize << zbd.f_params.window_log as usize).min(BLOCKSIZE); + zbd.block_size = block_size; + if zbd.in_buff_size < block_size { + libc::free(zbd.in_buff.cast::()); + zbd.in_buff_size = block_size; + zbd.in_buff = libc::malloc(block_size) as *mut u8; + if zbd.in_buff.is_null() { + return ERROR(ZstdErrorCode::MemoryAllocation); + } + } + let needed_out_size = (1usize << zbd.f_params.window_log as usize) + + block_size + + WILDCOPY_OVERLENGTH * 2; + if zbd.out_buff_size < needed_out_size { + libc::free(zbd.out_buff.cast::()); + zbd.out_buff_size = needed_out_size; + zbd.out_buff = libc::malloc(needed_out_size) as *mut u8; + if zbd.out_buff.is_null() { + return ERROR(ZstdErrorCode::MemoryAllocation); + } + } + zbd.stage = BUFF_READ; + } + BUFF_READ => { + let needed_in_size = next_src_size_to_decompress(&*zbd.zd); + if needed_in_size == 0 { + zbd.stage = BUFF_INIT; + not_done = false; + continue; + } + if iend.wrapping_sub(ip) >= needed_in_size { + let decoded_size = decompress_continue( + &mut *zbd.zd, + zbd.out_buff.add(zbd.out_start), + zbd.out_buff_size - zbd.out_start, + ip as *const u8, + needed_in_size, + ); + if ERR_isError(decoded_size) { + return decoded_size; + } + ip = ip.wrapping_add(needed_in_size); + if decoded_size == 0 { + continue; + } + zbd.out_end = zbd.out_start + decoded_size; + zbd.stage = BUFF_FLUSH; + continue; + } + if ip == iend { + not_done = false; + continue; + } + zbd.stage = BUFF_LOAD; + } + BUFF_LOAD => { + let needed_in_size = next_src_size_to_decompress(&*zbd.zd); + let to_load = needed_in_size.wrapping_sub(zbd.in_pos); + if to_load > zbd.in_buff_size.wrapping_sub(zbd.in_pos) { + return ERROR(ZstdErrorCode::CorruptionDetected); + } + let loaded_size = buff_limit_copy( + zbd.in_buff.add(zbd.in_pos), + to_load, + ip as *const u8, + iend.wrapping_sub(ip), + ); + ip = ip.wrapping_add(loaded_size); + zbd.in_pos += loaded_size; + if loaded_size < to_load { + not_done = false; + continue; + } + let decoded_size = decompress_continue( + &mut *zbd.zd, + zbd.out_buff.add(zbd.out_start), + zbd.out_buff_size - zbd.out_start, + zbd.in_buff, + needed_in_size, + ); + if ERR_isError(decoded_size) { + return decoded_size; + } + zbd.in_pos = 0; + if decoded_size == 0 { + zbd.stage = BUFF_READ; + continue; + } + zbd.out_end = zbd.out_start + decoded_size; + zbd.stage = BUFF_FLUSH; + } + BUFF_FLUSH => { + let to_flush_size = zbd.out_end.wrapping_sub(zbd.out_start); + let flushed_size = buff_limit_copy( + op as *mut u8, + oend.wrapping_sub(op), + zbd.out_buff.add(zbd.out_start), + to_flush_size, + ); + op = op.wrapping_add(flushed_size); + zbd.out_start += flushed_size; + if flushed_size == to_flush_size { + zbd.stage = BUFF_READ; + if zbd.out_start + zbd.block_size > zbd.out_buff_size { + zbd.out_start = 0; + zbd.out_end = 0; + } + } else { + not_done = false; + } + } + _ => return ERROR(ZstdErrorCode::Generic), + } + } + + *src_size_ptr = ip.wrapping_sub(istart); + *dst_capacity_ptr = op.wrapping_sub(ostart); + let mut hint = next_src_size_to_decompress(&*zbd.zd); + if hint > BLOCK_HEADER_SIZE { + hint = hint.wrapping_add(BLOCK_HEADER_SIZE); + } + hint.wrapping_sub(zbd.in_pos) +} + +#[no_mangle] +pub extern "C" fn ZSTDv06_isError(code: usize) -> c_uint { + ERR_isError(code) as c_uint +} + +#[no_mangle] +pub extern "C" fn ZSTDv06_getErrorName(code: usize) -> *const c_char { + ERR_getErrorName(code) +} + +#[no_mangle] +pub extern "C" fn ZBUFFv06_isError(code: usize) -> c_uint { + ERR_isError(code) as c_uint +} + +#[no_mangle] +pub extern "C" fn ZBUFFv06_getErrorName(code: usize) -> *const c_char { + ERR_getErrorName(code) +} + +#[no_mangle] +pub extern "C" fn ZSTDv06_sizeofDCtx() -> usize { + std::mem::size_of::() +} + +#[no_mangle] +pub unsafe extern "C" fn ZSTDv06_decompressBegin(dctx: *mut ZSTDv06_Dctx) -> usize { + decompress_begin(&mut *dctx) +} + +#[no_mangle] +pub unsafe extern "C" fn ZSTDv06_createDCtx() -> *mut ZSTDv06_Dctx { + create_dctx() +} + +#[no_mangle] +pub unsafe extern "C" fn ZSTDv06_freeDCtx(dctx: *mut ZSTDv06_Dctx) -> usize { + free_dctx(dctx) +} + +#[no_mangle] +pub unsafe extern "C" fn ZSTDv06_copyDCtx( + dctx: *mut ZSTDv06_Dctx, + prepared_dctx: *const ZSTDv06_Dctx, +) { + copy_dctx(dctx, prepared_dctx); +} + +#[no_mangle] +pub unsafe extern "C" fn ZSTDv06_getFrameParams( + fparams: *mut ZSTDv06_frameParams, + src: *const c_void, + src_size: usize, +) -> usize { + get_frame_params(&mut *fparams, src.cast::(), src_size) +} + +#[no_mangle] +pub unsafe extern "C" fn ZSTDv06_decompressBlock( + dctx: *mut ZSTDv06_Dctx, + dst: *mut c_void, + dst_capacity: usize, + src: *const c_void, + src_size: usize, +) -> usize { + check_continuity(&mut *dctx, dst.cast::()); + decompress_block_internal( + &mut *dctx, + dst.cast::(), + dst_capacity, + src.cast::(), + src_size, + ) +} + +#[no_mangle] +pub unsafe extern "C" fn ZSTDv06_decompress_usingPreparedDCtx( + dctx: *mut ZSTDv06_Dctx, + ref_dctx: *const ZSTDv06_Dctx, + dst: *mut c_void, + dst_capacity: usize, + src: *const c_void, + src_size: usize, +) -> usize { + decompress_using_prepared( + &mut *dctx, + ref_dctx, + dst.cast::(), + dst_capacity, + src.cast::(), + src_size, + ) +} + +#[no_mangle] +pub unsafe extern "C" fn ZSTDv06_decompress_usingDict( + dctx: *mut ZSTDv06_Dctx, + dst: *mut c_void, + dst_capacity: usize, + src: *const c_void, + src_size: usize, + dict: *const c_void, + dict_size: usize, +) -> usize { + decompress_using_dict( + &mut *dctx, + dst.cast::(), + dst_capacity, + src.cast::(), + src_size, + dict.cast::(), + dict_size, + ) +} + +#[no_mangle] +pub unsafe extern "C" fn ZSTDv06_decompressDCtx( + dctx: *mut ZSTDv06_Dctx, + dst: *mut c_void, + dst_capacity: usize, + src: *const c_void, + src_size: usize, +) -> usize { + decompress_dctx( + &mut *dctx, + dst.cast::(), + dst_capacity, + src.cast::(), + src_size, + ) +} + +#[no_mangle] +pub unsafe extern "C" fn ZSTDv06_decompress( + dst: *mut c_void, + dst_capacity: usize, + src: *const c_void, + src_size: usize, +) -> usize { + decompress_one_shot(dst.cast::(), dst_capacity, src.cast::(), src_size) +} + +#[no_mangle] +pub unsafe extern "C" fn ZSTDv06_findFrameSizeInfoLegacy( + src: *const c_void, + src_size: usize, + c_size: *mut usize, + d_bound: *mut u64, +) { + find_frame_size_info(src.cast::(), src_size, c_size, d_bound); +} + +#[no_mangle] +pub unsafe extern "C" fn ZSTDv06_nextSrcSizeToDecompress(dctx: *mut ZSTDv06_Dctx) -> usize { + next_src_size_to_decompress(&*dctx) +} + +#[no_mangle] +pub unsafe extern "C" fn ZSTDv06_decompressContinue( + dctx: *mut ZSTDv06_Dctx, + dst: *mut c_void, + dst_capacity: usize, + src: *const c_void, + src_size: usize, +) -> usize { + decompress_continue( + &mut *dctx, + dst.cast::(), + dst_capacity, + src.cast::(), + src_size, + ) +} + +#[no_mangle] +pub unsafe extern "C" fn ZSTDv06_decompressBegin_usingDict( + dctx: *mut ZSTDv06_Dctx, + dict: *const c_void, + dict_size: usize, +) -> usize { + decompress_begin_using_dict(&mut *dctx, dict.cast::(), dict_size) +} + +#[no_mangle] +pub unsafe extern "C" fn ZBUFFv06_createDCtx() -> *mut ZBUFFv06_DCtx { + buff_create_dctx() +} + +#[no_mangle] +pub unsafe extern "C" fn ZBUFFv06_freeDCtx(dctx: *mut ZBUFFv06_DCtx) -> usize { + buff_free_dctx(dctx) +} + +#[no_mangle] +pub unsafe extern "C" fn ZBUFFv06_decompressInit(dctx: *mut ZBUFFv06_DCtx) -> usize { + buff_decompress_init_dictionary(&mut *dctx, ptr::null(), 0) +} + +#[no_mangle] +pub unsafe extern "C" fn ZBUFFv06_decompressInitDictionary( + dctx: *mut ZBUFFv06_DCtx, + dict: *const c_void, + dict_size: usize, +) -> usize { + buff_decompress_init_dictionary(&mut *dctx, dict.cast::(), dict_size) +} + +#[no_mangle] +pub unsafe extern "C" fn ZBUFFv06_decompressContinue( + dctx: *mut ZBUFFv06_DCtx, + dst: *mut c_void, + dst_capacity_ptr: *mut usize, + src: *const c_void, + src_size_ptr: *mut usize, +) -> usize { + buff_decompress_continue( + &mut *dctx, + dst.cast::(), + dst_capacity_ptr, + src.cast::(), + src_size_ptr, + ) +} + +#[no_mangle] +pub extern "C" fn ZBUFFv06_recommendedDInSize() -> usize { + BLOCKSIZE + BLOCK_HEADER_SIZE +} + +#[no_mangle] +pub extern "C" fn ZBUFFv06_recommendedDOutSize() -> usize { + BLOCKSIZE +} + +#[no_mangle] +pub extern "C" fn FSEv06_isError(code: usize) -> c_uint { + ERR_isError(code) as c_uint +} + +#[no_mangle] +pub extern "C" fn FSEv06_getErrorName(code: usize) -> *const c_char { + ERR_getErrorName(code) +} + +#[no_mangle] +pub unsafe extern "C" fn FSEv06_createDTable(table_log: c_uint) -> *mut u32 { + let table_log = table_log.min(FSE_TABLELOG_ABSOLUTE_MAX) as usize; + libc::malloc((1 + (1usize << table_log)) * std::mem::size_of::()) as *mut u32 +} + +#[no_mangle] +pub unsafe extern "C" fn FSEv06_freeDTable(table: *mut u32) { + libc::free(table.cast::()); +} + +#[no_mangle] +pub unsafe extern "C" fn FSEv06_readNCount( + normalized_counter: *mut i16, + max_symbol_value: *mut c_uint, + table_log: *mut c_uint, + src: *const c_void, + src_size: usize, +) -> usize { + fse_read_ncount( + &mut *(normalized_counter as *mut [i16; 256]), + &mut *max_symbol_value, + &mut *table_log, + src.cast::(), + src_size, + ) +} + +#[no_mangle] +pub unsafe extern "C" fn FSEv06_buildDTable( + table: *mut u32, + normalized_counter: *const i16, + max_symbol_value: c_uint, + table_log: c_uint, +) -> usize { + let len = 1usize << (table_log as usize).min(FSE_TABLELOG_ABSOLUTE_MAX as usize); + fse_build_dtable( + slice::from_raw_parts_mut(table, 1 + len), + &*(normalized_counter as *const [i16; 256]), + max_symbol_value, + table_log, + ) +} + +#[no_mangle] +pub unsafe extern "C" fn FSEv06_buildDTable_rle(table: *mut u32, symbol: u8) -> usize { + fse_build_dtable_rle( + slice::from_raw_parts_mut(table, 1 + (1usize << FSE_MAX_TABLELOG)), + symbol, + ) +} + +#[no_mangle] +pub unsafe extern "C" fn FSEv06_buildDTable_raw(table: *mut u32, nb_bits: c_uint) -> usize { + fse_build_dtable_raw( + slice::from_raw_parts_mut(table, 1 + (1usize << FSE_MAX_TABLELOG)), + nb_bits, + ) +} + +#[no_mangle] +pub unsafe extern "C" fn FSEv06_decompress_usingDTable( + dst: *mut c_void, + dst_capacity: usize, + src: *const c_void, + src_size: usize, + table: *const u32, +) -> usize { + fse_decompress_using_dtable( + dst.cast::(), + dst_capacity, + src.cast::(), + src_size, + slice::from_raw_parts(table, 1 + (1usize << FSE_MAX_TABLELOG)), + ) +} + +#[no_mangle] +pub unsafe extern "C" fn FSEv06_decompress( + dst: *mut c_void, + max_dst_size: usize, + src: *const c_void, + src_size: usize, +) -> usize { + fse_decompress(dst.cast::(), max_dst_size, src.cast::(), src_size) +} + +#[no_mangle] +pub unsafe extern "C" fn HUFv06_readDTableX2( + table: *mut u16, + src: *const c_void, + src_size: usize, +) -> usize { + huf_read_dtable_x2( + &mut *(table as *mut [u16; 1 + (1 << HUF_MAX_TABLELOG)]), + src.cast::(), + src_size, + ) +} + +#[no_mangle] +pub unsafe extern "C" fn HUFv06_readDTableX4( + table: *mut u32, + src: *const c_void, + src_size: usize, +) -> usize { + huf_read_dtable_x4( + &mut *(table as *mut [u32; 1 + (1 << HUF_MAX_TABLELOG)]), + src.cast::(), + src_size, + ) +} + +#[no_mangle] +pub unsafe extern "C" fn HUFv06_decompress1X2_usingDTable( + dst: *mut c_void, + dst_size: usize, + src: *const c_void, + src_size: usize, + table: *const u16, +) -> usize { + huf_decompress1x2_using_dtable( + dst.cast::(), + dst_size, + src.cast::(), + src_size, + &*(table as *const [u16; 1 + (1 << HUF_MAX_TABLELOG)]), + ) +} + +#[no_mangle] +pub unsafe extern "C" fn HUFv06_decompress1X2( + dst: *mut c_void, + dst_size: usize, + src: *const c_void, + src_size: usize, +) -> usize { + huf_decompress1x2(dst.cast::(), dst_size, src.cast::(), src_size) +} + +#[no_mangle] +pub unsafe extern "C" fn HUFv06_decompress4X2_usingDTable( + dst: *mut c_void, + dst_size: usize, + src: *const c_void, + src_size: usize, + table: *const u16, +) -> usize { + huf_decompress4x2_using_dtable( + dst.cast::(), + dst_size, + src.cast::(), + src_size, + &*(table as *const [u16; 1 + (1 << HUF_MAX_TABLELOG)]), + ) +} + +#[no_mangle] +pub unsafe extern "C" fn HUFv06_decompress4X2( + dst: *mut c_void, + dst_size: usize, + src: *const c_void, + src_size: usize, +) -> usize { + let mut table = [0u16; 1 + (1 << HUF_MAX_TABLELOG)]; + table[0] = HUF_MAX_TABLELOG as u16; + let header_size = huf_read_dtable_x2(&mut table, src.cast::(), src_size); + if ERR_isError(header_size) { + return header_size; + } + if header_size >= src_size { + return ERROR(ZstdErrorCode::SrcSizeWrong); + } + huf_decompress4x2_using_dtable( + dst.cast::(), + dst_size, + src.cast::().add(header_size), + src_size - header_size, + &table, + ) +} + +#[no_mangle] +pub unsafe extern "C" fn HUFv06_decompress1X4_usingDTable( + dst: *mut c_void, + dst_size: usize, + src: *const c_void, + src_size: usize, + table: *const u32, +) -> usize { + huf_decompress1x4_using_dtable( + dst.cast::(), + dst_size, + src.cast::(), + src_size, + &*(table as *const [u32; 1 + (1 << HUF_MAX_TABLELOG)]), + ) +} + +#[no_mangle] +pub unsafe extern "C" fn HUFv06_decompress1X4( + dst: *mut c_void, + dst_size: usize, + src: *const c_void, + src_size: usize, +) -> usize { + huf_decompress1x4(dst.cast::(), dst_size, src.cast::(), src_size) +} + +#[no_mangle] +pub unsafe extern "C" fn HUFv06_decompress4X4_usingDTable( + dst: *mut c_void, + dst_size: usize, + src: *const c_void, + src_size: usize, + table: *const u32, +) -> usize { + huf_decompress4x4_using_dtable( + dst.cast::(), + dst_size, + src.cast::(), + src_size, + &*(table as *const [u32; 1 + (1 << HUF_MAX_TABLELOG)]), + ) +} + +#[no_mangle] +pub unsafe extern "C" fn HUFv06_decompress4X4( + dst: *mut c_void, + dst_size: usize, + src: *const c_void, + src_size: usize, +) -> usize { + huf_decompress4x4(dst.cast::(), dst_size, src.cast::(), src_size) +} + +#[no_mangle] +pub unsafe extern "C" fn HUFv06_decompress( + dst: *mut c_void, + dst_size: usize, + src: *const c_void, + src_size: usize, +) -> usize { + huf_decompress(dst.cast::(), dst_size, src.cast::(), src_size) +} + +#[cfg(test)] +mod tests { + use super::*; + + const RAW_FRAME: &[u8] = &[ + 0x26, 0xB5, 0x2F, 0xFD, 0x00, 0x40, 0x00, 0x0B, b'r', b'a', b'w', b' ', b'v', b'0', b'.', + b'6', b'!', b'!', b'!', 0xC0, 0x00, 0x00, + ]; + + const FCS_FRAME: &[u8] = &[ + 0x26, 0xB5, 0x2F, 0xFD, 0x40, 0x0B, 0x40, 0x00, 0x0B, b'r', b'a', b'w', b' ', b'v', b'0', + b'.', b'6', b'!', b'!', b'!', 0xC0, 0x00, 0x00, + ]; + + const COMPRESSED_FRAME: &[u8] = b"\x26\xB5\x2F\xFD\x42\xEF\x00\x00\xA6\x12\xB0\x7D\x1E\xB0\x01\x02\x00\x00\x54\xA0\xBA\x24\x8D\xC4\x25\xF2\x77\xFA\xFC\xFB\x94\x7A\xC7\xC9\x13\x03\x11\x24\x43\x63\x3C\x6D\x22\x03\x01\x50\x67\x56\xF5\x9F\x35\x84\x60\xA0\x60\x91\xC9\x0A\xDC\xAB\xAB\xE0\xE2\x81\xFA\xCF\xC6\xBA\xEB\xA8\xD1\x40\x39\x90\x4C\x64\xF8\xEB\x53\xE6\x18\x0B\x67\x12\xAD\xB8\x99\xB3\x5A\x6F\x8A\xF9\x63\x0C\xB8\xFA\x58\xE7\xF5\xE6\xE2\xE3\x67\xCC\x5D\x94\xC6\x56\xDC\x7F\x0C\x84\x4B\xA8\xF8\x63\x2E\x3E\x4E\x67\xCD\x9E\xAC\x04\x1E\x17\x27\xE4\x43\xF6\xA4\x56\xE4\x84\xC7\x9E\x34\x0E\x00\x35\x0B\x71\xB5\xC0\x2A\x5C\x26\x94\x22\x20\x8B\x4C\x8D\x13\x47\x58\x67\x15\x6C\xF1\x1C\x4B\x54\x10\x9D\x31\x50\x85\x4B\x54\x0E\x01\x4B\x3D\x01\xC0\x00\x00"; + + const COMPRESSED_OUTPUT: &[u8] = b"snowden is snowed in / he's now then in his snow den / when does the snow end?\ngoodbye little dog / you dug some holes in your day / they'll be hard to fill.\nwhen life shuts a door, / just open it. it\xE2\x80\x99s a door. / that is how doors work.\n"; + + unsafe fn decode(frame: &[u8], capacity: usize) -> Result, usize> { + let mut output = vec![0u8; capacity]; + let size = ZSTDv06_decompress( + output.as_mut_ptr().cast::(), + output.len(), + frame.as_ptr().cast::(), + frame.len(), + ); + if ZSTDv06_isError(size) != 0 { + Err(size) + } else { + output.truncate(size); + Ok(output) + } + } + + #[test] + fn decodes_raw_v06_frame() { + unsafe { + assert_eq!(decode(RAW_FRAME, 32).unwrap(), b"raw v0.6!!!"); + } + } + + #[test] + fn parses_content_size_and_frame_bound() { + unsafe { + let mut params = ZSTDv06_frameParams { + frame_content_size: 99, + window_log: 99, + }; + assert_eq!( + ZSTDv06_getFrameParams( + &mut params, + FCS_FRAME.as_ptr().cast::(), + FCS_FRAME.len(), + ), + 0 + ); + assert_eq!(params.frame_content_size, 11); + assert_eq!(params.window_log, 12); + + let mut c_size = 0; + let mut bound = 0; + ZSTDv06_findFrameSizeInfoLegacy( + RAW_FRAME.as_ptr().cast::(), + RAW_FRAME.len(), + &mut c_size, + &mut bound, + ); + assert_eq!(c_size, RAW_FRAME.len()); + assert_eq!(bound, BLOCKSIZE as u64); + } + } + + #[test] + fn reports_frozen_error_paths() { + unsafe { + let mut bad = RAW_FRAME.to_vec(); + bad[0] ^= 1; + assert_eq!( + decode(&bad, 32).unwrap_err(), + ERROR(ZstdErrorCode::CorruptionDetected) + ); + assert_eq!( + decode(&RAW_FRAME[..RAW_FRAME.len() - 1], 32).unwrap_err(), + ERROR(ZstdErrorCode::SrcSizeWrong) + ); + assert_eq!( + decode(RAW_FRAME, 1).unwrap_err(), + ERROR(ZstdErrorCode::DstSizeTooSmall) + ); + assert_eq!(ZSTDv06_freeDCtx(ptr::null_mut()), 0); + } + } + + #[test] + fn streaming_raw_frame_matches_one_shot() { + let expected = b"raw v0.6!!!"; + let mut output = vec![0u8; expected.len()]; + let mut input_offset = 0; + let mut output_offset = 0; + unsafe { + let dctx = ZSTDv06_createDCtx(); + assert!(!dctx.is_null()); + loop { + let needed = ZSTDv06_nextSrcSizeToDecompress(dctx); + if needed == 0 { + break; + } + assert!(input_offset + needed <= RAW_FRAME.len()); + let produced = ZSTDv06_decompressContinue( + dctx, + output.as_mut_ptr().add(output_offset).cast::(), + output.len() - output_offset, + RAW_FRAME.as_ptr().add(input_offset).cast::(), + needed, + ); + assert_eq!(ZSTDv06_isError(produced), 0); + input_offset += needed; + output_offset += produced; + } + assert_eq!(ZSTDv06_freeDCtx(dctx), 0); + } + assert_eq!(input_offset, RAW_FRAME.len()); + assert_eq!(output_offset, expected.len()); + assert_eq!(output, expected); + } + + #[test] + fn streaming_compressed_frame_matches_one_shot() { + unsafe { + let dctx = ZSTDv06_createDCtx(); + assert!(!dctx.is_null()); + let mut output = vec![0u8; COMPRESSED_OUTPUT.len()]; + let mut input_offset = 0; + let mut output_offset = 0; + loop { + let needed = ZSTDv06_nextSrcSizeToDecompress(dctx); + if needed == 0 { + break; + } + assert!(input_offset + needed <= COMPRESSED_FRAME.len()); + let produced = ZSTDv06_decompressContinue( + dctx, + output.as_mut_ptr().add(output_offset).cast::(), + output.len() - output_offset, + COMPRESSED_FRAME.as_ptr().add(input_offset).cast::(), + needed, + ); + assert_eq!(ZSTDv06_isError(produced), 0); + input_offset += needed; + output_offset += produced; + } + assert_eq!(ZSTDv06_freeDCtx(dctx), 0); + assert_eq!(input_offset, COMPRESSED_FRAME.len()); + assert_eq!(output_offset, COMPRESSED_OUTPUT.len()); + assert_eq!(output, COMPRESSED_OUTPUT); + } + } + + #[test] + fn buffered_streaming_raw_frame_matches_one_shot() { + let expected = b"raw v0.6!!!"; + let mut output = vec![0u8; expected.len()]; + let mut input_size = RAW_FRAME.len(); + let mut output_size = output.len(); + unsafe { + let dctx = ZBUFFv06_createDCtx(); + assert!(!dctx.is_null()); + assert_eq!(ZBUFFv06_decompressInit(dctx), 0); + let hint = ZBUFFv06_decompressContinue( + dctx, + output.as_mut_ptr().cast::(), + &mut output_size, + RAW_FRAME.as_ptr().cast::(), + &mut input_size, + ); + assert_eq!(ZBUFFv06_isError(hint), 0); + assert_eq!(&output[..output_size], expected); + assert_eq!(input_size, RAW_FRAME.len()); + assert_eq!(ZBUFFv06_freeDCtx(dctx), 0); + assert_eq!(ZBUFFv06_freeDCtx(ptr::null_mut()), 0); + } + } + + #[test] + fn buffered_streaming_compressed_frame_flushes_incrementally() { + let mut output = Vec::with_capacity(COMPRESSED_OUTPUT.len()); + let mut input_offset = 0; + unsafe { + let dctx = ZBUFFv06_createDCtx(); + assert!(!dctx.is_null()); + assert_eq!(ZBUFFv06_decompressInit(dctx), 0); + + for _ in 0..32 { + let mut input_size = COMPRESSED_FRAME.len() - input_offset; + let mut chunk = [0u8; 32]; + let mut output_size = chunk.len(); + let hint = ZBUFFv06_decompressContinue( + dctx, + chunk.as_mut_ptr().cast::(), + &mut output_size, + COMPRESSED_FRAME.as_ptr().add(input_offset).cast::(), + &mut input_size, + ); + assert_eq!(ZBUFFv06_isError(hint), 0); + input_offset += input_size; + output.extend_from_slice(&chunk[..output_size]); + if hint == 0 { + break; + } + } + + assert_eq!(ZBUFFv06_freeDCtx(dctx), 0); + } + assert_eq!(input_offset, COMPRESSED_FRAME.len()); + assert_eq!(output, COMPRESSED_OUTPUT); + } + + #[test] + fn decodes_frozen_v06_compressed_frame() { + unsafe { + assert_eq!( + decode(COMPRESSED_FRAME, COMPRESSED_OUTPUT.len()).unwrap(), + COMPRESSED_OUTPUT + ); + } + } +}