mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-28 15:41:40 +00:00
lib: zstd: update to latest Linux zstd 1.5.2
Update the zstd implementation to match Linux zstd 1.5.2 from commit 2aa14b1ab2. This was motivated by running into decompression corruption issues when trying to uncompress files compressed with newer versions of zstd. zstd users also claim significantly improved decompression times with newer zstd versions which is a side benefit. Original zstd code was copied from Linux commit 2aa14b1ab2 which is a custom-built implementation based on zstd 1.3.1. Linux switched to an implementation that is a copy of the upstream zstd code in Linux commit e0c1b49f5b, this results in a large code diff. However this should make future updates easier along with other benefits[1]. This commit is a straight mirror of the Linux zstd code, except to: - update a few #include that do not translate cleanly - linux/swab.h -> asm/byteorder.h - linux/limits.h -> linux/kernel.h - linux/module.h -> linux/compat.h - remove assert() from debug.h so it doesn't conflict with u-boot's assert() - strip out the compressor code as was done in the previous u-boot zstd - update existing zstd users to the new Linux zstd API - change the #define for MEM_STATIC to use INLINE_KEYWORD for codesize - add a new KConfig option that sets zstd build options to minify code based on zstd's ZSTD_LIB_MINIFY[2]. These changes were tested by booting a zstd 1.5.2 compressed kernel inside a FIT. And the squashfs changes by loading a file from zstd compressed squashfs with sqfsload. buildman was used to compile test other boards and check for binary bloat, as follows: > $ buildman -b zstd2 --boards dh_imx6,m53menlo,mvebu_espressobin-88f3720,sandbox,sandbox64,stm32mp15_dhcom_basic,stm32mp15_dhcor_basic,turris_mox,turris_omnia -sS > Summary of 6 commits for 9 boards (8 threads, 1 job per thread) > 01: Merge branch '2023-01-10-platform-updates' > arm: w+ m53menlo dh_imx6 > 02: lib: zstd: update to latest Linux zstd 1.5.2 > aarch64: (for 2/2 boards) all -3186.0 rodata +920.0 text -4106.0 > arm: (for 5/5 boards) all +1254.4 rodata +940.0 text +314.4 > sandbox: (for 2/2 boards) all -4452.0 data -16.0 rodata +640.0 text -5076.0 [1]e0c1b49f5b
[2]f302ad8811/lib/libzstd.mk (L31)
Signed-off-by: Brandon Maier <brandon.maier@collins.com> [trini: Set ret to -EINVAL for the error of "failed to detect compressed" to fix warning, drop ZSTD_SRCSIZEHINT_MAX for non-Linux host tool builds] Signed-off-by: Tom Rini <trini@konsulko.com>
This commit is contained in:
parent
e875cabd74
commit
4b9b25d943
45 changed files with 13662 additions and 7571 deletions
|
@ -40,7 +40,7 @@ int sqfs_decompressor_init(struct squashfs_ctxt *ctxt)
|
||||||
#endif
|
#endif
|
||||||
#if IS_ENABLED(CONFIG_ZSTD)
|
#if IS_ENABLED(CONFIG_ZSTD)
|
||||||
case SQFS_COMP_ZSTD:
|
case SQFS_COMP_ZSTD:
|
||||||
ctxt->zstd_workspace = malloc(ZSTD_DCtxWorkspaceBound());
|
ctxt->zstd_workspace = malloc(zstd_dctx_workspace_bound());
|
||||||
if (!ctxt->zstd_workspace)
|
if (!ctxt->zstd_workspace)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
break;
|
break;
|
||||||
|
@ -99,11 +99,14 @@ static int sqfs_zstd_decompress(struct squashfs_ctxt *ctxt, void *dest,
|
||||||
size_t wsize;
|
size_t wsize;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
wsize = ZSTD_DCtxWorkspaceBound();
|
wsize = zstd_dctx_workspace_bound();
|
||||||
ctx = ZSTD_initDCtx(ctxt->zstd_workspace, wsize);
|
|
||||||
ret = ZSTD_decompressDCtx(ctx, dest, dest_len, source, src_len);
|
|
||||||
|
|
||||||
return ZSTD_isError(ret);
|
ctx = zstd_init_dctx(ctxt->zstd_workspace, wsize);
|
||||||
|
if (!ctx)
|
||||||
|
return -EINVAL;
|
||||||
|
ret = zstd_decompress_dctx(ctx, dest, dest_len, source, src_len);
|
||||||
|
|
||||||
|
return zstd_is_error(ret);
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_ZSTD */
|
#endif /* CONFIG_ZSTD */
|
||||||
|
|
||||||
|
@ -140,7 +143,7 @@ int sqfs_decompress(struct squashfs_ctxt *ctxt, void *dest,
|
||||||
case SQFS_COMP_ZSTD:
|
case SQFS_COMP_ZSTD:
|
||||||
ret = sqfs_zstd_decompress(ctxt, dest, *dest_len, source, src_len);
|
ret = sqfs_zstd_decompress(ctxt, dest, *dest_len, source, src_len);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printf("ZSTD Error code: %d\n", ZSTD_getErrorCode(ret));
|
printf("ZSTD Error code: %d\n", zstd_get_error_code(ret));
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1288
include/linux/zstd.h
1288
include/linux/zstd.h
File diff suppressed because it is too large
Load diff
77
include/linux/zstd_errors.h
Normal file
77
include/linux/zstd_errors.h
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Yann Collet, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZSTD_ERRORS_H_398273423
|
||||||
|
#define ZSTD_ERRORS_H_398273423
|
||||||
|
|
||||||
|
|
||||||
|
/*===== dependency =====*/
|
||||||
|
#include <linux/types.h> /* size_t */
|
||||||
|
|
||||||
|
|
||||||
|
/* ===== ZSTDERRORLIB_API : control library symbols visibility ===== */
|
||||||
|
#define ZSTDERRORLIB_VISIBILITY
|
||||||
|
#define ZSTDERRORLIB_API ZSTDERRORLIB_VISIBILITY
|
||||||
|
|
||||||
|
/*-*********************************************
|
||||||
|
* Error codes list
|
||||||
|
*-*********************************************
|
||||||
|
* Error codes _values_ are pinned down since v1.3.1 only.
|
||||||
|
* Therefore, don't rely on values if you may link to any version < v1.3.1.
|
||||||
|
*
|
||||||
|
* Only values < 100 are considered stable.
|
||||||
|
*
|
||||||
|
* note 1 : this API shall be used with static linking only.
|
||||||
|
* dynamic linking is not yet officially supported.
|
||||||
|
* note 2 : Prefer relying on the enum than on its value whenever possible
|
||||||
|
* This is the only supported way to use the error list < v1.3.1
|
||||||
|
* note 3 : ZSTD_isError() is always correct, whatever the library version.
|
||||||
|
**********************************************/
|
||||||
|
typedef enum {
|
||||||
|
ZSTD_error_no_error = 0,
|
||||||
|
ZSTD_error_GENERIC = 1,
|
||||||
|
ZSTD_error_prefix_unknown = 10,
|
||||||
|
ZSTD_error_version_unsupported = 12,
|
||||||
|
ZSTD_error_frameParameter_unsupported = 14,
|
||||||
|
ZSTD_error_frameParameter_windowTooLarge = 16,
|
||||||
|
ZSTD_error_corruption_detected = 20,
|
||||||
|
ZSTD_error_checksum_wrong = 22,
|
||||||
|
ZSTD_error_dictionary_corrupted = 30,
|
||||||
|
ZSTD_error_dictionary_wrong = 32,
|
||||||
|
ZSTD_error_dictionaryCreation_failed = 34,
|
||||||
|
ZSTD_error_parameter_unsupported = 40,
|
||||||
|
ZSTD_error_parameter_outOfBound = 42,
|
||||||
|
ZSTD_error_tableLog_tooLarge = 44,
|
||||||
|
ZSTD_error_maxSymbolValue_tooLarge = 46,
|
||||||
|
ZSTD_error_maxSymbolValue_tooSmall = 48,
|
||||||
|
ZSTD_error_stage_wrong = 60,
|
||||||
|
ZSTD_error_init_missing = 62,
|
||||||
|
ZSTD_error_memory_allocation = 64,
|
||||||
|
ZSTD_error_workSpace_tooSmall= 66,
|
||||||
|
ZSTD_error_dstSize_tooSmall = 70,
|
||||||
|
ZSTD_error_srcSize_wrong = 72,
|
||||||
|
ZSTD_error_dstBuffer_null = 74,
|
||||||
|
/* following error codes are __NOT STABLE__, they can be removed or changed in future versions */
|
||||||
|
ZSTD_error_frameIndex_tooLarge = 100,
|
||||||
|
ZSTD_error_seekableIO = 102,
|
||||||
|
ZSTD_error_dstBuffer_wrong = 104,
|
||||||
|
ZSTD_error_srcBuffer_wrong = 105,
|
||||||
|
ZSTD_error_maxCode = 120 /* never EVER use this value directly, it can change in future versions! Use ZSTD_isError() instead */
|
||||||
|
} ZSTD_ErrorCode;
|
||||||
|
|
||||||
|
/*! ZSTD_getErrorCode() :
|
||||||
|
convert a `size_t` function result into a `ZSTD_ErrorCode` enum type,
|
||||||
|
which can be used to compare with enum list published above */
|
||||||
|
ZSTDERRORLIB_API ZSTD_ErrorCode ZSTD_getErrorCode(size_t functionResult);
|
||||||
|
ZSTDERRORLIB_API const char* ZSTD_getErrorString(ZSTD_ErrorCode code); /*< Same as ZSTD_getErrorName, but using a `ZSTD_ErrorCode` enum argument */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* ZSTD_ERRORS_H_398273423 */
|
2549
include/linux/zstd_lib.h
Normal file
2549
include/linux/zstd_lib.h
Normal file
File diff suppressed because it is too large
Load diff
15
lib/Kconfig
15
lib/Kconfig
|
@ -694,6 +694,21 @@ config ZSTD
|
||||||
help
|
help
|
||||||
This enables Zstandard decompression library.
|
This enables Zstandard decompression library.
|
||||||
|
|
||||||
|
if ZSTD
|
||||||
|
|
||||||
|
config ZSTD_LIB_MINIFY
|
||||||
|
bool "Minify Zstandard code"
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
This disables various optional components and changes the
|
||||||
|
compilation flags to prioritize space-saving.
|
||||||
|
|
||||||
|
For detailed info, see zstd's lib/README.md
|
||||||
|
|
||||||
|
https://github.com/facebook/zstd/blob/dev/lib/README.md
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
config SPL_LZ4
|
config SPL_LZ4
|
||||||
bool "Enable LZ4 decompression support in SPL"
|
bool "Enable LZ4 decompression support in SPL"
|
||||||
depends on SPL
|
depends on SPL
|
||||||
|
|
|
@ -1,4 +1,36 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||||
|
# ################################################################
|
||||||
|
# Copyright (c) Facebook, Inc.
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
# ################################################################
|
||||||
obj-y += zstd_decompress.o
|
obj-y += zstd_decompress.o
|
||||||
|
obj-y += zstd_common.o
|
||||||
|
|
||||||
zstd_decompress-y := huf_decompress.o decompress.o \
|
ifeq ($(CONFIG_ZSTD_LIB_MINIFY),y)
|
||||||
entropy_common.o fse_decompress.o zstd_common.o zstd.o
|
ccflags-y += -DHUF_FORCE_DECOMPRESS_X1
|
||||||
|
ccflags-y += -DZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT
|
||||||
|
ccflags-y += -DZSTD_NO_INLINE
|
||||||
|
ccflags-y += -DZSTD_STRIP_ERROR_STRINGS
|
||||||
|
ccflags-y += -DDYNAMIC_BMI2=0
|
||||||
|
endif
|
||||||
|
|
||||||
|
zstd_decompress-y := \
|
||||||
|
zstd_decompress_module.o \
|
||||||
|
decompress/huf_decompress.o \
|
||||||
|
decompress/zstd_ddict.o \
|
||||||
|
decompress/zstd_decompress.o \
|
||||||
|
decompress/zstd_decompress_block.o \
|
||||||
|
zstd.o \
|
||||||
|
|
||||||
|
zstd_common-y := \
|
||||||
|
zstd_common_module.o \
|
||||||
|
common/debug.o \
|
||||||
|
common/entropy_common.o \
|
||||||
|
common/error_private.o \
|
||||||
|
common/fse_decompress.o \
|
||||||
|
common/zstd_common.o \
|
||||||
|
|
|
@ -1,344 +0,0 @@
|
||||||
/* SPDX-License-Identifier: (GPL-2.0 or BSD-2-Clause) */
|
|
||||||
/*
|
|
||||||
* bitstream
|
|
||||||
* Part of FSE library
|
|
||||||
* header file (to include)
|
|
||||||
* Copyright (C) 2013-2016, Yann Collet.
|
|
||||||
*
|
|
||||||
* You can contact the author at :
|
|
||||||
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
|
||||||
*/
|
|
||||||
#ifndef BITSTREAM_H_MODULE
|
|
||||||
#define BITSTREAM_H_MODULE
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This API consists of small unitary functions, which must be inlined for best performance.
|
|
||||||
* Since link-time-optimization is not available for all compilers,
|
|
||||||
* these functions are defined into a .h to be included.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*-****************************************
|
|
||||||
* Dependencies
|
|
||||||
******************************************/
|
|
||||||
#include "error_private.h" /* error codes and messages */
|
|
||||||
#include "mem.h" /* unaligned access routines */
|
|
||||||
|
|
||||||
/*=========================================
|
|
||||||
* Target specific
|
|
||||||
=========================================*/
|
|
||||||
#define STREAM_ACCUMULATOR_MIN_32 25
|
|
||||||
#define STREAM_ACCUMULATOR_MIN_64 57
|
|
||||||
#define STREAM_ACCUMULATOR_MIN ((U32)(ZSTD_32bits() ? STREAM_ACCUMULATOR_MIN_32 : STREAM_ACCUMULATOR_MIN_64))
|
|
||||||
|
|
||||||
/*-******************************************
|
|
||||||
* bitStream encoding API (write forward)
|
|
||||||
********************************************/
|
|
||||||
/* bitStream can mix input from multiple sources.
|
|
||||||
* A critical property of these streams is that they encode and decode in **reverse** direction.
|
|
||||||
* So the first bit sequence you add will be the last to be read, like a LIFO stack.
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
size_t bitContainer;
|
|
||||||
int bitPos;
|
|
||||||
char *startPtr;
|
|
||||||
char *ptr;
|
|
||||||
char *endPtr;
|
|
||||||
} BIT_CStream_t;
|
|
||||||
|
|
||||||
ZSTD_STATIC size_t BIT_initCStream(BIT_CStream_t *bitC, void *dstBuffer, size_t dstCapacity);
|
|
||||||
ZSTD_STATIC void BIT_addBits(BIT_CStream_t *bitC, size_t value, unsigned nbBits);
|
|
||||||
ZSTD_STATIC void BIT_flushBits(BIT_CStream_t *bitC);
|
|
||||||
ZSTD_STATIC size_t BIT_closeCStream(BIT_CStream_t *bitC);
|
|
||||||
|
|
||||||
/* Start with initCStream, providing the size of buffer to write into.
|
|
||||||
* bitStream will never write outside of this buffer.
|
|
||||||
* `dstCapacity` must be >= sizeof(bitD->bitContainer), otherwise @return will be an error code.
|
|
||||||
*
|
|
||||||
* bits are first added to a local register.
|
|
||||||
* Local register is size_t, hence 64-bits on 64-bits systems, or 32-bits on 32-bits systems.
|
|
||||||
* Writing data into memory is an explicit operation, performed by the flushBits function.
|
|
||||||
* Hence keep track how many bits are potentially stored into local register to avoid register overflow.
|
|
||||||
* After a flushBits, a maximum of 7 bits might still be stored into local register.
|
|
||||||
*
|
|
||||||
* Avoid storing elements of more than 24 bits if you want compatibility with 32-bits bitstream readers.
|
|
||||||
*
|
|
||||||
* Last operation is to close the bitStream.
|
|
||||||
* The function returns the final size of CStream in bytes.
|
|
||||||
* If data couldn't fit into `dstBuffer`, it will return a 0 ( == not storable)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*-********************************************
|
|
||||||
* bitStream decoding API (read backward)
|
|
||||||
**********************************************/
|
|
||||||
typedef struct {
|
|
||||||
size_t bitContainer;
|
|
||||||
unsigned bitsConsumed;
|
|
||||||
const char *ptr;
|
|
||||||
const char *start;
|
|
||||||
} BIT_DStream_t;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
BIT_DStream_unfinished = 0,
|
|
||||||
BIT_DStream_endOfBuffer = 1,
|
|
||||||
BIT_DStream_completed = 2,
|
|
||||||
BIT_DStream_overflow = 3
|
|
||||||
} BIT_DStream_status; /* result of BIT_reloadDStream() */
|
|
||||||
/* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */
|
|
||||||
|
|
||||||
ZSTD_STATIC size_t BIT_initDStream(BIT_DStream_t *bitD, const void *srcBuffer, size_t srcSize);
|
|
||||||
ZSTD_STATIC size_t BIT_readBits(BIT_DStream_t *bitD, unsigned nbBits);
|
|
||||||
ZSTD_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t *bitD);
|
|
||||||
ZSTD_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t *bitD);
|
|
||||||
|
|
||||||
/* Start by invoking BIT_initDStream().
|
|
||||||
* A chunk of the bitStream is then stored into a local register.
|
|
||||||
* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
|
|
||||||
* You can then retrieve bitFields stored into the local register, **in reverse order**.
|
|
||||||
* Local register is explicitly reloaded from memory by the BIT_reloadDStream() method.
|
|
||||||
* A reload guarantee a minimum of ((8*sizeof(bitD->bitContainer))-7) bits when its result is BIT_DStream_unfinished.
|
|
||||||
* Otherwise, it can be less than that, so proceed accordingly.
|
|
||||||
* Checking if DStream has reached its end can be performed with BIT_endOfDStream().
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*-****************************************
|
|
||||||
* unsafe API
|
|
||||||
******************************************/
|
|
||||||
ZSTD_STATIC void BIT_addBitsFast(BIT_CStream_t *bitC, size_t value, unsigned nbBits);
|
|
||||||
/* faster, but works only if value is "clean", meaning all high bits above nbBits are 0 */
|
|
||||||
|
|
||||||
ZSTD_STATIC void BIT_flushBitsFast(BIT_CStream_t *bitC);
|
|
||||||
/* unsafe version; does not check buffer overflow */
|
|
||||||
|
|
||||||
ZSTD_STATIC size_t BIT_readBitsFast(BIT_DStream_t *bitD, unsigned nbBits);
|
|
||||||
/* faster, but works only if nbBits >= 1 */
|
|
||||||
|
|
||||||
/*-**************************************************************
|
|
||||||
* Internal functions
|
|
||||||
****************************************************************/
|
|
||||||
ZSTD_STATIC unsigned BIT_highbit32(register U32 val) { return 31 - __builtin_clz(val); }
|
|
||||||
|
|
||||||
/*===== Local Constants =====*/
|
|
||||||
static const unsigned BIT_mask[] = {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}; /* up to 26 bits */
|
|
||||||
|
|
||||||
/*-**************************************************************
|
|
||||||
* bitStream encoding
|
|
||||||
****************************************************************/
|
|
||||||
/*! BIT_initCStream() :
|
|
||||||
* `dstCapacity` must be > sizeof(void*)
|
|
||||||
* Return: 0 if success,
|
|
||||||
otherwise an error code (can be tested using ERR_isError() ) */
|
|
||||||
ZSTD_STATIC size_t BIT_initCStream(BIT_CStream_t *bitC, void *startPtr, size_t dstCapacity)
|
|
||||||
{
|
|
||||||
bitC->bitContainer = 0;
|
|
||||||
bitC->bitPos = 0;
|
|
||||||
bitC->startPtr = (char *)startPtr;
|
|
||||||
bitC->ptr = bitC->startPtr;
|
|
||||||
bitC->endPtr = bitC->startPtr + dstCapacity - sizeof(bitC->ptr);
|
|
||||||
if (dstCapacity <= sizeof(bitC->ptr))
|
|
||||||
return ERROR(dstSize_tooSmall);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! BIT_addBits() :
|
|
||||||
can add up to 26 bits into `bitC`.
|
|
||||||
Does not check for register overflow ! */
|
|
||||||
ZSTD_STATIC void BIT_addBits(BIT_CStream_t *bitC, size_t value, unsigned nbBits)
|
|
||||||
{
|
|
||||||
bitC->bitContainer |= (value & BIT_mask[nbBits]) << bitC->bitPos;
|
|
||||||
bitC->bitPos += nbBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! BIT_addBitsFast() :
|
|
||||||
* works only if `value` is _clean_, meaning all high bits above nbBits are 0 */
|
|
||||||
ZSTD_STATIC void BIT_addBitsFast(BIT_CStream_t *bitC, size_t value, unsigned nbBits)
|
|
||||||
{
|
|
||||||
bitC->bitContainer |= value << bitC->bitPos;
|
|
||||||
bitC->bitPos += nbBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! BIT_flushBitsFast() :
|
|
||||||
* unsafe version; does not check buffer overflow */
|
|
||||||
ZSTD_STATIC void BIT_flushBitsFast(BIT_CStream_t *bitC)
|
|
||||||
{
|
|
||||||
size_t const nbBytes = bitC->bitPos >> 3;
|
|
||||||
ZSTD_writeLEST(bitC->ptr, bitC->bitContainer);
|
|
||||||
bitC->ptr += nbBytes;
|
|
||||||
bitC->bitPos &= 7;
|
|
||||||
bitC->bitContainer >>= nbBytes * 8; /* if bitPos >= sizeof(bitContainer)*8 --> undefined behavior */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! BIT_flushBits() :
|
|
||||||
* safe version; check for buffer overflow, and prevents it.
|
|
||||||
* note : does not signal buffer overflow. This will be revealed later on using BIT_closeCStream() */
|
|
||||||
ZSTD_STATIC void BIT_flushBits(BIT_CStream_t *bitC)
|
|
||||||
{
|
|
||||||
size_t const nbBytes = bitC->bitPos >> 3;
|
|
||||||
ZSTD_writeLEST(bitC->ptr, bitC->bitContainer);
|
|
||||||
bitC->ptr += nbBytes;
|
|
||||||
if (bitC->ptr > bitC->endPtr)
|
|
||||||
bitC->ptr = bitC->endPtr;
|
|
||||||
bitC->bitPos &= 7;
|
|
||||||
bitC->bitContainer >>= nbBytes * 8; /* if bitPos >= sizeof(bitContainer)*8 --> undefined behavior */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! BIT_closeCStream() :
|
|
||||||
* Return: size of CStream, in bytes,
|
|
||||||
or 0 if it could not fit into dstBuffer */
|
|
||||||
ZSTD_STATIC size_t BIT_closeCStream(BIT_CStream_t *bitC)
|
|
||||||
{
|
|
||||||
BIT_addBitsFast(bitC, 1, 1); /* endMark */
|
|
||||||
BIT_flushBits(bitC);
|
|
||||||
|
|
||||||
if (bitC->ptr >= bitC->endPtr)
|
|
||||||
return 0; /* doesn't fit within authorized budget : cancel */
|
|
||||||
|
|
||||||
return (bitC->ptr - bitC->startPtr) + (bitC->bitPos > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-********************************************************
|
|
||||||
* bitStream decoding
|
|
||||||
**********************************************************/
|
|
||||||
/*! BIT_initDStream() :
|
|
||||||
* Initialize a BIT_DStream_t.
|
|
||||||
* `bitD` : a pointer to an already allocated BIT_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
|
|
||||||
*/
|
|
||||||
ZSTD_STATIC size_t BIT_initDStream(BIT_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 = ZSTD_readLEST(bitD->ptr);
|
|
||||||
{
|
|
||||||
BYTE const lastByte = ((const BYTE *)srcBuffer)[srcSize - 1];
|
|
||||||
bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; /* ensures bitsConsumed is always set */
|
|
||||||
if (lastByte == 0)
|
|
||||||
return ERROR(GENERIC); /* endMark not present */
|
|
||||||
}
|
|
||||||
} 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);
|
|
||||||
case 6: bitD->bitContainer += (size_t)(((const BYTE *)(srcBuffer))[5]) << (sizeof(bitD->bitContainer) * 8 - 24);
|
|
||||||
case 5: bitD->bitContainer += (size_t)(((const BYTE *)(srcBuffer))[4]) << (sizeof(bitD->bitContainer) * 8 - 32);
|
|
||||||
case 4: bitD->bitContainer += (size_t)(((const BYTE *)(srcBuffer))[3]) << 24;
|
|
||||||
case 3: bitD->bitContainer += (size_t)(((const BYTE *)(srcBuffer))[2]) << 16;
|
|
||||||
case 2: bitD->bitContainer += (size_t)(((const BYTE *)(srcBuffer))[1]) << 8;
|
|
||||||
default:;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
BYTE const lastByte = ((const BYTE *)srcBuffer)[srcSize - 1];
|
|
||||||
bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0;
|
|
||||||
if (lastByte == 0)
|
|
||||||
return ERROR(GENERIC); /* endMark not present */
|
|
||||||
}
|
|
||||||
bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize) * 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
return srcSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
ZSTD_STATIC size_t BIT_getUpperBits(size_t bitContainer, U32 const start) { return bitContainer >> start; }
|
|
||||||
|
|
||||||
ZSTD_STATIC size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits) { return (bitContainer >> start) & BIT_mask[nbBits]; }
|
|
||||||
|
|
||||||
ZSTD_STATIC size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits) { return bitContainer & BIT_mask[nbBits]; }
|
|
||||||
|
|
||||||
/*! BIT_lookBits() :
|
|
||||||
* Provides next n bits from local register.
|
|
||||||
* local register is not modified.
|
|
||||||
* On 32-bits, maxNbBits==24.
|
|
||||||
* On 64-bits, maxNbBits==56.
|
|
||||||
* Return: value extracted
|
|
||||||
*/
|
|
||||||
ZSTD_STATIC size_t BIT_lookBits(const BIT_DStream_t *bitD, U32 nbBits)
|
|
||||||
{
|
|
||||||
U32 const bitMask = sizeof(bitD->bitContainer) * 8 - 1;
|
|
||||||
return ((bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> 1) >> ((bitMask - nbBits) & bitMask);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! BIT_lookBitsFast() :
|
|
||||||
* unsafe version; only works only if nbBits >= 1 */
|
|
||||||
ZSTD_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t *bitD, U32 nbBits)
|
|
||||||
{
|
|
||||||
U32 const bitMask = sizeof(bitD->bitContainer) * 8 - 1;
|
|
||||||
return (bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> (((bitMask + 1) - nbBits) & bitMask);
|
|
||||||
}
|
|
||||||
|
|
||||||
ZSTD_STATIC void BIT_skipBits(BIT_DStream_t *bitD, U32 nbBits) { bitD->bitsConsumed += nbBits; }
|
|
||||||
|
|
||||||
/*! BIT_readBits() :
|
|
||||||
* Read (consume) next n bits from local register and update.
|
|
||||||
* Pay attention to not read more than nbBits contained into local register.
|
|
||||||
* Return: extracted value.
|
|
||||||
*/
|
|
||||||
ZSTD_STATIC size_t BIT_readBits(BIT_DStream_t *bitD, U32 nbBits)
|
|
||||||
{
|
|
||||||
size_t const value = BIT_lookBits(bitD, nbBits);
|
|
||||||
BIT_skipBits(bitD, nbBits);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! BIT_readBitsFast() :
|
|
||||||
* unsafe version; only works only if nbBits >= 1 */
|
|
||||||
ZSTD_STATIC size_t BIT_readBitsFast(BIT_DStream_t *bitD, U32 nbBits)
|
|
||||||
{
|
|
||||||
size_t const value = BIT_lookBitsFast(bitD, nbBits);
|
|
||||||
BIT_skipBits(bitD, nbBits);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! BIT_reloadDStream() :
|
|
||||||
* Refill `bitD` from buffer previously set in BIT_initDStream() .
|
|
||||||
* This function is safe, it guarantees it will not read beyond src buffer.
|
|
||||||
* @return : status of `BIT_DStream_t` internal register.
|
|
||||||
if status == BIT_DStream_unfinished, internal register is filled with >= (sizeof(bitD->bitContainer)*8 - 7) bits */
|
|
||||||
ZSTD_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t *bitD)
|
|
||||||
{
|
|
||||||
if (bitD->bitsConsumed > (sizeof(bitD->bitContainer) * 8)) /* should not happen => corruption detected */
|
|
||||||
return BIT_DStream_overflow;
|
|
||||||
|
|
||||||
if (bitD->ptr >= bitD->start + sizeof(bitD->bitContainer)) {
|
|
||||||
bitD->ptr -= bitD->bitsConsumed >> 3;
|
|
||||||
bitD->bitsConsumed &= 7;
|
|
||||||
bitD->bitContainer = ZSTD_readLEST(bitD->ptr);
|
|
||||||
return BIT_DStream_unfinished;
|
|
||||||
}
|
|
||||||
if (bitD->ptr == bitD->start) {
|
|
||||||
if (bitD->bitsConsumed < sizeof(bitD->bitContainer) * 8)
|
|
||||||
return BIT_DStream_endOfBuffer;
|
|
||||||
return BIT_DStream_completed;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
U32 nbBytes = bitD->bitsConsumed >> 3;
|
|
||||||
BIT_DStream_status result = BIT_DStream_unfinished;
|
|
||||||
if (bitD->ptr - nbBytes < bitD->start) {
|
|
||||||
nbBytes = (U32)(bitD->ptr - bitD->start); /* ptr > start */
|
|
||||||
result = BIT_DStream_endOfBuffer;
|
|
||||||
}
|
|
||||||
bitD->ptr -= nbBytes;
|
|
||||||
bitD->bitsConsumed -= nbBytes * 8;
|
|
||||||
bitD->bitContainer = ZSTD_readLEST(bitD->ptr); /* reminder : srcSize > sizeof(bitD) */
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! BIT_endOfDStream() :
|
|
||||||
* @return Tells if DStream has exactly reached its end (all bits consumed).
|
|
||||||
*/
|
|
||||||
ZSTD_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t *DStream)
|
|
||||||
{
|
|
||||||
return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer) * 8));
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* BITSTREAM_H_MODULE */
|
|
446
lib/zstd/common/bitstream.h
Normal file
446
lib/zstd/common/bitstream.h
Normal file
|
@ -0,0 +1,446 @@
|
||||||
|
/* ******************************************************************
|
||||||
|
* bitstream
|
||||||
|
* Part of FSE library
|
||||||
|
* Copyright (c) Yann Collet, Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You can contact the author at :
|
||||||
|
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
****************************************************************** */
|
||||||
|
#ifndef BITSTREAM_H_MODULE
|
||||||
|
#define BITSTREAM_H_MODULE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This API consists of small unitary functions, which must be inlined for best performance.
|
||||||
|
* Since link-time-optimization is not available for all compilers,
|
||||||
|
* these functions are defined into a .h to be included.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*-****************************************
|
||||||
|
* Dependencies
|
||||||
|
******************************************/
|
||||||
|
#include "mem.h" /* unaligned access routines */
|
||||||
|
#include "compiler.h" /* UNLIKELY() */
|
||||||
|
#include "debug.h" /* assert(), DEBUGLOG(), RAWLOG() */
|
||||||
|
#include "error_private.h" /* error codes and messages */
|
||||||
|
|
||||||
|
|
||||||
|
/*=========================================
|
||||||
|
* Target specific
|
||||||
|
=========================================*/
|
||||||
|
|
||||||
|
#define STREAM_ACCUMULATOR_MIN_32 25
|
||||||
|
#define STREAM_ACCUMULATOR_MIN_64 57
|
||||||
|
#define STREAM_ACCUMULATOR_MIN ((U32)(MEM_32bits() ? STREAM_ACCUMULATOR_MIN_32 : STREAM_ACCUMULATOR_MIN_64))
|
||||||
|
|
||||||
|
|
||||||
|
/*-******************************************
|
||||||
|
* bitStream encoding API (write forward)
|
||||||
|
********************************************/
|
||||||
|
/* bitStream can mix input from multiple sources.
|
||||||
|
* A critical property of these streams is that they encode and decode in **reverse** direction.
|
||||||
|
* So the first bit sequence you add will be the last to be read, like a LIFO stack.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
size_t bitContainer;
|
||||||
|
unsigned bitPos;
|
||||||
|
char* startPtr;
|
||||||
|
char* ptr;
|
||||||
|
char* endPtr;
|
||||||
|
} BIT_CStream_t;
|
||||||
|
|
||||||
|
MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, void* dstBuffer, size_t dstCapacity);
|
||||||
|
MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits);
|
||||||
|
MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC);
|
||||||
|
MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC);
|
||||||
|
|
||||||
|
/* Start with initCStream, providing the size of buffer to write into.
|
||||||
|
* bitStream will never write outside of this buffer.
|
||||||
|
* `dstCapacity` must be >= sizeof(bitD->bitContainer), otherwise @return will be an error code.
|
||||||
|
*
|
||||||
|
* bits are first added to a local register.
|
||||||
|
* Local register is size_t, hence 64-bits on 64-bits systems, or 32-bits on 32-bits systems.
|
||||||
|
* Writing data into memory is an explicit operation, performed by the flushBits function.
|
||||||
|
* Hence keep track how many bits are potentially stored into local register to avoid register overflow.
|
||||||
|
* After a flushBits, a maximum of 7 bits might still be stored into local register.
|
||||||
|
*
|
||||||
|
* Avoid storing elements of more than 24 bits if you want compatibility with 32-bits bitstream readers.
|
||||||
|
*
|
||||||
|
* Last operation is to close the bitStream.
|
||||||
|
* The function returns the final size of CStream in bytes.
|
||||||
|
* If data couldn't fit into `dstBuffer`, it will return a 0 ( == not storable)
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*-********************************************
|
||||||
|
* bitStream decoding API (read backward)
|
||||||
|
**********************************************/
|
||||||
|
typedef struct {
|
||||||
|
size_t bitContainer;
|
||||||
|
unsigned bitsConsumed;
|
||||||
|
const char* ptr;
|
||||||
|
const char* start;
|
||||||
|
const char* limitPtr;
|
||||||
|
} BIT_DStream_t;
|
||||||
|
|
||||||
|
typedef enum { BIT_DStream_unfinished = 0,
|
||||||
|
BIT_DStream_endOfBuffer = 1,
|
||||||
|
BIT_DStream_completed = 2,
|
||||||
|
BIT_DStream_overflow = 3 } BIT_DStream_status; /* result of BIT_reloadDStream() */
|
||||||
|
/* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */
|
||||||
|
|
||||||
|
MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize);
|
||||||
|
MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits);
|
||||||
|
MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD);
|
||||||
|
MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD);
|
||||||
|
|
||||||
|
|
||||||
|
/* Start by invoking BIT_initDStream().
|
||||||
|
* A chunk of the bitStream is then stored into a local register.
|
||||||
|
* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
|
||||||
|
* You can then retrieve bitFields stored into the local register, **in reverse order**.
|
||||||
|
* Local register is explicitly reloaded from memory by the BIT_reloadDStream() method.
|
||||||
|
* A reload guarantee a minimum of ((8*sizeof(bitD->bitContainer))-7) bits when its result is BIT_DStream_unfinished.
|
||||||
|
* Otherwise, it can be less than that, so proceed accordingly.
|
||||||
|
* Checking if DStream has reached its end can be performed with BIT_endOfDStream().
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*-****************************************
|
||||||
|
* unsafe API
|
||||||
|
******************************************/
|
||||||
|
MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, size_t value, unsigned nbBits);
|
||||||
|
/* faster, but works only if value is "clean", meaning all high bits above nbBits are 0 */
|
||||||
|
|
||||||
|
MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC);
|
||||||
|
/* unsafe version; does not check buffer overflow */
|
||||||
|
|
||||||
|
MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits);
|
||||||
|
/* faster, but works only if nbBits >= 1 */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-**************************************************************
|
||||||
|
* Internal functions
|
||||||
|
****************************************************************/
|
||||||
|
MEM_STATIC unsigned BIT_highbit32 (U32 val)
|
||||||
|
{
|
||||||
|
assert(val != 0);
|
||||||
|
{
|
||||||
|
# if (__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;
|
||||||
|
v |= v >> 1;
|
||||||
|
v |= v >> 2;
|
||||||
|
v |= v >> 4;
|
||||||
|
v |= v >> 8;
|
||||||
|
v |= v >> 16;
|
||||||
|
return DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27];
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===== Local Constants =====*/
|
||||||
|
static const unsigned BIT_mask[] = {
|
||||||
|
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, 0x7FFFFFF, 0xFFFFFFF, 0x1FFFFFFF,
|
||||||
|
0x3FFFFFFF, 0x7FFFFFFF}; /* up to 31 bits */
|
||||||
|
#define BIT_MASK_SIZE (sizeof(BIT_mask) / sizeof(BIT_mask[0]))
|
||||||
|
|
||||||
|
/*-**************************************************************
|
||||||
|
* bitStream encoding
|
||||||
|
****************************************************************/
|
||||||
|
/*! BIT_initCStream() :
|
||||||
|
* `dstCapacity` must be > sizeof(size_t)
|
||||||
|
* @return : 0 if success,
|
||||||
|
* otherwise an error code (can be tested using ERR_isError()) */
|
||||||
|
MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC,
|
||||||
|
void* startPtr, size_t dstCapacity)
|
||||||
|
{
|
||||||
|
bitC->bitContainer = 0;
|
||||||
|
bitC->bitPos = 0;
|
||||||
|
bitC->startPtr = (char*)startPtr;
|
||||||
|
bitC->ptr = bitC->startPtr;
|
||||||
|
bitC->endPtr = bitC->startPtr + dstCapacity - sizeof(bitC->bitContainer);
|
||||||
|
if (dstCapacity <= sizeof(bitC->bitContainer)) return ERROR(dstSize_tooSmall);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! BIT_addBits() :
|
||||||
|
* can add up to 31 bits into `bitC`.
|
||||||
|
* Note : does not check for register overflow ! */
|
||||||
|
MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC,
|
||||||
|
size_t value, unsigned nbBits)
|
||||||
|
{
|
||||||
|
DEBUG_STATIC_ASSERT(BIT_MASK_SIZE == 32);
|
||||||
|
assert(nbBits < BIT_MASK_SIZE);
|
||||||
|
assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8);
|
||||||
|
bitC->bitContainer |= (value & BIT_mask[nbBits]) << bitC->bitPos;
|
||||||
|
bitC->bitPos += nbBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! BIT_addBitsFast() :
|
||||||
|
* works only if `value` is _clean_,
|
||||||
|
* meaning all high bits above nbBits are 0 */
|
||||||
|
MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC,
|
||||||
|
size_t value, unsigned nbBits)
|
||||||
|
{
|
||||||
|
assert((value>>nbBits) == 0);
|
||||||
|
assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8);
|
||||||
|
bitC->bitContainer |= value << bitC->bitPos;
|
||||||
|
bitC->bitPos += nbBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! BIT_flushBitsFast() :
|
||||||
|
* assumption : bitContainer has not overflowed
|
||||||
|
* unsafe version; does not check buffer overflow */
|
||||||
|
MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC)
|
||||||
|
{
|
||||||
|
size_t const nbBytes = bitC->bitPos >> 3;
|
||||||
|
assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8);
|
||||||
|
assert(bitC->ptr <= bitC->endPtr);
|
||||||
|
MEM_writeLEST(bitC->ptr, bitC->bitContainer);
|
||||||
|
bitC->ptr += nbBytes;
|
||||||
|
bitC->bitPos &= 7;
|
||||||
|
bitC->bitContainer >>= nbBytes*8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! BIT_flushBits() :
|
||||||
|
* assumption : bitContainer has not overflowed
|
||||||
|
* safe version; check for buffer overflow, and prevents it.
|
||||||
|
* note : does not signal buffer overflow.
|
||||||
|
* overflow will be revealed later on using BIT_closeCStream() */
|
||||||
|
MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC)
|
||||||
|
{
|
||||||
|
size_t const nbBytes = bitC->bitPos >> 3;
|
||||||
|
assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8);
|
||||||
|
assert(bitC->ptr <= bitC->endPtr);
|
||||||
|
MEM_writeLEST(bitC->ptr, bitC->bitContainer);
|
||||||
|
bitC->ptr += nbBytes;
|
||||||
|
if (bitC->ptr > bitC->endPtr) bitC->ptr = bitC->endPtr;
|
||||||
|
bitC->bitPos &= 7;
|
||||||
|
bitC->bitContainer >>= nbBytes*8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! BIT_closeCStream() :
|
||||||
|
* @return : size of CStream, in bytes,
|
||||||
|
* or 0 if it could not fit into dstBuffer */
|
||||||
|
MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC)
|
||||||
|
{
|
||||||
|
BIT_addBitsFast(bitC, 1, 1); /* endMark */
|
||||||
|
BIT_flushBits(bitC);
|
||||||
|
if (bitC->ptr >= bitC->endPtr) return 0; /* overflow detected */
|
||||||
|
return (bitC->ptr - bitC->startPtr) + (bitC->bitPos > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-********************************************************
|
||||||
|
* bitStream decoding
|
||||||
|
**********************************************************/
|
||||||
|
/*! BIT_initDStream() :
|
||||||
|
* Initialize a BIT_DStream_t.
|
||||||
|
* `bitD` : a pointer to an already allocated BIT_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 BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize)
|
||||||
|
{
|
||||||
|
if (srcSize < 1) { ZSTD_memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); }
|
||||||
|
|
||||||
|
bitD->start = (const char*)srcBuffer;
|
||||||
|
bitD->limitPtr = bitD->start + sizeof(bitD->bitContainer);
|
||||||
|
|
||||||
|
if (srcSize >= sizeof(bitD->bitContainer)) { /* normal case */
|
||||||
|
bitD->ptr = (const char*)srcBuffer + srcSize - sizeof(bitD->bitContainer);
|
||||||
|
bitD->bitContainer = MEM_readLEST(bitD->ptr);
|
||||||
|
{ BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
|
||||||
|
bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; /* ensures bitsConsumed is always set */
|
||||||
|
if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ }
|
||||||
|
} else {
|
||||||
|
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);
|
||||||
|
ZSTD_FALLTHROUGH;
|
||||||
|
|
||||||
|
case 6: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24);
|
||||||
|
ZSTD_FALLTHROUGH;
|
||||||
|
|
||||||
|
case 5: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32);
|
||||||
|
ZSTD_FALLTHROUGH;
|
||||||
|
|
||||||
|
case 4: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[3]) << 24;
|
||||||
|
ZSTD_FALLTHROUGH;
|
||||||
|
|
||||||
|
case 3: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[2]) << 16;
|
||||||
|
ZSTD_FALLTHROUGH;
|
||||||
|
|
||||||
|
case 2: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[1]) << 8;
|
||||||
|
ZSTD_FALLTHROUGH;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
{ BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
|
||||||
|
bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0;
|
||||||
|
if (lastByte == 0) return ERROR(corruption_detected); /* endMark not present */
|
||||||
|
}
|
||||||
|
bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize)*8;
|
||||||
|
}
|
||||||
|
|
||||||
|
return srcSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getUpperBits(size_t bitContainer, U32 const start)
|
||||||
|
{
|
||||||
|
return bitContainer >> start;
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits)
|
||||||
|
{
|
||||||
|
U32 const regMask = sizeof(bitContainer)*8 - 1;
|
||||||
|
/* if start > regMask, bitstream is corrupted, and result is undefined */
|
||||||
|
assert(nbBits < BIT_MASK_SIZE);
|
||||||
|
/* x86 transform & ((1 << nbBits) - 1) to bzhi instruction, it is better
|
||||||
|
* than accessing memory. When bmi2 instruction is not present, we consider
|
||||||
|
* such cpus old (pre-Haswell, 2013) and their performance is not of that
|
||||||
|
* importance.
|
||||||
|
*/
|
||||||
|
#if defined(__x86_64__) || defined(_M_X86)
|
||||||
|
return (bitContainer >> (start & regMask)) & ((((U64)1) << nbBits) - 1);
|
||||||
|
#else
|
||||||
|
return (bitContainer >> (start & regMask)) & BIT_mask[nbBits];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits)
|
||||||
|
{
|
||||||
|
assert(nbBits < BIT_MASK_SIZE);
|
||||||
|
return bitContainer & BIT_mask[nbBits];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! BIT_lookBits() :
|
||||||
|
* Provides next n bits from local register.
|
||||||
|
* local register is not modified.
|
||||||
|
* On 32-bits, maxNbBits==24.
|
||||||
|
* On 64-bits, maxNbBits==56.
|
||||||
|
* @return : value extracted */
|
||||||
|
MEM_STATIC FORCE_INLINE_ATTR size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits)
|
||||||
|
{
|
||||||
|
/* arbitrate between double-shift and shift+mask */
|
||||||
|
#if 1
|
||||||
|
/* if bitD->bitsConsumed + nbBits > sizeof(bitD->bitContainer)*8,
|
||||||
|
* bitstream is likely corrupted, and result is undefined */
|
||||||
|
return BIT_getMiddleBits(bitD->bitContainer, (sizeof(bitD->bitContainer)*8) - bitD->bitsConsumed - nbBits, nbBits);
|
||||||
|
#else
|
||||||
|
/* this code path is slower on my os-x laptop */
|
||||||
|
U32 const regMask = sizeof(bitD->bitContainer)*8 - 1;
|
||||||
|
return ((bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> 1) >> ((regMask-nbBits) & regMask);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! BIT_lookBitsFast() :
|
||||||
|
* unsafe version; only works if nbBits >= 1 */
|
||||||
|
MEM_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t* bitD, U32 nbBits)
|
||||||
|
{
|
||||||
|
U32 const regMask = sizeof(bitD->bitContainer)*8 - 1;
|
||||||
|
assert(nbBits >= 1);
|
||||||
|
return (bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> (((regMask+1)-nbBits) & regMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC FORCE_INLINE_ATTR void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)
|
||||||
|
{
|
||||||
|
bitD->bitsConsumed += nbBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! BIT_readBits() :
|
||||||
|
* Read (consume) next n bits from local register and update.
|
||||||
|
* Pay attention to not read more than nbBits contained into local register.
|
||||||
|
* @return : extracted value. */
|
||||||
|
MEM_STATIC FORCE_INLINE_ATTR size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits)
|
||||||
|
{
|
||||||
|
size_t const value = BIT_lookBits(bitD, nbBits);
|
||||||
|
BIT_skipBits(bitD, nbBits);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! BIT_readBitsFast() :
|
||||||
|
* unsafe version; only works only if nbBits >= 1 */
|
||||||
|
MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits)
|
||||||
|
{
|
||||||
|
size_t const value = BIT_lookBitsFast(bitD, nbBits);
|
||||||
|
assert(nbBits >= 1);
|
||||||
|
BIT_skipBits(bitD, nbBits);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! BIT_reloadDStreamFast() :
|
||||||
|
* Similar to BIT_reloadDStream(), but with two differences:
|
||||||
|
* 1. bitsConsumed <= sizeof(bitD->bitContainer)*8 must hold!
|
||||||
|
* 2. Returns BIT_DStream_overflow when bitD->ptr < bitD->limitPtr, at this
|
||||||
|
* point you must use BIT_reloadDStream() to reload.
|
||||||
|
*/
|
||||||
|
MEM_STATIC BIT_DStream_status BIT_reloadDStreamFast(BIT_DStream_t* bitD)
|
||||||
|
{
|
||||||
|
if (UNLIKELY(bitD->ptr < bitD->limitPtr))
|
||||||
|
return BIT_DStream_overflow;
|
||||||
|
assert(bitD->bitsConsumed <= sizeof(bitD->bitContainer)*8);
|
||||||
|
bitD->ptr -= bitD->bitsConsumed >> 3;
|
||||||
|
bitD->bitsConsumed &= 7;
|
||||||
|
bitD->bitContainer = MEM_readLEST(bitD->ptr);
|
||||||
|
return BIT_DStream_unfinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! BIT_reloadDStream() :
|
||||||
|
* Refill `bitD` from buffer previously set in BIT_initDStream() .
|
||||||
|
* This function is safe, it guarantees it will not read beyond src buffer.
|
||||||
|
* @return : status of `BIT_DStream_t` internal register.
|
||||||
|
* when status == BIT_DStream_unfinished, internal register is filled with at least 25 or 57 bits */
|
||||||
|
MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD)
|
||||||
|
{
|
||||||
|
if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* overflow detected, like end of stream */
|
||||||
|
return BIT_DStream_overflow;
|
||||||
|
|
||||||
|
if (bitD->ptr >= bitD->limitPtr) {
|
||||||
|
return BIT_reloadDStreamFast(bitD);
|
||||||
|
}
|
||||||
|
if (bitD->ptr == bitD->start) {
|
||||||
|
if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BIT_DStream_endOfBuffer;
|
||||||
|
return BIT_DStream_completed;
|
||||||
|
}
|
||||||
|
/* start < ptr < limitPtr */
|
||||||
|
{ U32 nbBytes = bitD->bitsConsumed >> 3;
|
||||||
|
BIT_DStream_status result = BIT_DStream_unfinished;
|
||||||
|
if (bitD->ptr - nbBytes < bitD->start) {
|
||||||
|
nbBytes = (U32)(bitD->ptr - bitD->start); /* ptr > start */
|
||||||
|
result = BIT_DStream_endOfBuffer;
|
||||||
|
}
|
||||||
|
bitD->ptr -= nbBytes;
|
||||||
|
bitD->bitsConsumed -= nbBytes*8;
|
||||||
|
bitD->bitContainer = MEM_readLEST(bitD->ptr); /* reminder : srcSize > sizeof(bitD->bitContainer), otherwise bitD->ptr == bitD->start */
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! BIT_endOfDStream() :
|
||||||
|
* @return : 1 if DStream has _exactly_ reached its end (all bits consumed).
|
||||||
|
*/
|
||||||
|
MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* DStream)
|
||||||
|
{
|
||||||
|
return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer)*8));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* BITSTREAM_H_MODULE */
|
184
lib/zstd/common/compiler.h
Normal file
184
lib/zstd/common/compiler.h
Normal file
|
@ -0,0 +1,184 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Yann Collet, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZSTD_COMPILER_H
|
||||||
|
#define ZSTD_COMPILER_H
|
||||||
|
|
||||||
|
#include "portability_macros.h"
|
||||||
|
|
||||||
|
/*-*******************************************************
|
||||||
|
* Compiler specifics
|
||||||
|
*********************************************************/
|
||||||
|
/* force inlining */
|
||||||
|
|
||||||
|
#if !defined(ZSTD_NO_INLINE)
|
||||||
|
#if (defined(__GNUC__) && !defined(__STRICT_ANSI__)) || defined(__cplusplus) || defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
|
||||||
|
# define INLINE_KEYWORD inline
|
||||||
|
#else
|
||||||
|
# define INLINE_KEYWORD
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define FORCE_INLINE_ATTR __attribute__((always_inline))
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define INLINE_KEYWORD
|
||||||
|
#define FORCE_INLINE_ATTR
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
On MSVC qsort requires that functions passed into it use the __cdecl calling conversion(CC).
|
||||||
|
This explicitly marks such functions as __cdecl so that the code will still compile
|
||||||
|
if a CC other than __cdecl has been made the default.
|
||||||
|
*/
|
||||||
|
#define WIN_CDECL
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FORCE_INLINE_TEMPLATE is used to define C "templates", which take constant
|
||||||
|
* parameters. They must be inlined for the compiler to eliminate the constant
|
||||||
|
* branches.
|
||||||
|
*/
|
||||||
|
#define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR
|
||||||
|
/*
|
||||||
|
* HINT_INLINE is used to help the compiler generate better code. It is *not*
|
||||||
|
* used for "templates", so it can be tweaked based on the compilers
|
||||||
|
* performance.
|
||||||
|
*
|
||||||
|
* gcc-4.8 and gcc-4.9 have been shown to benefit from leaving off the
|
||||||
|
* always_inline attribute.
|
||||||
|
*
|
||||||
|
* clang up to 5.0.0 (trunk) benefit tremendously from the always_inline
|
||||||
|
* attribute.
|
||||||
|
*/
|
||||||
|
#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8 && __GNUC__ < 5
|
||||||
|
# define HINT_INLINE static INLINE_KEYWORD
|
||||||
|
#else
|
||||||
|
# define HINT_INLINE static INLINE_KEYWORD FORCE_INLINE_ATTR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* UNUSED_ATTR tells the compiler it is okay if the function is unused. */
|
||||||
|
#define UNUSED_ATTR __attribute__((unused))
|
||||||
|
|
||||||
|
/* force no inlining */
|
||||||
|
#define FORCE_NOINLINE static __attribute__((__noinline__))
|
||||||
|
|
||||||
|
|
||||||
|
/* target attribute */
|
||||||
|
#define TARGET_ATTRIBUTE(target) __attribute__((__target__(target)))
|
||||||
|
|
||||||
|
/* Target attribute for BMI2 dynamic dispatch.
|
||||||
|
* Enable lzcnt, bmi, and bmi2.
|
||||||
|
* We test for bmi1 & bmi2. lzcnt is included in bmi1.
|
||||||
|
*/
|
||||||
|
#define BMI2_TARGET_ATTRIBUTE TARGET_ATTRIBUTE("lzcnt,bmi,bmi2")
|
||||||
|
|
||||||
|
/* prefetch
|
||||||
|
* can be disabled, by declaring NO_PREFETCH build macro */
|
||||||
|
#if ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) )
|
||||||
|
# define PREFETCH_L1(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */)
|
||||||
|
# define PREFETCH_L2(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 2 /* locality */)
|
||||||
|
#elif defined(__aarch64__)
|
||||||
|
# define PREFETCH_L1(ptr) __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr)))
|
||||||
|
# define PREFETCH_L2(ptr) __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr)))
|
||||||
|
#else
|
||||||
|
# define PREFETCH_L1(ptr) (void)(ptr) /* disabled */
|
||||||
|
# define PREFETCH_L2(ptr) (void)(ptr) /* disabled */
|
||||||
|
#endif /* NO_PREFETCH */
|
||||||
|
|
||||||
|
#define CACHELINE_SIZE 64
|
||||||
|
|
||||||
|
#define PREFETCH_AREA(p, s) { \
|
||||||
|
const char* const _ptr = (const char*)(p); \
|
||||||
|
size_t const _size = (size_t)(s); \
|
||||||
|
size_t _pos; \
|
||||||
|
for (_pos=0; _pos<_size; _pos+=CACHELINE_SIZE) { \
|
||||||
|
PREFETCH_L2(_ptr + _pos); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vectorization
|
||||||
|
* older GCC (pre gcc-4.3 picked as the cutoff) uses a different syntax,
|
||||||
|
* and some compilers, like Intel ICC and MCST LCC, do not support it at all. */
|
||||||
|
#if !defined(__INTEL_COMPILER) && !defined(__clang__) && defined(__GNUC__) && !defined(__LCC__)
|
||||||
|
# if (__GNUC__ == 4 && __GNUC_MINOR__ > 3) || (__GNUC__ >= 5)
|
||||||
|
# define DONT_VECTORIZE __attribute__((optimize("no-tree-vectorize")))
|
||||||
|
# else
|
||||||
|
# define DONT_VECTORIZE _Pragma("GCC optimize(\"no-tree-vectorize\")")
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define DONT_VECTORIZE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Tell the compiler that a branch is likely or unlikely.
|
||||||
|
* Only use these macros if it causes the compiler to generate better code.
|
||||||
|
* If you can remove a LIKELY/UNLIKELY annotation without speed changes in gcc
|
||||||
|
* and clang, please do.
|
||||||
|
*/
|
||||||
|
#define LIKELY(x) (__builtin_expect((x), 1))
|
||||||
|
#define UNLIKELY(x) (__builtin_expect((x), 0))
|
||||||
|
|
||||||
|
#if __has_builtin(__builtin_unreachable) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)))
|
||||||
|
# define ZSTD_UNREACHABLE { assert(0), __builtin_unreachable(); }
|
||||||
|
#else
|
||||||
|
# define ZSTD_UNREACHABLE { assert(0); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* disable warnings */
|
||||||
|
|
||||||
|
/*Like DYNAMIC_BMI2 but for compile time determination of BMI2 support*/
|
||||||
|
|
||||||
|
|
||||||
|
/* compile time determination of SIMD support */
|
||||||
|
|
||||||
|
/* C-language Attributes are added in C23. */
|
||||||
|
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ > 201710L) && defined(__has_c_attribute)
|
||||||
|
# define ZSTD_HAS_C_ATTRIBUTE(x) __has_c_attribute(x)
|
||||||
|
#else
|
||||||
|
# define ZSTD_HAS_C_ATTRIBUTE(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Only use C++ attributes in C++. Some compilers report support for C++
|
||||||
|
* attributes when compiling with C.
|
||||||
|
*/
|
||||||
|
#define ZSTD_HAS_CPP_ATTRIBUTE(x) 0
|
||||||
|
|
||||||
|
/* Define ZSTD_FALLTHROUGH macro for annotating switch case with the 'fallthrough' attribute.
|
||||||
|
* - C23: https://en.cppreference.com/w/c/language/attributes/fallthrough
|
||||||
|
* - CPP17: https://en.cppreference.com/w/cpp/language/attributes/fallthrough
|
||||||
|
* - Else: __attribute__((__fallthrough__))
|
||||||
|
*/
|
||||||
|
#define ZSTD_FALLTHROUGH fallthrough
|
||||||
|
|
||||||
|
/*-**************************************************************
|
||||||
|
* Alignment check
|
||||||
|
*****************************************************************/
|
||||||
|
|
||||||
|
/* this test was initially positioned in mem.h,
|
||||||
|
* but this file is removed (or replaced) for linux kernel
|
||||||
|
* so it's now hosted in compiler.h,
|
||||||
|
* which remains valid for both user & kernel spaces.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZSTD_ALIGNOF
|
||||||
|
/* covers gcc, clang & MSVC */
|
||||||
|
/* note : this section must come first, before C11,
|
||||||
|
* due to a limitation in the kernel source generator */
|
||||||
|
# define ZSTD_ALIGNOF(T) __alignof(T)
|
||||||
|
|
||||||
|
#endif /* ZSTD_ALIGNOF */
|
||||||
|
|
||||||
|
/*-**************************************************************
|
||||||
|
* Sanitizer
|
||||||
|
*****************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* ZSTD_COMPILER_H */
|
194
lib/zstd/common/cpu.h
Normal file
194
lib/zstd/common/cpu.h
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZSTD_COMMON_CPU_H
|
||||||
|
#define ZSTD_COMMON_CPU_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Implementation taken from folly/CpuId.h
|
||||||
|
* https://github.com/facebook/folly/blob/master/folly/CpuId.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "mem.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
U32 f1c;
|
||||||
|
U32 f1d;
|
||||||
|
U32 f7b;
|
||||||
|
U32 f7c;
|
||||||
|
} ZSTD_cpuid_t;
|
||||||
|
|
||||||
|
MEM_STATIC ZSTD_cpuid_t ZSTD_cpuid(void) {
|
||||||
|
U32 f1c = 0;
|
||||||
|
U32 f1d = 0;
|
||||||
|
U32 f7b = 0;
|
||||||
|
U32 f7c = 0;
|
||||||
|
#if defined(__i386__) && defined(__PIC__) && !defined(__clang__) && defined(__GNUC__)
|
||||||
|
/* The following block like the normal cpuid branch below, but gcc
|
||||||
|
* reserves ebx for use of its pic register so we must specially
|
||||||
|
* handle the save and restore to avoid clobbering the register
|
||||||
|
*/
|
||||||
|
U32 n;
|
||||||
|
__asm__(
|
||||||
|
"pushl %%ebx\n\t"
|
||||||
|
"cpuid\n\t"
|
||||||
|
"popl %%ebx\n\t"
|
||||||
|
: "=a"(n)
|
||||||
|
: "a"(0)
|
||||||
|
: "ecx", "edx");
|
||||||
|
if (n >= 1) {
|
||||||
|
U32 f1a;
|
||||||
|
__asm__(
|
||||||
|
"pushl %%ebx\n\t"
|
||||||
|
"cpuid\n\t"
|
||||||
|
"popl %%ebx\n\t"
|
||||||
|
: "=a"(f1a), "=c"(f1c), "=d"(f1d)
|
||||||
|
: "a"(1));
|
||||||
|
}
|
||||||
|
if (n >= 7) {
|
||||||
|
__asm__(
|
||||||
|
"pushl %%ebx\n\t"
|
||||||
|
"cpuid\n\t"
|
||||||
|
"movl %%ebx, %%eax\n\t"
|
||||||
|
"popl %%ebx"
|
||||||
|
: "=a"(f7b), "=c"(f7c)
|
||||||
|
: "a"(7), "c"(0)
|
||||||
|
: "edx");
|
||||||
|
}
|
||||||
|
#elif defined(__x86_64__) || defined(_M_X64) || defined(__i386__)
|
||||||
|
U32 n;
|
||||||
|
__asm__("cpuid" : "=a"(n) : "a"(0) : "ebx", "ecx", "edx");
|
||||||
|
if (n >= 1) {
|
||||||
|
U32 f1a;
|
||||||
|
__asm__("cpuid" : "=a"(f1a), "=c"(f1c), "=d"(f1d) : "a"(1) : "ebx");
|
||||||
|
}
|
||||||
|
if (n >= 7) {
|
||||||
|
U32 f7a;
|
||||||
|
__asm__("cpuid"
|
||||||
|
: "=a"(f7a), "=b"(f7b), "=c"(f7c)
|
||||||
|
: "a"(7), "c"(0)
|
||||||
|
: "edx");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
ZSTD_cpuid_t cpuid;
|
||||||
|
cpuid.f1c = f1c;
|
||||||
|
cpuid.f1d = f1d;
|
||||||
|
cpuid.f7b = f7b;
|
||||||
|
cpuid.f7c = f7c;
|
||||||
|
return cpuid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define X(name, r, bit) \
|
||||||
|
MEM_STATIC int ZSTD_cpuid_##name(ZSTD_cpuid_t const cpuid) { \
|
||||||
|
return ((cpuid.r) & (1U << bit)) != 0; \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cpuid(1): Processor Info and Feature Bits. */
|
||||||
|
#define C(name, bit) X(name, f1c, bit)
|
||||||
|
C(sse3, 0)
|
||||||
|
C(pclmuldq, 1)
|
||||||
|
C(dtes64, 2)
|
||||||
|
C(monitor, 3)
|
||||||
|
C(dscpl, 4)
|
||||||
|
C(vmx, 5)
|
||||||
|
C(smx, 6)
|
||||||
|
C(eist, 7)
|
||||||
|
C(tm2, 8)
|
||||||
|
C(ssse3, 9)
|
||||||
|
C(cnxtid, 10)
|
||||||
|
C(fma, 12)
|
||||||
|
C(cx16, 13)
|
||||||
|
C(xtpr, 14)
|
||||||
|
C(pdcm, 15)
|
||||||
|
C(pcid, 17)
|
||||||
|
C(dca, 18)
|
||||||
|
C(sse41, 19)
|
||||||
|
C(sse42, 20)
|
||||||
|
C(x2apic, 21)
|
||||||
|
C(movbe, 22)
|
||||||
|
C(popcnt, 23)
|
||||||
|
C(tscdeadline, 24)
|
||||||
|
C(aes, 25)
|
||||||
|
C(xsave, 26)
|
||||||
|
C(osxsave, 27)
|
||||||
|
C(avx, 28)
|
||||||
|
C(f16c, 29)
|
||||||
|
C(rdrand, 30)
|
||||||
|
#undef C
|
||||||
|
#define D(name, bit) X(name, f1d, bit)
|
||||||
|
D(fpu, 0)
|
||||||
|
D(vme, 1)
|
||||||
|
D(de, 2)
|
||||||
|
D(pse, 3)
|
||||||
|
D(tsc, 4)
|
||||||
|
D(msr, 5)
|
||||||
|
D(pae, 6)
|
||||||
|
D(mce, 7)
|
||||||
|
D(cx8, 8)
|
||||||
|
D(apic, 9)
|
||||||
|
D(sep, 11)
|
||||||
|
D(mtrr, 12)
|
||||||
|
D(pge, 13)
|
||||||
|
D(mca, 14)
|
||||||
|
D(cmov, 15)
|
||||||
|
D(pat, 16)
|
||||||
|
D(pse36, 17)
|
||||||
|
D(psn, 18)
|
||||||
|
D(clfsh, 19)
|
||||||
|
D(ds, 21)
|
||||||
|
D(acpi, 22)
|
||||||
|
D(mmx, 23)
|
||||||
|
D(fxsr, 24)
|
||||||
|
D(sse, 25)
|
||||||
|
D(sse2, 26)
|
||||||
|
D(ss, 27)
|
||||||
|
D(htt, 28)
|
||||||
|
D(tm, 29)
|
||||||
|
D(pbe, 31)
|
||||||
|
#undef D
|
||||||
|
|
||||||
|
/* cpuid(7): Extended Features. */
|
||||||
|
#define B(name, bit) X(name, f7b, bit)
|
||||||
|
B(bmi1, 3)
|
||||||
|
B(hle, 4)
|
||||||
|
B(avx2, 5)
|
||||||
|
B(smep, 7)
|
||||||
|
B(bmi2, 8)
|
||||||
|
B(erms, 9)
|
||||||
|
B(invpcid, 10)
|
||||||
|
B(rtm, 11)
|
||||||
|
B(mpx, 14)
|
||||||
|
B(avx512f, 16)
|
||||||
|
B(avx512dq, 17)
|
||||||
|
B(rdseed, 18)
|
||||||
|
B(adx, 19)
|
||||||
|
B(smap, 20)
|
||||||
|
B(avx512ifma, 21)
|
||||||
|
B(pcommit, 22)
|
||||||
|
B(clflushopt, 23)
|
||||||
|
B(clwb, 24)
|
||||||
|
B(avx512pf, 26)
|
||||||
|
B(avx512er, 27)
|
||||||
|
B(avx512cd, 28)
|
||||||
|
B(sha, 29)
|
||||||
|
B(avx512bw, 30)
|
||||||
|
B(avx512vl, 31)
|
||||||
|
#undef B
|
||||||
|
#define C(name, bit) X(name, f7c, bit)
|
||||||
|
C(prefetchwt1, 0)
|
||||||
|
C(avx512vbmi, 1)
|
||||||
|
#undef C
|
||||||
|
|
||||||
|
#undef X
|
||||||
|
|
||||||
|
#endif /* ZSTD_COMMON_CPU_H */
|
24
lib/zstd/common/debug.c
Normal file
24
lib/zstd/common/debug.c
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/* ******************************************************************
|
||||||
|
* debug
|
||||||
|
* Part of FSE library
|
||||||
|
* Copyright (c) Yann Collet, Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You can contact the author at :
|
||||||
|
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
****************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This module only hosts one global variable
|
||||||
|
* which can be used to dynamically influence the verbosity of traces,
|
||||||
|
* such as DEBUGLOG and RAWLOG
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
int g_debuglevel = DEBUGLEVEL;
|
92
lib/zstd/common/debug.h
Normal file
92
lib/zstd/common/debug.h
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
/* ******************************************************************
|
||||||
|
* debug
|
||||||
|
* Part of FSE library
|
||||||
|
* Copyright (c) Yann Collet, Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You can contact the author at :
|
||||||
|
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
****************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The purpose of this header is to enable debug functions.
|
||||||
|
* They regroup assert(), DEBUGLOG() and RAWLOG() for run-time,
|
||||||
|
* and DEBUG_STATIC_ASSERT() for compile-time.
|
||||||
|
*
|
||||||
|
* By default, DEBUGLEVEL==0, which means run-time debug is disabled.
|
||||||
|
*
|
||||||
|
* Level 1 enables assert() only.
|
||||||
|
* Starting level 2, traces can be generated and pushed to stderr.
|
||||||
|
* The higher the level, the more verbose the traces.
|
||||||
|
*
|
||||||
|
* It's possible to dynamically adjust level using variable g_debug_level,
|
||||||
|
* which is only declared if DEBUGLEVEL>=2,
|
||||||
|
* and is a global variable, not multi-thread protected (use with care)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DEBUG_H_12987983217
|
||||||
|
#define DEBUG_H_12987983217
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* static assert is triggered at compile time, leaving no runtime artefact.
|
||||||
|
* static assert only works with compile-time constants.
|
||||||
|
* Also, this variant can only be used inside a function. */
|
||||||
|
#define DEBUG_STATIC_ASSERT(c) (void)sizeof(char[(c) ? 1 : -1])
|
||||||
|
|
||||||
|
|
||||||
|
/* DEBUGLEVEL is expected to be defined externally,
|
||||||
|
* typically through compiler command line.
|
||||||
|
* Value must be a number. */
|
||||||
|
#ifndef DEBUGLEVEL
|
||||||
|
# define DEBUGLEVEL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* recommended values for DEBUGLEVEL :
|
||||||
|
* 0 : release mode, no debug, all run-time checks disabled
|
||||||
|
* 1 : enables assert() only, no display
|
||||||
|
* 2 : reserved, for currently active debug path
|
||||||
|
* 3 : events once per object lifetime (CCtx, CDict, etc.)
|
||||||
|
* 4 : events once per frame
|
||||||
|
* 5 : events once per block
|
||||||
|
* 6 : events once per sequence (verbose)
|
||||||
|
* 7+: events at every position (*very* verbose)
|
||||||
|
*
|
||||||
|
* It's generally inconvenient to output traces > 5.
|
||||||
|
* In which case, it's possible to selectively trigger high verbosity levels
|
||||||
|
* by modifying g_debug_level.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if (DEBUGLEVEL>=2)
|
||||||
|
# define ZSTD_DEPS_NEED_IO
|
||||||
|
# include "zstd_deps.h"
|
||||||
|
extern int g_debuglevel; /* the variable is only declared,
|
||||||
|
it actually lives in debug.c,
|
||||||
|
and is shared by the whole process.
|
||||||
|
It's not thread-safe.
|
||||||
|
It's useful when enabling very verbose levels
|
||||||
|
on selective conditions (such as position in src) */
|
||||||
|
|
||||||
|
# define RAWLOG(l, ...) { \
|
||||||
|
if (l<=g_debuglevel) { \
|
||||||
|
ZSTD_DEBUG_PRINT(__VA_ARGS__); \
|
||||||
|
} }
|
||||||
|
# define DEBUGLOG(l, ...) { \
|
||||||
|
if (l<=g_debuglevel) { \
|
||||||
|
ZSTD_DEBUG_PRINT(__FILE__ ": " __VA_ARGS__); \
|
||||||
|
ZSTD_DEBUG_PRINT(" \n"); \
|
||||||
|
} }
|
||||||
|
#else
|
||||||
|
# define RAWLOG(l, ...) {} /* disabled */
|
||||||
|
# define DEBUGLOG(l, ...) {} /* disabled */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* DEBUG_H_12987983217 */
|
357
lib/zstd/common/entropy_common.c
Normal file
357
lib/zstd/common/entropy_common.c
Normal file
|
@ -0,0 +1,357 @@
|
||||||
|
/* ******************************************************************
|
||||||
|
* Common functions of New Generation Entropy library
|
||||||
|
* Copyright (c) Yann Collet, Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You can contact the author at :
|
||||||
|
* - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||||
|
* - Public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
****************************************************************** */
|
||||||
|
|
||||||
|
/* *************************************
|
||||||
|
* Dependencies
|
||||||
|
***************************************/
|
||||||
|
#include "mem.h"
|
||||||
|
#include "error_private.h" /* ERR_*, ERROR */
|
||||||
|
#define FSE_STATIC_LINKING_ONLY /* FSE_MIN_TABLELOG */
|
||||||
|
#include "fse.h"
|
||||||
|
#define HUF_STATIC_LINKING_ONLY /* HUF_TABLELOG_ABSOLUTEMAX */
|
||||||
|
#include "huf.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*=== Version ===*/
|
||||||
|
unsigned FSE_versionNumber(void) { return FSE_VERSION_NUMBER; }
|
||||||
|
|
||||||
|
|
||||||
|
/*=== Error Management ===*/
|
||||||
|
unsigned FSE_isError(size_t code) { return ERR_isError(code); }
|
||||||
|
const char* FSE_getErrorName(size_t code) { return ERR_getErrorName(code); }
|
||||||
|
|
||||||
|
unsigned HUF_isError(size_t code) { return ERR_isError(code); }
|
||||||
|
const char* HUF_getErrorName(size_t code) { return ERR_getErrorName(code); }
|
||||||
|
|
||||||
|
|
||||||
|
/*-**************************************************************
|
||||||
|
* FSE NCount encoding-decoding
|
||||||
|
****************************************************************/
|
||||||
|
static U32 FSE_ctz(U32 val)
|
||||||
|
{
|
||||||
|
assert(val != 0);
|
||||||
|
{
|
||||||
|
# if (__GNUC__ >= 3) /* GCC Intrinsic */
|
||||||
|
return __builtin_ctz(val);
|
||||||
|
# else /* Software version */
|
||||||
|
U32 count = 0;
|
||||||
|
while ((val & 1) == 0) {
|
||||||
|
val >>= 1;
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE_TEMPLATE
|
||||||
|
size_t FSE_readNCount_body(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;
|
||||||
|
unsigned const maxSV1 = *maxSVPtr + 1;
|
||||||
|
int previous0 = 0;
|
||||||
|
|
||||||
|
if (hbSize < 8) {
|
||||||
|
/* This function only works when hbSize >= 8 */
|
||||||
|
char buffer[8] = {0};
|
||||||
|
ZSTD_memcpy(buffer, headerBuffer, hbSize);
|
||||||
|
{ size_t const countSize = FSE_readNCount(normalizedCounter, maxSVPtr, tableLogPtr,
|
||||||
|
buffer, sizeof(buffer));
|
||||||
|
if (FSE_isError(countSize)) return countSize;
|
||||||
|
if (countSize > hbSize) return ERROR(corruption_detected);
|
||||||
|
return countSize;
|
||||||
|
} }
|
||||||
|
assert(hbSize >= 8);
|
||||||
|
|
||||||
|
/* init */
|
||||||
|
ZSTD_memset(normalizedCounter, 0, (*maxSVPtr+1) * sizeof(normalizedCounter[0])); /* all symbols not present in NCount have a frequency of 0 */
|
||||||
|
bitStream = MEM_readLE32(ip);
|
||||||
|
nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG; /* extract tableLog */
|
||||||
|
if (nbBits > FSE_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge);
|
||||||
|
bitStream >>= 4;
|
||||||
|
bitCount = 4;
|
||||||
|
*tableLogPtr = nbBits;
|
||||||
|
remaining = (1<<nbBits)+1;
|
||||||
|
threshold = 1<<nbBits;
|
||||||
|
nbBits++;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (previous0) {
|
||||||
|
/* Count the number of repeats. Each time the
|
||||||
|
* 2-bit repeat code is 0b11 there is another
|
||||||
|
* repeat.
|
||||||
|
* Avoid UB by setting the high bit to 1.
|
||||||
|
*/
|
||||||
|
int repeats = FSE_ctz(~bitStream | 0x80000000) >> 1;
|
||||||
|
while (repeats >= 12) {
|
||||||
|
charnum += 3 * 12;
|
||||||
|
if (LIKELY(ip <= iend-7)) {
|
||||||
|
ip += 3;
|
||||||
|
} else {
|
||||||
|
bitCount -= (int)(8 * (iend - 7 - ip));
|
||||||
|
bitCount &= 31;
|
||||||
|
ip = iend - 4;
|
||||||
|
}
|
||||||
|
bitStream = MEM_readLE32(ip) >> bitCount;
|
||||||
|
repeats = FSE_ctz(~bitStream | 0x80000000) >> 1;
|
||||||
|
}
|
||||||
|
charnum += 3 * repeats;
|
||||||
|
bitStream >>= 2 * repeats;
|
||||||
|
bitCount += 2 * repeats;
|
||||||
|
|
||||||
|
/* Add the final repeat which isn't 0b11. */
|
||||||
|
assert((bitStream & 3) < 3);
|
||||||
|
charnum += bitStream & 3;
|
||||||
|
bitCount += 2;
|
||||||
|
|
||||||
|
/* This is an error, but break and return an error
|
||||||
|
* at the end, because returning out of a loop makes
|
||||||
|
* it harder for the compiler to optimize.
|
||||||
|
*/
|
||||||
|
if (charnum >= maxSV1) break;
|
||||||
|
|
||||||
|
/* We don't need to set the normalized count to 0
|
||||||
|
* because we already memset the whole buffer to 0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (LIKELY(ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
|
||||||
|
assert((bitCount >> 3) <= 3); /* For first condition to work */
|
||||||
|
ip += bitCount>>3;
|
||||||
|
bitCount &= 7;
|
||||||
|
} else {
|
||||||
|
bitCount -= (int)(8 * (iend - 4 - ip));
|
||||||
|
bitCount &= 31;
|
||||||
|
ip = iend - 4;
|
||||||
|
}
|
||||||
|
bitStream = MEM_readLE32(ip) >> bitCount;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int const max = (2*threshold-1) - remaining;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
if ((bitStream & (threshold-1)) < (U32)max) {
|
||||||
|
count = bitStream & (threshold-1);
|
||||||
|
bitCount += nbBits-1;
|
||||||
|
} else {
|
||||||
|
count = bitStream & (2*threshold-1);
|
||||||
|
if (count >= threshold) count -= max;
|
||||||
|
bitCount += nbBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
count--; /* extra accuracy */
|
||||||
|
/* When it matters (small blocks), this is a
|
||||||
|
* predictable branch, because we don't use -1.
|
||||||
|
*/
|
||||||
|
if (count >= 0) {
|
||||||
|
remaining -= count;
|
||||||
|
} else {
|
||||||
|
assert(count == -1);
|
||||||
|
remaining += count;
|
||||||
|
}
|
||||||
|
normalizedCounter[charnum++] = (short)count;
|
||||||
|
previous0 = !count;
|
||||||
|
|
||||||
|
assert(threshold > 1);
|
||||||
|
if (remaining < threshold) {
|
||||||
|
/* This branch can be folded into the
|
||||||
|
* threshold update condition because we
|
||||||
|
* know that threshold > 1.
|
||||||
|
*/
|
||||||
|
if (remaining <= 1) break;
|
||||||
|
nbBits = BIT_highbit32(remaining) + 1;
|
||||||
|
threshold = 1 << (nbBits - 1);
|
||||||
|
}
|
||||||
|
if (charnum >= maxSV1) break;
|
||||||
|
|
||||||
|
if (LIKELY(ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
|
||||||
|
ip += bitCount>>3;
|
||||||
|
bitCount &= 7;
|
||||||
|
} else {
|
||||||
|
bitCount -= (int)(8 * (iend - 4 - ip));
|
||||||
|
bitCount &= 31;
|
||||||
|
ip = iend - 4;
|
||||||
|
}
|
||||||
|
bitStream = MEM_readLE32(ip) >> bitCount;
|
||||||
|
} }
|
||||||
|
if (remaining != 1) return ERROR(corruption_detected);
|
||||||
|
/* Only possible when there are too many zeros. */
|
||||||
|
if (charnum > maxSV1) return ERROR(maxSymbolValue_tooSmall);
|
||||||
|
if (bitCount > 32) return ERROR(corruption_detected);
|
||||||
|
*maxSVPtr = charnum-1;
|
||||||
|
|
||||||
|
ip += (bitCount+7)>>3;
|
||||||
|
return ip-istart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Avoids the FORCE_INLINE of the _body() function. */
|
||||||
|
static size_t FSE_readNCount_body_default(
|
||||||
|
short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
|
||||||
|
const void* headerBuffer, size_t hbSize)
|
||||||
|
{
|
||||||
|
return FSE_readNCount_body(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DYNAMIC_BMI2
|
||||||
|
BMI2_TARGET_ATTRIBUTE static size_t FSE_readNCount_body_bmi2(
|
||||||
|
short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
|
||||||
|
const void* headerBuffer, size_t hbSize)
|
||||||
|
{
|
||||||
|
return FSE_readNCount_body(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
size_t FSE_readNCount_bmi2(
|
||||||
|
short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
|
||||||
|
const void* headerBuffer, size_t hbSize, int bmi2)
|
||||||
|
{
|
||||||
|
#if DYNAMIC_BMI2
|
||||||
|
if (bmi2) {
|
||||||
|
return FSE_readNCount_body_bmi2(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
(void)bmi2;
|
||||||
|
return FSE_readNCount_body_default(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t FSE_readNCount(
|
||||||
|
short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
|
||||||
|
const void* headerBuffer, size_t hbSize)
|
||||||
|
{
|
||||||
|
return FSE_readNCount_bmi2(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize, /* bmi2 */ 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! HUF_readStats() :
|
||||||
|
Read compact Huffman tree, saved by HUF_writeCTable().
|
||||||
|
`huffWeight` is destination buffer.
|
||||||
|
`rankStats` is assumed to be a table of at least HUF_TABLELOG_MAX U32.
|
||||||
|
@return : size read from `src` , or an error Code .
|
||||||
|
Note : Needed by HUF_readCTable() and HUF_readDTableX?() .
|
||||||
|
*/
|
||||||
|
size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats,
|
||||||
|
U32* nbSymbolsPtr, U32* tableLogPtr,
|
||||||
|
const void* src, size_t srcSize)
|
||||||
|
{
|
||||||
|
U32 wksp[HUF_READ_STATS_WORKSPACE_SIZE_U32];
|
||||||
|
return HUF_readStats_wksp(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, wksp, sizeof(wksp), /* bmi2 */ 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE_TEMPLATE size_t
|
||||||
|
HUF_readStats_body(BYTE* huffWeight, size_t hwSize, U32* rankStats,
|
||||||
|
U32* nbSymbolsPtr, U32* tableLogPtr,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
void* workSpace, size_t wkspSize,
|
||||||
|
int bmi2)
|
||||||
|
{
|
||||||
|
U32 weightTotal;
|
||||||
|
const BYTE* ip = (const BYTE*) src;
|
||||||
|
size_t iSize;
|
||||||
|
size_t oSize;
|
||||||
|
|
||||||
|
if (!srcSize) return ERROR(srcSize_wrong);
|
||||||
|
iSize = ip[0];
|
||||||
|
/* ZSTD_memset(huffWeight, 0, hwSize); *//* is not necessary, even though some analyzer complain ... */
|
||||||
|
|
||||||
|
if (iSize >= 128) { /* special header */
|
||||||
|
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<oSize; n+=2) {
|
||||||
|
huffWeight[n] = ip[n/2] >> 4;
|
||||||
|
huffWeight[n+1] = ip[n/2] & 15;
|
||||||
|
} } }
|
||||||
|
else { /* header compressed with FSE (normal case) */
|
||||||
|
if (iSize+1 > srcSize) return ERROR(srcSize_wrong);
|
||||||
|
/* max (hwSize-1) values decoded, as last one is implied */
|
||||||
|
oSize = FSE_decompress_wksp_bmi2(huffWeight, hwSize-1, ip+1, iSize, 6, workSpace, wkspSize, bmi2);
|
||||||
|
if (FSE_isError(oSize)) return oSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* collect weight stats */
|
||||||
|
ZSTD_memset(rankStats, 0, (HUF_TABLELOG_MAX + 1) * sizeof(U32));
|
||||||
|
weightTotal = 0;
|
||||||
|
{ U32 n; for (n=0; n<oSize; n++) {
|
||||||
|
if (huffWeight[n] > HUF_TABLELOG_MAX) 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 = BIT_highbit32(weightTotal) + 1;
|
||||||
|
if (tableLog > HUF_TABLELOG_MAX) return ERROR(corruption_detected);
|
||||||
|
*tableLogPtr = tableLog;
|
||||||
|
/* determine last weight */
|
||||||
|
{ U32 const total = 1 << tableLog;
|
||||||
|
U32 const rest = total - weightTotal;
|
||||||
|
U32 const verif = 1 << BIT_highbit32(rest);
|
||||||
|
U32 const lastWeight = BIT_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Avoids the FORCE_INLINE of the _body() function. */
|
||||||
|
static size_t HUF_readStats_body_default(BYTE* huffWeight, size_t hwSize, U32* rankStats,
|
||||||
|
U32* nbSymbolsPtr, U32* tableLogPtr,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
void* workSpace, size_t wkspSize)
|
||||||
|
{
|
||||||
|
return HUF_readStats_body(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DYNAMIC_BMI2
|
||||||
|
static BMI2_TARGET_ATTRIBUTE size_t HUF_readStats_body_bmi2(BYTE* huffWeight, size_t hwSize, U32* rankStats,
|
||||||
|
U32* nbSymbolsPtr, U32* tableLogPtr,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
void* workSpace, size_t wkspSize)
|
||||||
|
{
|
||||||
|
return HUF_readStats_body(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize, 1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
size_t HUF_readStats_wksp(BYTE* huffWeight, size_t hwSize, U32* rankStats,
|
||||||
|
U32* nbSymbolsPtr, U32* tableLogPtr,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
void* workSpace, size_t wkspSize,
|
||||||
|
int bmi2)
|
||||||
|
{
|
||||||
|
#if DYNAMIC_BMI2
|
||||||
|
if (bmi2) {
|
||||||
|
return HUF_readStats_body_bmi2(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
(void)bmi2;
|
||||||
|
return HUF_readStats_body_default(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize);
|
||||||
|
}
|
56
lib/zstd/common/error_private.c
Normal file
56
lib/zstd/common/error_private.c
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Yann Collet, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* The purpose of this file is to have a single list of error strings embedded in binary */
|
||||||
|
|
||||||
|
#include "error_private.h"
|
||||||
|
|
||||||
|
const char* ERR_getErrorString(ERR_enum code)
|
||||||
|
{
|
||||||
|
#ifdef ZSTD_STRIP_ERROR_STRINGS
|
||||||
|
(void)code;
|
||||||
|
return "Error strings stripped";
|
||||||
|
#else
|
||||||
|
static const char* const notErrorCode = "Unspecified error code";
|
||||||
|
switch( code )
|
||||||
|
{
|
||||||
|
case PREFIX(no_error): return "No error detected";
|
||||||
|
case PREFIX(GENERIC): return "Error (generic)";
|
||||||
|
case PREFIX(prefix_unknown): return "Unknown frame descriptor";
|
||||||
|
case PREFIX(version_unsupported): return "Version not supported";
|
||||||
|
case PREFIX(frameParameter_unsupported): return "Unsupported frame parameter";
|
||||||
|
case PREFIX(frameParameter_windowTooLarge): return "Frame requires too much memory for decoding";
|
||||||
|
case PREFIX(corruption_detected): return "Corrupted block detected";
|
||||||
|
case PREFIX(checksum_wrong): return "Restored data doesn't match checksum";
|
||||||
|
case PREFIX(parameter_unsupported): return "Unsupported parameter";
|
||||||
|
case PREFIX(parameter_outOfBound): return "Parameter is out of bound";
|
||||||
|
case PREFIX(init_missing): return "Context should be init first";
|
||||||
|
case PREFIX(memory_allocation): return "Allocation error : not enough memory";
|
||||||
|
case PREFIX(workSpace_tooSmall): return "workSpace buffer is not large enough";
|
||||||
|
case PREFIX(stage_wrong): return "Operation not authorized at current processing stage";
|
||||||
|
case PREFIX(tableLog_tooLarge): return "tableLog requires too much memory : unsupported";
|
||||||
|
case PREFIX(maxSymbolValue_tooLarge): return "Unsupported max Symbol Value : too large";
|
||||||
|
case PREFIX(maxSymbolValue_tooSmall): return "Specified maxSymbolValue is too small";
|
||||||
|
case PREFIX(dictionary_corrupted): return "Dictionary is corrupted";
|
||||||
|
case PREFIX(dictionary_wrong): return "Dictionary mismatch";
|
||||||
|
case PREFIX(dictionaryCreation_failed): return "Cannot create Dictionary from provided samples";
|
||||||
|
case PREFIX(dstSize_tooSmall): return "Destination buffer is too small";
|
||||||
|
case PREFIX(srcSize_wrong): return "Src size is incorrect";
|
||||||
|
case PREFIX(dstBuffer_null): return "Operation on NULL destination buffer";
|
||||||
|
/* following error codes are not stable and may be removed or changed in a future version */
|
||||||
|
case PREFIX(frameIndex_tooLarge): return "Frame index is too large";
|
||||||
|
case PREFIX(seekableIO): return "An I/O error occurred when reading/seeking";
|
||||||
|
case PREFIX(dstBuffer_wrong): return "Destination buffer is wrong";
|
||||||
|
case PREFIX(srcBuffer_wrong): return "Source buffer is wrong";
|
||||||
|
case PREFIX(maxCode):
|
||||||
|
default: return notErrorCode;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
145
lib/zstd/common/error_private.h
Normal file
145
lib/zstd/common/error_private.h
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Yann Collet, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Note : this module is expected to remain private, do not expose it */
|
||||||
|
|
||||||
|
#ifndef ERROR_H_MODULE
|
||||||
|
#define ERROR_H_MODULE
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ****************************************
|
||||||
|
* Dependencies
|
||||||
|
******************************************/
|
||||||
|
#include <linux/zstd_errors.h> /* enum list */
|
||||||
|
#include "compiler.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "zstd_deps.h" /* size_t */
|
||||||
|
|
||||||
|
|
||||||
|
/* ****************************************
|
||||||
|
* Compiler-specific
|
||||||
|
******************************************/
|
||||||
|
#define ERR_STATIC static __attribute__((unused))
|
||||||
|
|
||||||
|
|
||||||
|
/*-****************************************
|
||||||
|
* Customization (error_public.h)
|
||||||
|
******************************************/
|
||||||
|
typedef ZSTD_ErrorCode ERR_enum;
|
||||||
|
#define PREFIX(name) ZSTD_error_##name
|
||||||
|
|
||||||
|
|
||||||
|
/*-****************************************
|
||||||
|
* Error codes handling
|
||||||
|
******************************************/
|
||||||
|
#undef ERROR /* already defined on Visual Studio */
|
||||||
|
#define ERROR(name) ZSTD_ERROR(name)
|
||||||
|
#define ZSTD_ERROR(name) ((size_t)-PREFIX(name))
|
||||||
|
|
||||||
|
ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); }
|
||||||
|
|
||||||
|
ERR_STATIC ERR_enum ERR_getErrorCode(size_t code) { if (!ERR_isError(code)) return (ERR_enum)0; return (ERR_enum) (0-code); }
|
||||||
|
|
||||||
|
/* check and forward error code */
|
||||||
|
#define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return e
|
||||||
|
#define CHECK_F(f) { CHECK_V_F(_var_err__, f); }
|
||||||
|
|
||||||
|
|
||||||
|
/*-****************************************
|
||||||
|
* Error Strings
|
||||||
|
******************************************/
|
||||||
|
|
||||||
|
const char* ERR_getErrorString(ERR_enum code); /* error_private.c */
|
||||||
|
|
||||||
|
ERR_STATIC const char* ERR_getErrorName(size_t code)
|
||||||
|
{
|
||||||
|
return ERR_getErrorString(ERR_getErrorCode(code));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ignore: this is an internal helper.
|
||||||
|
*
|
||||||
|
* This is a helper function to help force C99-correctness during compilation.
|
||||||
|
* Under strict compilation modes, variadic macro arguments can't be empty.
|
||||||
|
* However, variadic function arguments can be. Using a function therefore lets
|
||||||
|
* us statically check that at least one (string) argument was passed,
|
||||||
|
* independent of the compilation flags.
|
||||||
|
*/
|
||||||
|
static INLINE_KEYWORD UNUSED_ATTR
|
||||||
|
void _force_has_format_string(const char *format, ...) {
|
||||||
|
(void)format;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ignore: this is an internal helper.
|
||||||
|
*
|
||||||
|
* We want to force this function invocation to be syntactically correct, but
|
||||||
|
* we don't want to force runtime evaluation of its arguments.
|
||||||
|
*/
|
||||||
|
#define _FORCE_HAS_FORMAT_STRING(...) \
|
||||||
|
if (0) { \
|
||||||
|
_force_has_format_string(__VA_ARGS__); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ERR_QUOTE(str) #str
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the specified error if the condition evaluates to true.
|
||||||
|
*
|
||||||
|
* In debug modes, prints additional information.
|
||||||
|
* In order to do that (particularly, printing the conditional that failed),
|
||||||
|
* this can't just wrap RETURN_ERROR().
|
||||||
|
*/
|
||||||
|
#define RETURN_ERROR_IF(cond, err, ...) \
|
||||||
|
if (cond) { \
|
||||||
|
RAWLOG(3, "%s:%d: ERROR!: check %s failed, returning %s", \
|
||||||
|
__FILE__, __LINE__, ERR_QUOTE(cond), ERR_QUOTE(ERROR(err))); \
|
||||||
|
_FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \
|
||||||
|
RAWLOG(3, ": " __VA_ARGS__); \
|
||||||
|
RAWLOG(3, "\n"); \
|
||||||
|
return ERROR(err); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unconditionally return the specified error.
|
||||||
|
*
|
||||||
|
* In debug modes, prints additional information.
|
||||||
|
*/
|
||||||
|
#define RETURN_ERROR(err, ...) \
|
||||||
|
do { \
|
||||||
|
RAWLOG(3, "%s:%d: ERROR!: unconditional check failed, returning %s", \
|
||||||
|
__FILE__, __LINE__, ERR_QUOTE(ERROR(err))); \
|
||||||
|
_FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \
|
||||||
|
RAWLOG(3, ": " __VA_ARGS__); \
|
||||||
|
RAWLOG(3, "\n"); \
|
||||||
|
return ERROR(err); \
|
||||||
|
} while(0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the provided expression evaluates to an error code, returns that error code.
|
||||||
|
*
|
||||||
|
* In debug modes, prints additional information.
|
||||||
|
*/
|
||||||
|
#define FORWARD_IF_ERROR(err, ...) \
|
||||||
|
do { \
|
||||||
|
size_t const err_code = (err); \
|
||||||
|
if (ERR_isError(err_code)) { \
|
||||||
|
RAWLOG(3, "%s:%d: ERROR!: forwarding error in %s: %s", \
|
||||||
|
__FILE__, __LINE__, ERR_QUOTE(err), ERR_getErrorName(err_code)); \
|
||||||
|
_FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \
|
||||||
|
RAWLOG(3, ": " __VA_ARGS__); \
|
||||||
|
RAWLOG(3, "\n"); \
|
||||||
|
return err_code; \
|
||||||
|
} \
|
||||||
|
} while(0);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* ERROR_H_MODULE */
|
711
lib/zstd/common/fse.h
Normal file
711
lib/zstd/common/fse.h
Normal file
|
@ -0,0 +1,711 @@
|
||||||
|
/* ******************************************************************
|
||||||
|
* FSE : Finite State Entropy codec
|
||||||
|
* Public Prototypes declaration
|
||||||
|
* Copyright (c) Yann Collet, Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You can contact the author at :
|
||||||
|
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
****************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FSE_H
|
||||||
|
#define FSE_H
|
||||||
|
|
||||||
|
|
||||||
|
/*-*****************************************
|
||||||
|
* Dependencies
|
||||||
|
******************************************/
|
||||||
|
#include "zstd_deps.h" /* size_t, ptrdiff_t */
|
||||||
|
|
||||||
|
|
||||||
|
/*-*****************************************
|
||||||
|
* FSE_PUBLIC_API : control library symbols visibility
|
||||||
|
******************************************/
|
||||||
|
#if defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) && defined(__GNUC__) && (__GNUC__ >= 4)
|
||||||
|
# define FSE_PUBLIC_API __attribute__ ((visibility ("default")))
|
||||||
|
#elif defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) /* Visual expected */
|
||||||
|
# define FSE_PUBLIC_API __declspec(dllexport)
|
||||||
|
#elif defined(FSE_DLL_IMPORT) && (FSE_DLL_IMPORT==1)
|
||||||
|
# define FSE_PUBLIC_API __declspec(dllimport) /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/
|
||||||
|
#else
|
||||||
|
# define FSE_PUBLIC_API
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*------ Version ------*/
|
||||||
|
#define FSE_VERSION_MAJOR 0
|
||||||
|
#define FSE_VERSION_MINOR 9
|
||||||
|
#define FSE_VERSION_RELEASE 0
|
||||||
|
|
||||||
|
#define FSE_LIB_VERSION FSE_VERSION_MAJOR.FSE_VERSION_MINOR.FSE_VERSION_RELEASE
|
||||||
|
#define FSE_QUOTE(str) #str
|
||||||
|
#define FSE_EXPAND_AND_QUOTE(str) FSE_QUOTE(str)
|
||||||
|
#define FSE_VERSION_STRING FSE_EXPAND_AND_QUOTE(FSE_LIB_VERSION)
|
||||||
|
|
||||||
|
#define FSE_VERSION_NUMBER (FSE_VERSION_MAJOR *100*100 + FSE_VERSION_MINOR *100 + FSE_VERSION_RELEASE)
|
||||||
|
FSE_PUBLIC_API unsigned FSE_versionNumber(void); /*< library version number; to be used when checking dll version */
|
||||||
|
|
||||||
|
|
||||||
|
/*-****************************************
|
||||||
|
* FSE simple functions
|
||||||
|
******************************************/
|
||||||
|
/*! FSE_compress() :
|
||||||
|
Compress content of buffer 'src', of size 'srcSize', into destination buffer 'dst'.
|
||||||
|
'dst' buffer must be already allocated. Compression runs faster is dstCapacity >= FSE_compressBound(srcSize).
|
||||||
|
@return : size of compressed data (<= dstCapacity).
|
||||||
|
Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!!
|
||||||
|
if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression instead.
|
||||||
|
if FSE_isError(return), compression failed (more details using FSE_getErrorName())
|
||||||
|
*/
|
||||||
|
FSE_PUBLIC_API size_t FSE_compress(void* dst, size_t dstCapacity,
|
||||||
|
const void* src, size_t srcSize);
|
||||||
|
|
||||||
|
/*! FSE_decompress():
|
||||||
|
Decompress FSE data from buffer 'cSrc', of size 'cSrcSize',
|
||||||
|
into already allocated destination buffer 'dst', of size 'dstCapacity'.
|
||||||
|
@return : size of regenerated data (<= maxDstSize),
|
||||||
|
or an error code, which can be tested using FSE_isError() .
|
||||||
|
|
||||||
|
** Important ** : FSE_decompress() does not 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.
|
||||||
|
*/
|
||||||
|
FSE_PUBLIC_API size_t FSE_decompress(void* dst, size_t dstCapacity,
|
||||||
|
const void* cSrc, size_t cSrcSize);
|
||||||
|
|
||||||
|
|
||||||
|
/*-*****************************************
|
||||||
|
* Tool functions
|
||||||
|
******************************************/
|
||||||
|
FSE_PUBLIC_API size_t FSE_compressBound(size_t size); /* maximum compressed size */
|
||||||
|
|
||||||
|
/* Error Management */
|
||||||
|
FSE_PUBLIC_API unsigned FSE_isError(size_t code); /* tells if a return value is an error code */
|
||||||
|
FSE_PUBLIC_API const char* FSE_getErrorName(size_t code); /* provides error code string (useful for debugging) */
|
||||||
|
|
||||||
|
|
||||||
|
/*-*****************************************
|
||||||
|
* FSE advanced functions
|
||||||
|
******************************************/
|
||||||
|
/*! FSE_compress2() :
|
||||||
|
Same as FSE_compress(), but allows the selection of 'maxSymbolValue' and 'tableLog'
|
||||||
|
Both parameters can be defined as '0' to mean : use default value
|
||||||
|
@return : size of compressed data
|
||||||
|
Special values : if return == 0, srcData is not compressible => Nothing is stored within cSrc !!!
|
||||||
|
if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression.
|
||||||
|
if FSE_isError(return), it's an error code.
|
||||||
|
*/
|
||||||
|
FSE_PUBLIC_API size_t FSE_compress2 (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog);
|
||||||
|
|
||||||
|
|
||||||
|
/*-*****************************************
|
||||||
|
* FSE detailed API
|
||||||
|
******************************************/
|
||||||
|
/*!
|
||||||
|
FSE_compress() does the following:
|
||||||
|
1. count symbol occurrence from source[] into table count[] (see hist.h)
|
||||||
|
2. normalize counters so that sum(count[]) == Power_of_2 (2^tableLog)
|
||||||
|
3. save normalized counters to memory buffer using writeNCount()
|
||||||
|
4. build encoding table 'CTable' from normalized counters
|
||||||
|
5. encode the data stream using encoding table 'CTable'
|
||||||
|
|
||||||
|
FSE_decompress() does the following:
|
||||||
|
1. read normalized counters with readNCount()
|
||||||
|
2. build decoding table 'DTable' from normalized counters
|
||||||
|
3. decode the data stream using decoding table 'DTable'
|
||||||
|
|
||||||
|
The following API allows targeting specific sub-functions for advanced tasks.
|
||||||
|
For example, it's possible to compress several blocks using the same 'CTable',
|
||||||
|
or to save and provide normalized distribution using external method.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* *** COMPRESSION *** */
|
||||||
|
|
||||||
|
/*! FSE_optimalTableLog():
|
||||||
|
dynamically downsize 'tableLog' when conditions are met.
|
||||||
|
It saves CPU time, by using smaller tables, while preserving or even improving compression ratio.
|
||||||
|
@return : recommended tableLog (necessarily <= 'maxTableLog') */
|
||||||
|
FSE_PUBLIC_API unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue);
|
||||||
|
|
||||||
|
/*! FSE_normalizeCount():
|
||||||
|
normalize counts so that sum(count[]) == Power_of_2 (2^tableLog)
|
||||||
|
'normalizedCounter' is a table of short, of minimum size (maxSymbolValue+1).
|
||||||
|
useLowProbCount is a boolean parameter which trades off compressed size for
|
||||||
|
faster header decoding. When it is set to 1, the compressed data will be slightly
|
||||||
|
smaller. And when it is set to 0, FSE_readNCount() and FSE_buildDTable() will be
|
||||||
|
faster. If you are compressing a small amount of data (< 2 KB) then useLowProbCount=0
|
||||||
|
is a good default, since header deserialization makes a big speed difference.
|
||||||
|
Otherwise, useLowProbCount=1 is a good default, since the speed difference is small.
|
||||||
|
@return : tableLog,
|
||||||
|
or an errorCode, which can be tested using FSE_isError() */
|
||||||
|
FSE_PUBLIC_API size_t FSE_normalizeCount(short* normalizedCounter, unsigned tableLog,
|
||||||
|
const unsigned* count, size_t srcSize, unsigned maxSymbolValue, unsigned useLowProbCount);
|
||||||
|
|
||||||
|
/*! FSE_NCountWriteBound():
|
||||||
|
Provides the maximum possible size of an FSE normalized table, given 'maxSymbolValue' and 'tableLog'.
|
||||||
|
Typically useful for allocation purpose. */
|
||||||
|
FSE_PUBLIC_API size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog);
|
||||||
|
|
||||||
|
/*! FSE_writeNCount():
|
||||||
|
Compactly save 'normalizedCounter' into 'buffer'.
|
||||||
|
@return : size of the compressed table,
|
||||||
|
or an errorCode, which can be tested using FSE_isError(). */
|
||||||
|
FSE_PUBLIC_API size_t FSE_writeNCount (void* buffer, size_t bufferSize,
|
||||||
|
const short* normalizedCounter,
|
||||||
|
unsigned maxSymbolValue, unsigned tableLog);
|
||||||
|
|
||||||
|
/*! Constructor and Destructor of FSE_CTable.
|
||||||
|
Note that FSE_CTable size depends on 'tableLog' and 'maxSymbolValue' */
|
||||||
|
typedef unsigned FSE_CTable; /* don't allocate that. It's only meant to be more restrictive than void* */
|
||||||
|
FSE_PUBLIC_API FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog);
|
||||||
|
FSE_PUBLIC_API void FSE_freeCTable (FSE_CTable* ct);
|
||||||
|
|
||||||
|
/*! FSE_buildCTable():
|
||||||
|
Builds `ct`, which must be already allocated, using FSE_createCTable().
|
||||||
|
@return : 0, or an errorCode, which can be tested using FSE_isError() */
|
||||||
|
FSE_PUBLIC_API size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);
|
||||||
|
|
||||||
|
/*! FSE_compress_usingCTable():
|
||||||
|
Compress `src` using `ct` into `dst` which must be already allocated.
|
||||||
|
@return : size of compressed data (<= `dstCapacity`),
|
||||||
|
or 0 if compressed data could not fit into `dst`,
|
||||||
|
or an errorCode, which can be tested using FSE_isError() */
|
||||||
|
FSE_PUBLIC_API size_t FSE_compress_usingCTable (void* dst, size_t dstCapacity, const void* src, size_t srcSize, const FSE_CTable* ct);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Tutorial :
|
||||||
|
----------
|
||||||
|
The first step is to count all symbols. FSE_count() does this job very fast.
|
||||||
|
Result will be saved into 'count', a table of unsigned int, which must be already allocated, and have 'maxSymbolValuePtr[0]+1' cells.
|
||||||
|
'src' is a table of bytes of size 'srcSize'. All values within 'src' MUST be <= maxSymbolValuePtr[0]
|
||||||
|
maxSymbolValuePtr[0] will be updated, with its real value (necessarily <= original value)
|
||||||
|
FSE_count() will return the number of occurrence of the most frequent symbol.
|
||||||
|
This can be used to know if there is a single symbol within 'src', and to quickly evaluate its compressibility.
|
||||||
|
If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()).
|
||||||
|
|
||||||
|
The next step is to normalize the frequencies.
|
||||||
|
FSE_normalizeCount() will ensure that sum of frequencies is == 2 ^'tableLog'.
|
||||||
|
It also guarantees a minimum of 1 to any Symbol with frequency >= 1.
|
||||||
|
You can use 'tableLog'==0 to mean "use default tableLog value".
|
||||||
|
If you are unsure of which tableLog value to use, you can ask FSE_optimalTableLog(),
|
||||||
|
which will provide the optimal valid tableLog given sourceSize, maxSymbolValue, and a user-defined maximum (0 means "default").
|
||||||
|
|
||||||
|
The result of FSE_normalizeCount() will be saved into a table,
|
||||||
|
called 'normalizedCounter', which is a table of signed short.
|
||||||
|
'normalizedCounter' must be already allocated, and have at least 'maxSymbolValue+1' cells.
|
||||||
|
The return value is tableLog if everything proceeded as expected.
|
||||||
|
It is 0 if there is a single symbol within distribution.
|
||||||
|
If there is an error (ex: invalid tableLog value), the function will return an ErrorCode (which can be tested using FSE_isError()).
|
||||||
|
|
||||||
|
'normalizedCounter' can be saved in a compact manner to a memory area using FSE_writeNCount().
|
||||||
|
'buffer' must be already allocated.
|
||||||
|
For guaranteed success, buffer size must be at least FSE_headerBound().
|
||||||
|
The result of the function is the number of bytes written into 'buffer'.
|
||||||
|
If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError(); ex : buffer size too small).
|
||||||
|
|
||||||
|
'normalizedCounter' can then be used to create the compression table 'CTable'.
|
||||||
|
The space required by 'CTable' must be already allocated, using FSE_createCTable().
|
||||||
|
You can then use FSE_buildCTable() to fill 'CTable'.
|
||||||
|
If there is an error, both functions will return an ErrorCode (which can be tested using FSE_isError()).
|
||||||
|
|
||||||
|
'CTable' can then be used to compress 'src', with FSE_compress_usingCTable().
|
||||||
|
Similar to FSE_count(), the convention is that 'src' is assumed to be a table of char of size 'srcSize'
|
||||||
|
The function returns the size of compressed data (without header), necessarily <= `dstCapacity`.
|
||||||
|
If it returns '0', compressed data could not fit into 'dst'.
|
||||||
|
If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()).
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* *** DECOMPRESSION *** */
|
||||||
|
|
||||||
|
/*! FSE_readNCount():
|
||||||
|
Read compactly saved 'normalizedCounter' from 'rBuffer'.
|
||||||
|
@return : size read from 'rBuffer',
|
||||||
|
or an errorCode, which can be tested using FSE_isError().
|
||||||
|
maxSymbolValuePtr[0] and tableLogPtr[0] will also be updated with their respective values */
|
||||||
|
FSE_PUBLIC_API size_t FSE_readNCount (short* normalizedCounter,
|
||||||
|
unsigned* maxSymbolValuePtr, unsigned* tableLogPtr,
|
||||||
|
const void* rBuffer, size_t rBuffSize);
|
||||||
|
|
||||||
|
/*! FSE_readNCount_bmi2():
|
||||||
|
* Same as FSE_readNCount() but pass bmi2=1 when your CPU supports BMI2 and 0 otherwise.
|
||||||
|
*/
|
||||||
|
FSE_PUBLIC_API size_t FSE_readNCount_bmi2(short* normalizedCounter,
|
||||||
|
unsigned* maxSymbolValuePtr, unsigned* tableLogPtr,
|
||||||
|
const void* rBuffer, size_t rBuffSize, int bmi2);
|
||||||
|
|
||||||
|
/*! Constructor and Destructor of FSE_DTable.
|
||||||
|
Note that its size depends on 'tableLog' */
|
||||||
|
typedef unsigned FSE_DTable; /* don't allocate that. It's just a way to be more restrictive than void* */
|
||||||
|
FSE_PUBLIC_API FSE_DTable* FSE_createDTable(unsigned tableLog);
|
||||||
|
FSE_PUBLIC_API void FSE_freeDTable(FSE_DTable* dt);
|
||||||
|
|
||||||
|
/*! FSE_buildDTable():
|
||||||
|
Builds 'dt', which must be already allocated, using FSE_createDTable().
|
||||||
|
return : 0, or an errorCode, which can be tested using FSE_isError() */
|
||||||
|
FSE_PUBLIC_API size_t FSE_buildDTable (FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);
|
||||||
|
|
||||||
|
/*! FSE_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 FSE_isError() */
|
||||||
|
FSE_PUBLIC_API size_t FSE_decompress_usingDTable(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, const FSE_DTable* dt);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Tutorial :
|
||||||
|
----------
|
||||||
|
(Note : these functions only decompress FSE-compressed blocks.
|
||||||
|
If block is uncompressed, use memcpy() instead
|
||||||
|
If block is a single repeated byte, use memset() instead )
|
||||||
|
|
||||||
|
The first step is to obtain the normalized frequencies of symbols.
|
||||||
|
This can be performed by FSE_readNCount() if it was saved using FSE_writeNCount().
|
||||||
|
'normalizedCounter' must be already allocated, and have at least 'maxSymbolValuePtr[0]+1' cells of signed short.
|
||||||
|
In practice, that means it's necessary to know 'maxSymbolValue' beforehand,
|
||||||
|
or size the table to handle worst case situations (typically 256).
|
||||||
|
FSE_readNCount() will provide 'tableLog' and 'maxSymbolValue'.
|
||||||
|
The result of FSE_readNCount() is the number of bytes read from 'rBuffer'.
|
||||||
|
Note that 'rBufferSize' must be at least 4 bytes, even if useful information is less than that.
|
||||||
|
If there is an error, the function will return an error code, which can be tested using FSE_isError().
|
||||||
|
|
||||||
|
The next step is to build the decompression tables 'FSE_DTable' from 'normalizedCounter'.
|
||||||
|
This is performed by the function FSE_buildDTable().
|
||||||
|
The space required by 'FSE_DTable' must be already allocated using FSE_createDTable().
|
||||||
|
If there is an error, the function will return an error code, which can be tested using FSE_isError().
|
||||||
|
|
||||||
|
`FSE_DTable` can then be used to decompress `cSrc`, with FSE_decompress_usingDTable().
|
||||||
|
`cSrcSize` must be strictly correct, otherwise decompression will fail.
|
||||||
|
FSE_decompress_usingDTable() result will tell how many bytes were regenerated (<=`dstCapacity`).
|
||||||
|
If there is an error, the function will return an error code, which can be tested using FSE_isError(). (ex: dst buffer too small)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#endif /* FSE_H */
|
||||||
|
|
||||||
|
#if !defined(FSE_H_FSE_STATIC_LINKING_ONLY)
|
||||||
|
#define FSE_H_FSE_STATIC_LINKING_ONLY
|
||||||
|
|
||||||
|
/* *** Dependency *** */
|
||||||
|
#include "bitstream.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* *****************************************
|
||||||
|
* Static allocation
|
||||||
|
*******************************************/
|
||||||
|
/* FSE buffer bounds */
|
||||||
|
#define FSE_NCOUNTBOUND 512
|
||||||
|
#define FSE_BLOCKBOUND(size) ((size) + ((size)>>7) + 4 /* fse states */ + sizeof(size_t) /* bitContainer */)
|
||||||
|
#define FSE_COMPRESSBOUND(size) (FSE_NCOUNTBOUND + FSE_BLOCKBOUND(size)) /* Macro version, useful for static allocation */
|
||||||
|
|
||||||
|
/* It is possible to statically allocate FSE CTable/DTable as a table of FSE_CTable/FSE_DTable using below macros */
|
||||||
|
#define FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) (1 + (1<<((maxTableLog)-1)) + (((maxSymbolValue)+1)*2))
|
||||||
|
#define FSE_DTABLE_SIZE_U32(maxTableLog) (1 + (1<<(maxTableLog)))
|
||||||
|
|
||||||
|
/* or use the size to malloc() space directly. Pay attention to alignment restrictions though */
|
||||||
|
#define FSE_CTABLE_SIZE(maxTableLog, maxSymbolValue) (FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) * sizeof(FSE_CTable))
|
||||||
|
#define FSE_DTABLE_SIZE(maxTableLog) (FSE_DTABLE_SIZE_U32(maxTableLog) * sizeof(FSE_DTable))
|
||||||
|
|
||||||
|
|
||||||
|
/* *****************************************
|
||||||
|
* FSE advanced API
|
||||||
|
***************************************** */
|
||||||
|
|
||||||
|
unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus);
|
||||||
|
/*< same as FSE_optimalTableLog(), which used `minus==2` */
|
||||||
|
|
||||||
|
/* FSE_compress_wksp() :
|
||||||
|
* Same as FSE_compress2(), but using an externally allocated scratch buffer (`workSpace`).
|
||||||
|
* FSE_COMPRESS_WKSP_SIZE_U32() provides the minimum size required for `workSpace` as a table of FSE_CTable.
|
||||||
|
*/
|
||||||
|
#define FSE_COMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) ( FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) + ((maxTableLog > 12) ? (1 << (maxTableLog - 2)) : 1024) )
|
||||||
|
size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);
|
||||||
|
|
||||||
|
size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits);
|
||||||
|
/*< build a fake FSE_CTable, designed for a flat distribution, where each symbol uses nbBits */
|
||||||
|
|
||||||
|
size_t FSE_buildCTable_rle (FSE_CTable* ct, unsigned char symbolValue);
|
||||||
|
/*< build a fake FSE_CTable, designed to compress always the same symbolValue */
|
||||||
|
|
||||||
|
/* FSE_buildCTable_wksp() :
|
||||||
|
* Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`).
|
||||||
|
* `wkspSize` must be >= `FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog)` of `unsigned`.
|
||||||
|
* See FSE_buildCTable_wksp() for breakdown of workspace usage.
|
||||||
|
*/
|
||||||
|
#define FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog) (((maxSymbolValue + 2) + (1ull << (tableLog)))/2 + sizeof(U64)/sizeof(U32) /* additional 8 bytes for potential table overwrite */)
|
||||||
|
#define FSE_BUILD_CTABLE_WORKSPACE_SIZE(maxSymbolValue, tableLog) (sizeof(unsigned) * FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog))
|
||||||
|
size_t FSE_buildCTable_wksp(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);
|
||||||
|
|
||||||
|
#define FSE_BUILD_DTABLE_WKSP_SIZE(maxTableLog, maxSymbolValue) (sizeof(short) * (maxSymbolValue + 1) + (1ULL << maxTableLog) + 8)
|
||||||
|
#define FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) ((FSE_BUILD_DTABLE_WKSP_SIZE(maxTableLog, maxSymbolValue) + sizeof(unsigned) - 1) / sizeof(unsigned))
|
||||||
|
FSE_PUBLIC_API size_t FSE_buildDTable_wksp(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);
|
||||||
|
/*< Same as FSE_buildDTable(), using an externally allocated `workspace` produced with `FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxSymbolValue)` */
|
||||||
|
|
||||||
|
size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits);
|
||||||
|
/*< build a fake FSE_DTable, designed to read a flat distribution where each symbol uses nbBits */
|
||||||
|
|
||||||
|
size_t FSE_buildDTable_rle (FSE_DTable* dt, unsigned char symbolValue);
|
||||||
|
/*< build a fake FSE_DTable, designed to always generate the same symbolValue */
|
||||||
|
|
||||||
|
#define FSE_DECOMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) (FSE_DTABLE_SIZE_U32(maxTableLog) + FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) + (FSE_MAX_SYMBOL_VALUE + 1) / 2 + 1)
|
||||||
|
#define FSE_DECOMPRESS_WKSP_SIZE(maxTableLog, maxSymbolValue) (FSE_DECOMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) * sizeof(unsigned))
|
||||||
|
size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize);
|
||||||
|
/*< same as FSE_decompress(), using an externally allocated `workSpace` produced with `FSE_DECOMPRESS_WKSP_SIZE_U32(maxLog, maxSymbolValue)` */
|
||||||
|
|
||||||
|
size_t FSE_decompress_wksp_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize, int bmi2);
|
||||||
|
/*< Same as FSE_decompress_wksp() but with dynamic BMI2 support. Pass 1 if your CPU supports BMI2 or 0 if it doesn't. */
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
FSE_repeat_none, /*< Cannot use the previous table */
|
||||||
|
FSE_repeat_check, /*< Can use the previous table but it must be checked */
|
||||||
|
FSE_repeat_valid /*< Can use the previous table and it is assumed to be valid */
|
||||||
|
} FSE_repeat;
|
||||||
|
|
||||||
|
/* *****************************************
|
||||||
|
* FSE symbol compression API
|
||||||
|
*******************************************/
|
||||||
|
/*!
|
||||||
|
This API consists of small unitary functions, which highly benefit from being inlined.
|
||||||
|
Hence their body are included in next section.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
ptrdiff_t value;
|
||||||
|
const void* stateTable;
|
||||||
|
const void* symbolTT;
|
||||||
|
unsigned stateLog;
|
||||||
|
} FSE_CState_t;
|
||||||
|
|
||||||
|
static void FSE_initCState(FSE_CState_t* CStatePtr, const FSE_CTable* ct);
|
||||||
|
|
||||||
|
static void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* CStatePtr, unsigned symbol);
|
||||||
|
|
||||||
|
static void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* CStatePtr);
|
||||||
|
|
||||||
|
/*<
|
||||||
|
These functions are inner components of FSE_compress_usingCTable().
|
||||||
|
They allow the creation of custom streams, mixing multiple tables and bit sources.
|
||||||
|
|
||||||
|
A key property to keep in mind is that encoding and decoding are done **in reverse direction**.
|
||||||
|
So the first symbol you will encode is the last you will decode, like a LIFO stack.
|
||||||
|
|
||||||
|
You will need a few variables to track your CStream. They are :
|
||||||
|
|
||||||
|
FSE_CTable ct; // Provided by FSE_buildCTable()
|
||||||
|
BIT_CStream_t bitStream; // bitStream tracking structure
|
||||||
|
FSE_CState_t state; // State tracking structure (can have several)
|
||||||
|
|
||||||
|
|
||||||
|
The first thing to do is to init bitStream and state.
|
||||||
|
size_t errorCode = BIT_initCStream(&bitStream, dstBuffer, maxDstSize);
|
||||||
|
FSE_initCState(&state, ct);
|
||||||
|
|
||||||
|
Note that BIT_initCStream() can produce an error code, so its result should be tested, using FSE_isError();
|
||||||
|
You can then encode your input data, byte after byte.
|
||||||
|
FSE_encodeSymbol() outputs a maximum of 'tableLog' bits at a time.
|
||||||
|
Remember decoding will be done in reverse direction.
|
||||||
|
FSE_encodeByte(&bitStream, &state, symbol);
|
||||||
|
|
||||||
|
At any time, you can also add any bit sequence.
|
||||||
|
Note : maximum allowed nbBits is 25, for compatibility with 32-bits decoders
|
||||||
|
BIT_addBits(&bitStream, bitField, nbBits);
|
||||||
|
|
||||||
|
The above methods don't commit data to memory, they just store it into local register, for speed.
|
||||||
|
Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
|
||||||
|
Writing data to memory is a manual operation, performed by the flushBits function.
|
||||||
|
BIT_flushBits(&bitStream);
|
||||||
|
|
||||||
|
Your last FSE encoding operation shall be to flush your last state value(s).
|
||||||
|
FSE_flushState(&bitStream, &state);
|
||||||
|
|
||||||
|
Finally, you must close the bitStream.
|
||||||
|
The function returns the size of CStream in bytes.
|
||||||
|
If data couldn't fit into dstBuffer, it will return a 0 ( == not compressible)
|
||||||
|
If there is an error, it returns an errorCode (which can be tested using FSE_isError()).
|
||||||
|
size_t size = BIT_closeCStream(&bitStream);
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* *****************************************
|
||||||
|
* FSE symbol decompression API
|
||||||
|
*******************************************/
|
||||||
|
typedef struct {
|
||||||
|
size_t state;
|
||||||
|
const void* table; /* precise table may vary, depending on U16 */
|
||||||
|
} FSE_DState_t;
|
||||||
|
|
||||||
|
|
||||||
|
static void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt);
|
||||||
|
|
||||||
|
static unsigned char FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD);
|
||||||
|
|
||||||
|
static unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr);
|
||||||
|
|
||||||
|
/*<
|
||||||
|
Let's now decompose FSE_decompress_usingDTable() into its unitary components.
|
||||||
|
You will decode FSE-encoded symbols from the bitStream,
|
||||||
|
and also any other bitFields you put in, **in reverse order**.
|
||||||
|
|
||||||
|
You will need a few variables to track your bitStream. They are :
|
||||||
|
|
||||||
|
BIT_DStream_t DStream; // Stream context
|
||||||
|
FSE_DState_t DState; // State context. Multiple ones are possible
|
||||||
|
FSE_DTable* DTablePtr; // Decoding table, provided by FSE_buildDTable()
|
||||||
|
|
||||||
|
The first thing to do is to init the bitStream.
|
||||||
|
errorCode = BIT_initDStream(&DStream, srcBuffer, srcSize);
|
||||||
|
|
||||||
|
You should then retrieve your initial state(s)
|
||||||
|
(in reverse flushing order if you have several ones) :
|
||||||
|
errorCode = FSE_initDState(&DState, &DStream, DTablePtr);
|
||||||
|
|
||||||
|
You can then decode your data, symbol after symbol.
|
||||||
|
For information the maximum number of bits read by FSE_decodeSymbol() is 'tableLog'.
|
||||||
|
Keep in mind that symbols are decoded in reverse order, like a LIFO stack (last in, first out).
|
||||||
|
unsigned char symbol = FSE_decodeSymbol(&DState, &DStream);
|
||||||
|
|
||||||
|
You can retrieve any bitfield you eventually stored into the bitStream (in reverse order)
|
||||||
|
Note : maximum allowed nbBits is 25, for 32-bits compatibility
|
||||||
|
size_t bitField = BIT_readBits(&DStream, nbBits);
|
||||||
|
|
||||||
|
All above operations only read from local register (which size depends on size_t).
|
||||||
|
Refueling the register from memory is manually performed by the reload method.
|
||||||
|
endSignal = FSE_reloadDStream(&DStream);
|
||||||
|
|
||||||
|
BIT_reloadDStream() result tells if there is still some more data to read from DStream.
|
||||||
|
BIT_DStream_unfinished : there is still some data left into the DStream.
|
||||||
|
BIT_DStream_endOfBuffer : Dstream reached end of buffer. Its container may no longer be completely filled.
|
||||||
|
BIT_DStream_completed : Dstream reached its exact end, corresponding in general to decompression completed.
|
||||||
|
BIT_DStream_tooFar : Dstream went too far. Decompression result is corrupted.
|
||||||
|
|
||||||
|
When reaching end of buffer (BIT_DStream_endOfBuffer), progress slowly, notably if you decode multiple symbols per loop,
|
||||||
|
to properly detect the exact end of stream.
|
||||||
|
After each decoded symbol, check if DStream is fully consumed using this simple test :
|
||||||
|
BIT_reloadDStream(&DStream) >= BIT_DStream_completed
|
||||||
|
|
||||||
|
When it's done, verify decompression is fully completed, by checking both DStream and the relevant states.
|
||||||
|
Checking if DStream has reached its end is performed by :
|
||||||
|
BIT_endOfDStream(&DStream);
|
||||||
|
Check also the states. There might be some symbols left there, if some high probability ones (>50%) are possible.
|
||||||
|
FSE_endOfDState(&DState);
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* *****************************************
|
||||||
|
* FSE unsafe API
|
||||||
|
*******************************************/
|
||||||
|
static unsigned char FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD);
|
||||||
|
/* faster, but works only if nbBits is always >= 1 (otherwise, result will be corrupted) */
|
||||||
|
|
||||||
|
|
||||||
|
/* *****************************************
|
||||||
|
* Implementation of inlined functions
|
||||||
|
*******************************************/
|
||||||
|
typedef struct {
|
||||||
|
int deltaFindState;
|
||||||
|
U32 deltaNbBits;
|
||||||
|
} FSE_symbolCompressionTransform; /* total 8 bytes */
|
||||||
|
|
||||||
|
MEM_STATIC void FSE_initCState(FSE_CState_t* statePtr, const FSE_CTable* ct)
|
||||||
|
{
|
||||||
|
const void* ptr = ct;
|
||||||
|
const U16* u16ptr = (const U16*) ptr;
|
||||||
|
const U32 tableLog = MEM_read16(ptr);
|
||||||
|
statePtr->value = (ptrdiff_t)1<<tableLog;
|
||||||
|
statePtr->stateTable = u16ptr+2;
|
||||||
|
statePtr->symbolTT = ct + 1 + (tableLog ? (1<<(tableLog-1)) : 1);
|
||||||
|
statePtr->stateLog = tableLog;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! FSE_initCState2() :
|
||||||
|
* Same as FSE_initCState(), but the first symbol to include (which will be the last to be read)
|
||||||
|
* uses the smallest state value possible, saving the cost of this symbol */
|
||||||
|
MEM_STATIC void FSE_initCState2(FSE_CState_t* statePtr, const FSE_CTable* ct, U32 symbol)
|
||||||
|
{
|
||||||
|
FSE_initCState(statePtr, ct);
|
||||||
|
{ const FSE_symbolCompressionTransform symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol];
|
||||||
|
const U16* stateTable = (const U16*)(statePtr->stateTable);
|
||||||
|
U32 nbBitsOut = (U32)((symbolTT.deltaNbBits + (1<<15)) >> 16);
|
||||||
|
statePtr->value = (nbBitsOut << 16) - symbolTT.deltaNbBits;
|
||||||
|
statePtr->value = stateTable[(statePtr->value >> nbBitsOut) + symbolTT.deltaFindState];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* statePtr, unsigned symbol)
|
||||||
|
{
|
||||||
|
FSE_symbolCompressionTransform const symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol];
|
||||||
|
const U16* const stateTable = (const U16*)(statePtr->stateTable);
|
||||||
|
U32 const nbBitsOut = (U32)((statePtr->value + symbolTT.deltaNbBits) >> 16);
|
||||||
|
BIT_addBits(bitC, statePtr->value, nbBitsOut);
|
||||||
|
statePtr->value = stateTable[ (statePtr->value >> nbBitsOut) + symbolTT.deltaFindState];
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* statePtr)
|
||||||
|
{
|
||||||
|
BIT_addBits(bitC, statePtr->value, statePtr->stateLog);
|
||||||
|
BIT_flushBits(bitC);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* FSE_getMaxNbBits() :
|
||||||
|
* Approximate maximum cost of a symbol, in bits.
|
||||||
|
* Fractional get rounded up (i.e : a symbol with a normalized frequency of 3 gives the same result as a frequency of 2)
|
||||||
|
* note 1 : assume symbolValue is valid (<= maxSymbolValue)
|
||||||
|
* note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */
|
||||||
|
MEM_STATIC U32 FSE_getMaxNbBits(const void* symbolTTPtr, U32 symbolValue)
|
||||||
|
{
|
||||||
|
const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr;
|
||||||
|
return (symbolTT[symbolValue].deltaNbBits + ((1<<16)-1)) >> 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FSE_bitCost() :
|
||||||
|
* Approximate symbol cost, as fractional value, using fixed-point format (accuracyLog fractional bits)
|
||||||
|
* note 1 : assume symbolValue is valid (<= maxSymbolValue)
|
||||||
|
* note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */
|
||||||
|
MEM_STATIC U32 FSE_bitCost(const void* symbolTTPtr, U32 tableLog, U32 symbolValue, U32 accuracyLog)
|
||||||
|
{
|
||||||
|
const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr;
|
||||||
|
U32 const minNbBits = symbolTT[symbolValue].deltaNbBits >> 16;
|
||||||
|
U32 const threshold = (minNbBits+1) << 16;
|
||||||
|
assert(tableLog < 16);
|
||||||
|
assert(accuracyLog < 31-tableLog); /* ensure enough room for renormalization double shift */
|
||||||
|
{ U32 const tableSize = 1 << tableLog;
|
||||||
|
U32 const deltaFromThreshold = threshold - (symbolTT[symbolValue].deltaNbBits + tableSize);
|
||||||
|
U32 const normalizedDeltaFromThreshold = (deltaFromThreshold << accuracyLog) >> tableLog; /* linear interpolation (very approximate) */
|
||||||
|
U32 const bitMultiplier = 1 << accuracyLog;
|
||||||
|
assert(symbolTT[symbolValue].deltaNbBits + tableSize <= threshold);
|
||||||
|
assert(normalizedDeltaFromThreshold <= bitMultiplier);
|
||||||
|
return (minNbBits+1)*bitMultiplier - normalizedDeltaFromThreshold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ====== Decompression ====== */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
U16 tableLog;
|
||||||
|
U16 fastMode;
|
||||||
|
} FSE_DTableHeader; /* sizeof U32 */
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned short newState;
|
||||||
|
unsigned char symbol;
|
||||||
|
unsigned char nbBits;
|
||||||
|
} FSE_decode_t; /* size == U32 */
|
||||||
|
|
||||||
|
MEM_STATIC void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt)
|
||||||
|
{
|
||||||
|
const void* ptr = dt;
|
||||||
|
const FSE_DTableHeader* const DTableH = (const FSE_DTableHeader*)ptr;
|
||||||
|
DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog);
|
||||||
|
BIT_reloadDStream(bitD);
|
||||||
|
DStatePtr->table = dt + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC BYTE FSE_peekSymbol(const FSE_DState_t* DStatePtr)
|
||||||
|
{
|
||||||
|
FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
|
||||||
|
return DInfo.symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void FSE_updateState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
|
||||||
|
{
|
||||||
|
FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
|
||||||
|
U32 const nbBits = DInfo.nbBits;
|
||||||
|
size_t const lowBits = BIT_readBits(bitD, nbBits);
|
||||||
|
DStatePtr->state = DInfo.newState + lowBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC BYTE FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
|
||||||
|
{
|
||||||
|
FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
|
||||||
|
U32 const nbBits = DInfo.nbBits;
|
||||||
|
BYTE const symbol = DInfo.symbol;
|
||||||
|
size_t const lowBits = BIT_readBits(bitD, nbBits);
|
||||||
|
|
||||||
|
DStatePtr->state = DInfo.newState + lowBits;
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! FSE_decodeSymbolFast() :
|
||||||
|
unsafe, only works if no symbol has a probability > 50% */
|
||||||
|
MEM_STATIC BYTE FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
|
||||||
|
{
|
||||||
|
FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
|
||||||
|
U32 const nbBits = DInfo.nbBits;
|
||||||
|
BYTE const symbol = DInfo.symbol;
|
||||||
|
size_t const lowBits = BIT_readBitsFast(bitD, nbBits);
|
||||||
|
|
||||||
|
DStatePtr->state = DInfo.newState + lowBits;
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr)
|
||||||
|
{
|
||||||
|
return DStatePtr->state == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FSE_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 */
|
||||||
|
#ifndef FSE_MAX_MEMORY_USAGE
|
||||||
|
# define FSE_MAX_MEMORY_USAGE 14
|
||||||
|
#endif
|
||||||
|
#ifndef FSE_DEFAULT_MEMORY_USAGE
|
||||||
|
# define FSE_DEFAULT_MEMORY_USAGE 13
|
||||||
|
#endif
|
||||||
|
#if (FSE_DEFAULT_MEMORY_USAGE > FSE_MAX_MEMORY_USAGE)
|
||||||
|
# error "FSE_DEFAULT_MEMORY_USAGE must be <= FSE_MAX_MEMORY_USAGE"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*!FSE_MAX_SYMBOL_VALUE :
|
||||||
|
* Maximum symbol value authorized.
|
||||||
|
* Required for proper stack allocation */
|
||||||
|
#ifndef FSE_MAX_SYMBOL_VALUE
|
||||||
|
# define FSE_MAX_SYMBOL_VALUE 255
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* **************************************************************
|
||||||
|
* template functions type & suffix
|
||||||
|
****************************************************************/
|
||||||
|
#define FSE_FUNCTION_TYPE BYTE
|
||||||
|
#define FSE_FUNCTION_EXTENSION
|
||||||
|
#define FSE_DECODE_TYPE FSE_decode_t
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* !FSE_COMMONDEFS_ONLY */
|
||||||
|
|
||||||
|
|
||||||
|
/* ***************************************************************
|
||||||
|
* Constants
|
||||||
|
*****************************************************************/
|
||||||
|
#define FSE_MAX_TABLELOG (FSE_MAX_MEMORY_USAGE-2)
|
||||||
|
#define FSE_MAX_TABLESIZE (1U<<FSE_MAX_TABLELOG)
|
||||||
|
#define FSE_MAXTABLESIZE_MASK (FSE_MAX_TABLESIZE-1)
|
||||||
|
#define FSE_DEFAULT_TABLELOG (FSE_DEFAULT_MEMORY_USAGE-2)
|
||||||
|
#define FSE_MIN_TABLELOG 5
|
||||||
|
|
||||||
|
#define FSE_TABLELOG_ABSOLUTE_MAX 15
|
||||||
|
#if FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX
|
||||||
|
# error "FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX is not supported"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define FSE_TABLESTEP(tableSize) (((tableSize)>>1) + ((tableSize)>>3) + 3)
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* FSE_STATIC_LINKING_ONLY */
|
||||||
|
|
||||||
|
|
390
lib/zstd/common/fse_decompress.c
Normal file
390
lib/zstd/common/fse_decompress.c
Normal file
|
@ -0,0 +1,390 @@
|
||||||
|
/* ******************************************************************
|
||||||
|
* FSE : Finite State Entropy decoder
|
||||||
|
* Copyright (c) Yann Collet, Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You can contact the author at :
|
||||||
|
* - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||||
|
* - Public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
****************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
/* **************************************************************
|
||||||
|
* Includes
|
||||||
|
****************************************************************/
|
||||||
|
#include "debug.h" /* assert */
|
||||||
|
#include "bitstream.h"
|
||||||
|
#include "compiler.h"
|
||||||
|
#define FSE_STATIC_LINKING_ONLY
|
||||||
|
#include "fse.h"
|
||||||
|
#include "error_private.h"
|
||||||
|
#define ZSTD_DEPS_NEED_MALLOC
|
||||||
|
#include "zstd_deps.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* **************************************************************
|
||||||
|
* Error Management
|
||||||
|
****************************************************************/
|
||||||
|
#define FSE_isError ERR_isError
|
||||||
|
#define FSE_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) /* use only *after* variable declarations */
|
||||||
|
|
||||||
|
|
||||||
|
/* **************************************************************
|
||||||
|
* 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 FSE_FUNCTION_EXTENSION
|
||||||
|
# error "FSE_FUNCTION_EXTENSION must be defined"
|
||||||
|
#endif
|
||||||
|
#ifndef FSE_FUNCTION_TYPE
|
||||||
|
# error "FSE_FUNCTION_TYPE must be defined"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Function names */
|
||||||
|
#define FSE_CAT(X,Y) X##Y
|
||||||
|
#define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y)
|
||||||
|
#define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y)
|
||||||
|
|
||||||
|
|
||||||
|
/* Function templates */
|
||||||
|
FSE_DTable* FSE_createDTable (unsigned tableLog)
|
||||||
|
{
|
||||||
|
if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX;
|
||||||
|
return (FSE_DTable*)ZSTD_malloc( FSE_DTABLE_SIZE_U32(tableLog) * sizeof (U32) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void FSE_freeDTable (FSE_DTable* dt)
|
||||||
|
{
|
||||||
|
ZSTD_free(dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t FSE_buildDTable_internal(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize)
|
||||||
|
{
|
||||||
|
void* const tdPtr = dt+1; /* because *dt is unsigned, 32-bits aligned on 32-bits */
|
||||||
|
FSE_DECODE_TYPE* const tableDecode = (FSE_DECODE_TYPE*) (tdPtr);
|
||||||
|
U16* symbolNext = (U16*)workSpace;
|
||||||
|
BYTE* spread = (BYTE*)(symbolNext + maxSymbolValue + 1);
|
||||||
|
|
||||||
|
U32 const maxSV1 = maxSymbolValue + 1;
|
||||||
|
U32 const tableSize = 1 << tableLog;
|
||||||
|
U32 highThreshold = tableSize-1;
|
||||||
|
|
||||||
|
/* Sanity Checks */
|
||||||
|
if (FSE_BUILD_DTABLE_WKSP_SIZE(tableLog, maxSymbolValue) > wkspSize) return ERROR(maxSymbolValue_tooLarge);
|
||||||
|
if (maxSymbolValue > FSE_MAX_SYMBOL_VALUE) return ERROR(maxSymbolValue_tooLarge);
|
||||||
|
if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge);
|
||||||
|
|
||||||
|
/* Init, lay down lowprob symbols */
|
||||||
|
{ FSE_DTableHeader DTableH;
|
||||||
|
DTableH.tableLog = (U16)tableLog;
|
||||||
|
DTableH.fastMode = 1;
|
||||||
|
{ S16 const largeLimit= (S16)(1 << (tableLog-1));
|
||||||
|
U32 s;
|
||||||
|
for (s=0; s<maxSV1; s++) {
|
||||||
|
if (normalizedCounter[s]==-1) {
|
||||||
|
tableDecode[highThreshold--].symbol = (FSE_FUNCTION_TYPE)s;
|
||||||
|
symbolNext[s] = 1;
|
||||||
|
} else {
|
||||||
|
if (normalizedCounter[s] >= largeLimit) DTableH.fastMode=0;
|
||||||
|
symbolNext[s] = normalizedCounter[s];
|
||||||
|
} } }
|
||||||
|
ZSTD_memcpy(dt, &DTableH, sizeof(DTableH));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Spread symbols */
|
||||||
|
if (highThreshold == tableSize - 1) {
|
||||||
|
size_t const tableMask = tableSize-1;
|
||||||
|
size_t const step = FSE_TABLESTEP(tableSize);
|
||||||
|
/* First lay down the symbols in order.
|
||||||
|
* We use a uint64_t to lay down 8 bytes at a time. This reduces branch
|
||||||
|
* misses since small blocks generally have small table logs, so nearly
|
||||||
|
* all symbols have counts <= 8. We ensure we have 8 bytes at the end of
|
||||||
|
* our buffer to handle the over-write.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
U64 const add = 0x0101010101010101ull;
|
||||||
|
size_t pos = 0;
|
||||||
|
U64 sv = 0;
|
||||||
|
U32 s;
|
||||||
|
for (s=0; s<maxSV1; ++s, sv += add) {
|
||||||
|
int i;
|
||||||
|
int const n = normalizedCounter[s];
|
||||||
|
MEM_write64(spread + pos, sv);
|
||||||
|
for (i = 8; i < n; i += 8) {
|
||||||
|
MEM_write64(spread + pos + i, sv);
|
||||||
|
}
|
||||||
|
pos += n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Now we spread those positions across the table.
|
||||||
|
* The benefit of doing it in two stages is that we avoid the the
|
||||||
|
* variable size inner loop, which caused lots of branch misses.
|
||||||
|
* Now we can run through all the positions without any branch misses.
|
||||||
|
* We unroll the loop twice, since that is what emperically worked best.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
size_t position = 0;
|
||||||
|
size_t s;
|
||||||
|
size_t const unroll = 2;
|
||||||
|
assert(tableSize % unroll == 0); /* FSE_MIN_TABLELOG is 5 */
|
||||||
|
for (s = 0; s < (size_t)tableSize; s += unroll) {
|
||||||
|
size_t u;
|
||||||
|
for (u = 0; u < unroll; ++u) {
|
||||||
|
size_t const uPosition = (position + (u * step)) & tableMask;
|
||||||
|
tableDecode[uPosition].symbol = spread[s + u];
|
||||||
|
}
|
||||||
|
position = (position + (unroll * step)) & tableMask;
|
||||||
|
}
|
||||||
|
assert(position == 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
U32 const tableMask = tableSize-1;
|
||||||
|
U32 const step = FSE_TABLESTEP(tableSize);
|
||||||
|
U32 s, position = 0;
|
||||||
|
for (s=0; s<maxSV1; s++) {
|
||||||
|
int i;
|
||||||
|
for (i=0; i<normalizedCounter[s]; i++) {
|
||||||
|
tableDecode[position].symbol = (FSE_FUNCTION_TYPE)s;
|
||||||
|
position = (position + step) & tableMask;
|
||||||
|
while (position > 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; u<tableSize; u++) {
|
||||||
|
FSE_FUNCTION_TYPE const symbol = (FSE_FUNCTION_TYPE)(tableDecode[u].symbol);
|
||||||
|
U32 const nextState = symbolNext[symbol]++;
|
||||||
|
tableDecode[u].nbBits = (BYTE) (tableLog - BIT_highbit32(nextState) );
|
||||||
|
tableDecode[u].newState = (U16) ( (nextState << tableDecode[u].nbBits) - tableSize);
|
||||||
|
} }
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t FSE_buildDTable_wksp(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize)
|
||||||
|
{
|
||||||
|
return FSE_buildDTable_internal(dt, normalizedCounter, maxSymbolValue, tableLog, workSpace, wkspSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FSE_COMMONDEFS_ONLY
|
||||||
|
|
||||||
|
/*-*******************************************************
|
||||||
|
* Decompression (Byte symbols)
|
||||||
|
*********************************************************/
|
||||||
|
size_t FSE_buildDTable_rle (FSE_DTable* dt, BYTE symbolValue)
|
||||||
|
{
|
||||||
|
void* ptr = dt;
|
||||||
|
FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr;
|
||||||
|
void* dPtr = dt + 1;
|
||||||
|
FSE_decode_t* const cell = (FSE_decode_t*)dPtr;
|
||||||
|
|
||||||
|
DTableH->tableLog = 0;
|
||||||
|
DTableH->fastMode = 0;
|
||||||
|
|
||||||
|
cell->newState = 0;
|
||||||
|
cell->symbol = symbolValue;
|
||||||
|
cell->nbBits = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits)
|
||||||
|
{
|
||||||
|
void* ptr = dt;
|
||||||
|
FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr;
|
||||||
|
void* dPtr = dt + 1;
|
||||||
|
FSE_decode_t* const dinfo = (FSE_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<maxSV1; s++) {
|
||||||
|
dinfo[s].newState = 0;
|
||||||
|
dinfo[s].symbol = (BYTE)s;
|
||||||
|
dinfo[s].nbBits = (BYTE)nbBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE_TEMPLATE size_t FSE_decompress_usingDTable_generic(
|
||||||
|
void* dst, size_t maxDstSize,
|
||||||
|
const void* cSrc, size_t cSrcSize,
|
||||||
|
const FSE_DTable* dt, const unsigned fast)
|
||||||
|
{
|
||||||
|
BYTE* const ostart = (BYTE*) dst;
|
||||||
|
BYTE* op = ostart;
|
||||||
|
BYTE* const omax = op + maxDstSize;
|
||||||
|
BYTE* const olimit = omax-3;
|
||||||
|
|
||||||
|
BIT_DStream_t bitD;
|
||||||
|
FSE_DState_t state1;
|
||||||
|
FSE_DState_t state2;
|
||||||
|
|
||||||
|
/* Init */
|
||||||
|
CHECK_F(BIT_initDStream(&bitD, cSrc, cSrcSize));
|
||||||
|
|
||||||
|
FSE_initDState(&state1, &bitD, dt);
|
||||||
|
FSE_initDState(&state2, &bitD, dt);
|
||||||
|
|
||||||
|
#define FSE_GETSYMBOL(statePtr) fast ? FSE_decodeSymbolFast(statePtr, &bitD) : FSE_decodeSymbol(statePtr, &bitD)
|
||||||
|
|
||||||
|
/* 4 symbols per loop */
|
||||||
|
for ( ; (BIT_reloadDStream(&bitD)==BIT_DStream_unfinished) & (op<olimit) ; op+=4) {
|
||||||
|
op[0] = FSE_GETSYMBOL(&state1);
|
||||||
|
|
||||||
|
if (FSE_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */
|
||||||
|
BIT_reloadDStream(&bitD);
|
||||||
|
|
||||||
|
op[1] = FSE_GETSYMBOL(&state2);
|
||||||
|
|
||||||
|
if (FSE_MAX_TABLELOG*4+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */
|
||||||
|
{ if (BIT_reloadDStream(&bitD) > BIT_DStream_unfinished) { op+=2; break; } }
|
||||||
|
|
||||||
|
op[2] = FSE_GETSYMBOL(&state1);
|
||||||
|
|
||||||
|
if (FSE_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */
|
||||||
|
BIT_reloadDStream(&bitD);
|
||||||
|
|
||||||
|
op[3] = FSE_GETSYMBOL(&state2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tail */
|
||||||
|
/* note : BIT_reloadDStream(&bitD) >= FSE_DStream_partiallyFilled; Ends at exactly BIT_DStream_completed */
|
||||||
|
while (1) {
|
||||||
|
if (op>(omax-2)) return ERROR(dstSize_tooSmall);
|
||||||
|
*op++ = FSE_GETSYMBOL(&state1);
|
||||||
|
if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) {
|
||||||
|
*op++ = FSE_GETSYMBOL(&state2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op>(omax-2)) return ERROR(dstSize_tooSmall);
|
||||||
|
*op++ = FSE_GETSYMBOL(&state2);
|
||||||
|
if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) {
|
||||||
|
*op++ = FSE_GETSYMBOL(&state1);
|
||||||
|
break;
|
||||||
|
} }
|
||||||
|
|
||||||
|
return op-ostart;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t FSE_decompress_usingDTable(void* dst, size_t originalSize,
|
||||||
|
const void* cSrc, size_t cSrcSize,
|
||||||
|
const FSE_DTable* dt)
|
||||||
|
{
|
||||||
|
const void* ptr = dt;
|
||||||
|
const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr;
|
||||||
|
const U32 fastMode = DTableH->fastMode;
|
||||||
|
|
||||||
|
/* select fast mode (static) */
|
||||||
|
if (fastMode) return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 1);
|
||||||
|
return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize)
|
||||||
|
{
|
||||||
|
return FSE_decompress_wksp_bmi2(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, /* bmi2 */ 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
short ncount[FSE_MAX_SYMBOL_VALUE + 1];
|
||||||
|
FSE_DTable dtable[1]; /* Dynamically sized */
|
||||||
|
} FSE_DecompressWksp;
|
||||||
|
|
||||||
|
|
||||||
|
FORCE_INLINE_TEMPLATE size_t FSE_decompress_wksp_body(
|
||||||
|
void* dst, size_t dstCapacity,
|
||||||
|
const void* cSrc, size_t cSrcSize,
|
||||||
|
unsigned maxLog, void* workSpace, size_t wkspSize,
|
||||||
|
int bmi2)
|
||||||
|
{
|
||||||
|
const BYTE* const istart = (const BYTE*)cSrc;
|
||||||
|
const BYTE* ip = istart;
|
||||||
|
unsigned tableLog;
|
||||||
|
unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE;
|
||||||
|
FSE_DecompressWksp* const wksp = (FSE_DecompressWksp*)workSpace;
|
||||||
|
|
||||||
|
DEBUG_STATIC_ASSERT((FSE_MAX_SYMBOL_VALUE + 1) % 2 == 0);
|
||||||
|
if (wkspSize < sizeof(*wksp)) return ERROR(GENERIC);
|
||||||
|
|
||||||
|
/* normal FSE decoding mode */
|
||||||
|
{
|
||||||
|
size_t const NCountLength = FSE_readNCount_bmi2(wksp->ncount, &maxSymbolValue, &tableLog, istart, cSrcSize, bmi2);
|
||||||
|
if (FSE_isError(NCountLength)) return NCountLength;
|
||||||
|
if (tableLog > maxLog) return ERROR(tableLog_tooLarge);
|
||||||
|
assert(NCountLength <= cSrcSize);
|
||||||
|
ip += NCountLength;
|
||||||
|
cSrcSize -= NCountLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FSE_DECOMPRESS_WKSP_SIZE(tableLog, maxSymbolValue) > wkspSize) return ERROR(tableLog_tooLarge);
|
||||||
|
workSpace = wksp->dtable + FSE_DTABLE_SIZE_U32(tableLog);
|
||||||
|
wkspSize -= sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog);
|
||||||
|
|
||||||
|
CHECK_F( FSE_buildDTable_internal(wksp->dtable, wksp->ncount, maxSymbolValue, tableLog, workSpace, wkspSize) );
|
||||||
|
|
||||||
|
{
|
||||||
|
const void* ptr = wksp->dtable;
|
||||||
|
const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr;
|
||||||
|
const U32 fastMode = DTableH->fastMode;
|
||||||
|
|
||||||
|
/* select fast mode (static) */
|
||||||
|
if (fastMode) return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, wksp->dtable, 1);
|
||||||
|
return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, wksp->dtable, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Avoids the FORCE_INLINE of the _body() function. */
|
||||||
|
static size_t FSE_decompress_wksp_body_default(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize)
|
||||||
|
{
|
||||||
|
return FSE_decompress_wksp_body(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DYNAMIC_BMI2
|
||||||
|
BMI2_TARGET_ATTRIBUTE static size_t FSE_decompress_wksp_body_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize)
|
||||||
|
{
|
||||||
|
return FSE_decompress_wksp_body(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, 1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
size_t FSE_decompress_wksp_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize, int bmi2)
|
||||||
|
{
|
||||||
|
#if DYNAMIC_BMI2
|
||||||
|
if (bmi2) {
|
||||||
|
return FSE_decompress_wksp_body_bmi2(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
(void)bmi2;
|
||||||
|
return FSE_decompress_wksp_body_default(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef FSE_DTable DTable_max_t[FSE_DTABLE_SIZE_U32(FSE_MAX_TABLELOG)];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* FSE_COMMONDEFS_ONLY */
|
358
lib/zstd/common/huf.h
Normal file
358
lib/zstd/common/huf.h
Normal file
|
@ -0,0 +1,358 @@
|
||||||
|
/* ******************************************************************
|
||||||
|
* huff0 huffman codec,
|
||||||
|
* part of Finite State Entropy library
|
||||||
|
* Copyright (c) Yann Collet, Facebook, Inc.
|
||||||
|
*
|
||||||
|
* You can contact the author at :
|
||||||
|
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
****************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef HUF_H_298734234
|
||||||
|
#define HUF_H_298734234
|
||||||
|
|
||||||
|
/* *** Dependencies *** */
|
||||||
|
#include "zstd_deps.h" /* size_t */
|
||||||
|
|
||||||
|
|
||||||
|
/* *** library symbols visibility *** */
|
||||||
|
/* Note : when linking with -fvisibility=hidden on gcc, or by default on Visual,
|
||||||
|
* HUF symbols remain "private" (internal symbols for library only).
|
||||||
|
* Set macro FSE_DLL_EXPORT to 1 if you want HUF symbols visible on DLL interface */
|
||||||
|
#if defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) && defined(__GNUC__) && (__GNUC__ >= 4)
|
||||||
|
# define HUF_PUBLIC_API __attribute__ ((visibility ("default")))
|
||||||
|
#elif defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) /* Visual expected */
|
||||||
|
# define HUF_PUBLIC_API __declspec(dllexport)
|
||||||
|
#elif defined(FSE_DLL_IMPORT) && (FSE_DLL_IMPORT==1)
|
||||||
|
# define HUF_PUBLIC_API __declspec(dllimport) /* not required, just to generate faster code (saves a function pointer load from IAT and an indirect jump) */
|
||||||
|
#else
|
||||||
|
# define HUF_PUBLIC_API
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* ========================== */
|
||||||
|
/* *** simple functions *** */
|
||||||
|
/* ========================== */
|
||||||
|
|
||||||
|
/* HUF_compress() :
|
||||||
|
* Compress content from buffer 'src', of size 'srcSize', into buffer 'dst'.
|
||||||
|
* 'dst' buffer must be already allocated.
|
||||||
|
* Compression runs faster if `dstCapacity` >= HUF_compressBound(srcSize).
|
||||||
|
* `srcSize` must be <= `HUF_BLOCKSIZE_MAX` == 128 KB.
|
||||||
|
* @return : size of compressed data (<= `dstCapacity`).
|
||||||
|
* Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!!
|
||||||
|
* if HUF_isError(return), compression failed (more details using HUF_getErrorName())
|
||||||
|
*/
|
||||||
|
HUF_PUBLIC_API size_t HUF_compress(void* dst, size_t dstCapacity,
|
||||||
|
const void* src, size_t srcSize);
|
||||||
|
|
||||||
|
/* HUF_decompress() :
|
||||||
|
* Decompress HUF data from buffer 'cSrc', of size 'cSrcSize',
|
||||||
|
* into already allocated buffer 'dst', of minimum size 'dstSize'.
|
||||||
|
* `originalSize` : **must** be the ***exact*** size of original (uncompressed) data.
|
||||||
|
* Note : in contrast with FSE, HUF_decompress can regenerate
|
||||||
|
* RLE (cSrcSize==1) and uncompressed (cSrcSize==dstSize) data,
|
||||||
|
* because it knows size to regenerate (originalSize).
|
||||||
|
* @return : size of regenerated data (== originalSize),
|
||||||
|
* or an error code, which can be tested using HUF_isError()
|
||||||
|
*/
|
||||||
|
HUF_PUBLIC_API size_t HUF_decompress(void* dst, size_t originalSize,
|
||||||
|
const void* cSrc, size_t cSrcSize);
|
||||||
|
|
||||||
|
|
||||||
|
/* *** Tool functions *** */
|
||||||
|
#define HUF_BLOCKSIZE_MAX (128 * 1024) /*< maximum input size for a single block compressed with HUF_compress */
|
||||||
|
HUF_PUBLIC_API size_t HUF_compressBound(size_t size); /*< maximum compressed size (worst case) */
|
||||||
|
|
||||||
|
/* Error Management */
|
||||||
|
HUF_PUBLIC_API unsigned HUF_isError(size_t code); /*< tells if a return value is an error code */
|
||||||
|
HUF_PUBLIC_API const char* HUF_getErrorName(size_t code); /*< provides error code string (useful for debugging) */
|
||||||
|
|
||||||
|
|
||||||
|
/* *** Advanced function *** */
|
||||||
|
|
||||||
|
/* HUF_compress2() :
|
||||||
|
* Same as HUF_compress(), but offers control over `maxSymbolValue` and `tableLog`.
|
||||||
|
* `maxSymbolValue` must be <= HUF_SYMBOLVALUE_MAX .
|
||||||
|
* `tableLog` must be `<= HUF_TABLELOG_MAX` . */
|
||||||
|
HUF_PUBLIC_API size_t HUF_compress2 (void* dst, size_t dstCapacity,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
unsigned maxSymbolValue, unsigned tableLog);
|
||||||
|
|
||||||
|
/* HUF_compress4X_wksp() :
|
||||||
|
* Same as HUF_compress2(), but uses externally allocated `workSpace`.
|
||||||
|
* `workspace` must be at least as large as HUF_WORKSPACE_SIZE */
|
||||||
|
#define HUF_WORKSPACE_SIZE ((8 << 10) + 512 /* sorting scratch space */)
|
||||||
|
#define HUF_WORKSPACE_SIZE_U64 (HUF_WORKSPACE_SIZE / sizeof(U64))
|
||||||
|
HUF_PUBLIC_API size_t HUF_compress4X_wksp (void* dst, size_t dstCapacity,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
unsigned maxSymbolValue, unsigned tableLog,
|
||||||
|
void* workSpace, size_t wkspSize);
|
||||||
|
|
||||||
|
#endif /* HUF_H_298734234 */
|
||||||
|
|
||||||
|
/* ******************************************************************
|
||||||
|
* WARNING !!
|
||||||
|
* The following section contains advanced and experimental definitions
|
||||||
|
* which shall never be used in the context of a dynamic library,
|
||||||
|
* because they are not guaranteed to remain stable in the future.
|
||||||
|
* Only consider them in association with static linking.
|
||||||
|
* *****************************************************************/
|
||||||
|
#if !defined(HUF_H_HUF_STATIC_LINKING_ONLY)
|
||||||
|
#define HUF_H_HUF_STATIC_LINKING_ONLY
|
||||||
|
|
||||||
|
/* *** Dependencies *** */
|
||||||
|
#include "mem.h" /* U32 */
|
||||||
|
#define FSE_STATIC_LINKING_ONLY
|
||||||
|
#include "fse.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* *** Constants *** */
|
||||||
|
#define HUF_TABLELOG_MAX 12 /* max runtime value of tableLog (due to static allocation); can be modified up to HUF_TABLELOG_ABSOLUTEMAX */
|
||||||
|
#define HUF_TABLELOG_DEFAULT 11 /* default tableLog value when none specified */
|
||||||
|
#define HUF_SYMBOLVALUE_MAX 255
|
||||||
|
|
||||||
|
#define HUF_TABLELOG_ABSOLUTEMAX 12 /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */
|
||||||
|
#if (HUF_TABLELOG_MAX > HUF_TABLELOG_ABSOLUTEMAX)
|
||||||
|
# error "HUF_TABLELOG_MAX is too large !"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* ****************************************
|
||||||
|
* Static allocation
|
||||||
|
******************************************/
|
||||||
|
/* HUF buffer bounds */
|
||||||
|
#define HUF_CTABLEBOUND 129
|
||||||
|
#define HUF_BLOCKBOUND(size) (size + (size>>8) + 8) /* only true when incompressible is pre-filtered with fast heuristic */
|
||||||
|
#define HUF_COMPRESSBOUND(size) (HUF_CTABLEBOUND + HUF_BLOCKBOUND(size)) /* Macro version, useful for static allocation */
|
||||||
|
|
||||||
|
/* static allocation of HUF's Compression Table */
|
||||||
|
/* this is a private definition, just exposed for allocation and strict aliasing purpose. never EVER access its members directly */
|
||||||
|
typedef size_t HUF_CElt; /* consider it an incomplete type */
|
||||||
|
#define HUF_CTABLE_SIZE_ST(maxSymbolValue) ((maxSymbolValue)+2) /* Use tables of size_t, for proper alignment */
|
||||||
|
#define HUF_CTABLE_SIZE(maxSymbolValue) (HUF_CTABLE_SIZE_ST(maxSymbolValue) * sizeof(size_t))
|
||||||
|
#define HUF_CREATE_STATIC_CTABLE(name, maxSymbolValue) \
|
||||||
|
HUF_CElt name[HUF_CTABLE_SIZE_ST(maxSymbolValue)] /* no final ; */
|
||||||
|
|
||||||
|
/* static allocation of HUF's DTable */
|
||||||
|
typedef U32 HUF_DTable;
|
||||||
|
#define HUF_DTABLE_SIZE(maxTableLog) (1 + (1<<(maxTableLog)))
|
||||||
|
#define HUF_CREATE_STATIC_DTABLEX1(DTable, maxTableLog) \
|
||||||
|
HUF_DTable DTable[HUF_DTABLE_SIZE((maxTableLog)-1)] = { ((U32)((maxTableLog)-1) * 0x01000001) }
|
||||||
|
#define HUF_CREATE_STATIC_DTABLEX2(DTable, maxTableLog) \
|
||||||
|
HUF_DTable DTable[HUF_DTABLE_SIZE(maxTableLog)] = { ((U32)(maxTableLog) * 0x01000001) }
|
||||||
|
|
||||||
|
|
||||||
|
/* ****************************************
|
||||||
|
* Advanced decompression functions
|
||||||
|
******************************************/
|
||||||
|
size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /*< single-symbol decoder */
|
||||||
|
#ifndef HUF_FORCE_DECOMPRESS_X1
|
||||||
|
size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /*< double-symbols decoder */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /*< decodes RLE and uncompressed */
|
||||||
|
size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /*< considers RLE and uncompressed as errors */
|
||||||
|
size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /*< considers RLE and uncompressed as errors */
|
||||||
|
size_t HUF_decompress4X1_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /*< single-symbol decoder */
|
||||||
|
size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /*< single-symbol decoder */
|
||||||
|
#ifndef HUF_FORCE_DECOMPRESS_X1
|
||||||
|
size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /*< double-symbols decoder */
|
||||||
|
size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /*< double-symbols decoder */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* ****************************************
|
||||||
|
* HUF detailed API
|
||||||
|
* ****************************************/
|
||||||
|
|
||||||
|
/*! HUF_compress() does the following:
|
||||||
|
* 1. count symbol occurrence from source[] into table count[] using FSE_count() (exposed within "fse.h")
|
||||||
|
* 2. (optional) refine tableLog using HUF_optimalTableLog()
|
||||||
|
* 3. build Huffman table from count using HUF_buildCTable()
|
||||||
|
* 4. save Huffman table to memory buffer using HUF_writeCTable()
|
||||||
|
* 5. encode the data stream using HUF_compress4X_usingCTable()
|
||||||
|
*
|
||||||
|
* The following API allows targeting specific sub-functions for advanced tasks.
|
||||||
|
* For example, it's possible to compress several blocks using the same 'CTable',
|
||||||
|
* or to save and regenerate 'CTable' using external methods.
|
||||||
|
*/
|
||||||
|
unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue);
|
||||||
|
size_t HUF_buildCTable (HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits); /* @return : maxNbBits; CTable and count can overlap. In which case, CTable will overwrite count content */
|
||||||
|
size_t HUF_writeCTable (void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog);
|
||||||
|
size_t HUF_writeCTable_wksp(void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog, void* workspace, size_t workspaceSize);
|
||||||
|
size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable);
|
||||||
|
size_t HUF_compress4X_usingCTable_bmi2(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int bmi2);
|
||||||
|
size_t HUF_estimateCompressedSize(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue);
|
||||||
|
int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
HUF_repeat_none, /*< Cannot use the previous table */
|
||||||
|
HUF_repeat_check, /*< Can use the previous table but it must be checked. Note : The previous table must have been constructed by HUF_compress{1, 4}X_repeat */
|
||||||
|
HUF_repeat_valid /*< Can use the previous table and it is assumed to be valid */
|
||||||
|
} HUF_repeat;
|
||||||
|
/* HUF_compress4X_repeat() :
|
||||||
|
* Same as HUF_compress4X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none.
|
||||||
|
* If it uses hufTable it does not modify hufTable or repeat.
|
||||||
|
* If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
|
||||||
|
* If preferRepeat then the old table will always be used if valid.
|
||||||
|
* If suspectUncompressible then some sampling checks will be run to potentially skip huffman coding */
|
||||||
|
size_t HUF_compress4X_repeat(void* dst, size_t dstSize,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
unsigned maxSymbolValue, unsigned tableLog,
|
||||||
|
void* workSpace, size_t wkspSize, /*< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */
|
||||||
|
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2, unsigned suspectUncompressible);
|
||||||
|
|
||||||
|
/* HUF_buildCTable_wksp() :
|
||||||
|
* Same as HUF_buildCTable(), but using externally allocated scratch buffer.
|
||||||
|
* `workSpace` must be aligned on 4-bytes boundaries, and its size must be >= HUF_CTABLE_WORKSPACE_SIZE.
|
||||||
|
*/
|
||||||
|
#define HUF_CTABLE_WORKSPACE_SIZE_U32 (2*HUF_SYMBOLVALUE_MAX +1 +1)
|
||||||
|
#define HUF_CTABLE_WORKSPACE_SIZE (HUF_CTABLE_WORKSPACE_SIZE_U32 * sizeof(unsigned))
|
||||||
|
size_t HUF_buildCTable_wksp (HUF_CElt* tree,
|
||||||
|
const unsigned* count, U32 maxSymbolValue, U32 maxNbBits,
|
||||||
|
void* workSpace, size_t wkspSize);
|
||||||
|
|
||||||
|
/*! HUF_readStats() :
|
||||||
|
* Read compact Huffman tree, saved by HUF_writeCTable().
|
||||||
|
* `huffWeight` is destination buffer.
|
||||||
|
* @return : size read from `src` , or an error Code .
|
||||||
|
* Note : Needed by HUF_readCTable() and HUF_readDTableXn() . */
|
||||||
|
size_t HUF_readStats(BYTE* huffWeight, size_t hwSize,
|
||||||
|
U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr,
|
||||||
|
const void* src, size_t srcSize);
|
||||||
|
|
||||||
|
/*! HUF_readStats_wksp() :
|
||||||
|
* Same as HUF_readStats() but takes an external workspace which must be
|
||||||
|
* 4-byte aligned and its size must be >= HUF_READ_STATS_WORKSPACE_SIZE.
|
||||||
|
* If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0.
|
||||||
|
*/
|
||||||
|
#define HUF_READ_STATS_WORKSPACE_SIZE_U32 FSE_DECOMPRESS_WKSP_SIZE_U32(6, HUF_TABLELOG_MAX-1)
|
||||||
|
#define HUF_READ_STATS_WORKSPACE_SIZE (HUF_READ_STATS_WORKSPACE_SIZE_U32 * sizeof(unsigned))
|
||||||
|
size_t HUF_readStats_wksp(BYTE* huffWeight, size_t hwSize,
|
||||||
|
U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
void* workspace, size_t wkspSize,
|
||||||
|
int bmi2);
|
||||||
|
|
||||||
|
/* HUF_readCTable() :
|
||||||
|
* Loading a CTable saved with HUF_writeCTable() */
|
||||||
|
size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned *hasZeroWeights);
|
||||||
|
|
||||||
|
/* HUF_getNbBitsFromCTable() :
|
||||||
|
* Read nbBits from CTable symbolTable, for symbol `symbolValue` presumed <= HUF_SYMBOLVALUE_MAX
|
||||||
|
* Note 1 : is not inlined, as HUF_CElt definition is private */
|
||||||
|
U32 HUF_getNbBitsFromCTable(const HUF_CElt* symbolTable, U32 symbolValue);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* HUF_decompress() does the following:
|
||||||
|
* 1. select the decompression algorithm (X1, X2) based on pre-computed heuristics
|
||||||
|
* 2. build Huffman table from save, using HUF_readDTableX?()
|
||||||
|
* 3. decode 1 or 4 segments in parallel using HUF_decompress?X?_usingDTable()
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* HUF_selectDecoder() :
|
||||||
|
* Tells which decoder is likely to decode faster,
|
||||||
|
* based on a set of pre-computed metrics.
|
||||||
|
* @return : 0==HUF_decompress4X1, 1==HUF_decompress4X2 .
|
||||||
|
* Assumption : 0 < dstSize <= 128 KB */
|
||||||
|
U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The minimum workspace size for the `workSpace` used in
|
||||||
|
* HUF_readDTableX1_wksp() and HUF_readDTableX2_wksp().
|
||||||
|
*
|
||||||
|
* The space used depends on HUF_TABLELOG_MAX, ranging from ~1500 bytes when
|
||||||
|
* HUF_TABLE_LOG_MAX=12 to ~1850 bytes when HUF_TABLE_LOG_MAX=15.
|
||||||
|
* Buffer overflow errors may potentially occur if code modifications result in
|
||||||
|
* a required workspace size greater than that specified in the following
|
||||||
|
* macro.
|
||||||
|
*/
|
||||||
|
#define HUF_DECOMPRESS_WORKSPACE_SIZE ((2 << 10) + (1 << 9))
|
||||||
|
#define HUF_DECOMPRESS_WORKSPACE_SIZE_U32 (HUF_DECOMPRESS_WORKSPACE_SIZE / sizeof(U32))
|
||||||
|
|
||||||
|
#ifndef HUF_FORCE_DECOMPRESS_X2
|
||||||
|
size_t HUF_readDTableX1 (HUF_DTable* DTable, const void* src, size_t srcSize);
|
||||||
|
size_t HUF_readDTableX1_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize);
|
||||||
|
#endif
|
||||||
|
#ifndef HUF_FORCE_DECOMPRESS_X1
|
||||||
|
size_t HUF_readDTableX2 (HUF_DTable* DTable, const void* src, size_t srcSize);
|
||||||
|
size_t HUF_readDTableX2_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
|
||||||
|
#ifndef HUF_FORCE_DECOMPRESS_X2
|
||||||
|
size_t HUF_decompress4X1_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
|
||||||
|
#endif
|
||||||
|
#ifndef HUF_FORCE_DECOMPRESS_X1
|
||||||
|
size_t HUF_decompress4X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* ====================== */
|
||||||
|
/* single stream variants */
|
||||||
|
/* ====================== */
|
||||||
|
|
||||||
|
size_t HUF_compress1X (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog);
|
||||||
|
size_t HUF_compress1X_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); /*< `workSpace` must be a table of at least HUF_WORKSPACE_SIZE_U64 U64 */
|
||||||
|
size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable);
|
||||||
|
size_t HUF_compress1X_usingCTable_bmi2(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int bmi2);
|
||||||
|
/* HUF_compress1X_repeat() :
|
||||||
|
* Same as HUF_compress1X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none.
|
||||||
|
* If it uses hufTable it does not modify hufTable or repeat.
|
||||||
|
* If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
|
||||||
|
* If preferRepeat then the old table will always be used if valid.
|
||||||
|
* If suspectUncompressible then some sampling checks will be run to potentially skip huffman coding */
|
||||||
|
size_t HUF_compress1X_repeat(void* dst, size_t dstSize,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
unsigned maxSymbolValue, unsigned tableLog,
|
||||||
|
void* workSpace, size_t wkspSize, /*< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */
|
||||||
|
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2, unsigned suspectUncompressible);
|
||||||
|
|
||||||
|
size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* single-symbol decoder */
|
||||||
|
#ifndef HUF_FORCE_DECOMPRESS_X1
|
||||||
|
size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* double-symbol decoder */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
size_t HUF_decompress1X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);
|
||||||
|
size_t HUF_decompress1X_DCtx_wksp (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize);
|
||||||
|
#ifndef HUF_FORCE_DECOMPRESS_X2
|
||||||
|
size_t HUF_decompress1X1_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /*< single-symbol decoder */
|
||||||
|
size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /*< single-symbol decoder */
|
||||||
|
#endif
|
||||||
|
#ifndef HUF_FORCE_DECOMPRESS_X1
|
||||||
|
size_t HUF_decompress1X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /*< double-symbols decoder */
|
||||||
|
size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /*< double-symbols decoder */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); /*< automatic selection of sing or double symbol decoder, based on DTable */
|
||||||
|
#ifndef HUF_FORCE_DECOMPRESS_X2
|
||||||
|
size_t HUF_decompress1X1_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
|
||||||
|
#endif
|
||||||
|
#ifndef HUF_FORCE_DECOMPRESS_X1
|
||||||
|
size_t HUF_decompress1X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* BMI2 variants.
|
||||||
|
* If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0.
|
||||||
|
*/
|
||||||
|
size_t HUF_decompress1X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2);
|
||||||
|
#ifndef HUF_FORCE_DECOMPRESS_X2
|
||||||
|
size_t HUF_decompress1X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2);
|
||||||
|
#endif
|
||||||
|
size_t HUF_decompress4X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2);
|
||||||
|
size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2);
|
||||||
|
#ifndef HUF_FORCE_DECOMPRESS_X2
|
||||||
|
size_t HUF_readDTableX1_wksp_bmi2(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int bmi2);
|
||||||
|
#endif
|
||||||
|
#ifndef HUF_FORCE_DECOMPRESS_X1
|
||||||
|
size_t HUF_readDTableX2_wksp_bmi2(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int bmi2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* HUF_STATIC_LINKING_ONLY */
|
||||||
|
|
262
lib/zstd/common/mem.h
Normal file
262
lib/zstd/common/mem.h
Normal file
|
@ -0,0 +1,262 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
|
/*
|
||||||
|
* Copyright (c) Yann Collet, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MEM_H_MODULE
|
||||||
|
#define MEM_H_MODULE
|
||||||
|
|
||||||
|
/*-****************************************
|
||||||
|
* Dependencies
|
||||||
|
******************************************/
|
||||||
|
#include <asm/unaligned.h> /* get_unaligned, put_unaligned* */
|
||||||
|
#include <linux/compiler.h> /* inline */
|
||||||
|
#include <asm/byteorder.h> /* swab32, swab64 */
|
||||||
|
#include <linux/types.h> /* size_t, ptrdiff_t */
|
||||||
|
#include "debug.h" /* DEBUG_STATIC_ASSERT */
|
||||||
|
#include "compiler.h" /* INLINE_KEYWORD, UNUSED_ATTR */
|
||||||
|
|
||||||
|
/*-****************************************
|
||||||
|
* Compiler specifics
|
||||||
|
******************************************/
|
||||||
|
#define MEM_STATIC static INLINE_KEYWORD UNUSED_ATTR
|
||||||
|
|
||||||
|
/*-**************************************************************
|
||||||
|
* Basic Types
|
||||||
|
*****************************************************************/
|
||||||
|
typedef uint8_t BYTE;
|
||||||
|
typedef uint8_t U8;
|
||||||
|
typedef int8_t S8;
|
||||||
|
typedef uint16_t U16;
|
||||||
|
typedef int16_t S16;
|
||||||
|
typedef uint32_t U32;
|
||||||
|
typedef int32_t S32;
|
||||||
|
typedef uint64_t U64;
|
||||||
|
typedef int64_t S64;
|
||||||
|
|
||||||
|
/*-**************************************************************
|
||||||
|
* Memory I/O API
|
||||||
|
*****************************************************************/
|
||||||
|
/*=== Static platform detection ===*/
|
||||||
|
MEM_STATIC unsigned MEM_32bits(void);
|
||||||
|
MEM_STATIC unsigned MEM_64bits(void);
|
||||||
|
MEM_STATIC unsigned MEM_isLittleEndian(void);
|
||||||
|
|
||||||
|
/*=== Native unaligned read/write ===*/
|
||||||
|
MEM_STATIC U16 MEM_read16(const void* memPtr);
|
||||||
|
MEM_STATIC U32 MEM_read32(const void* memPtr);
|
||||||
|
MEM_STATIC U64 MEM_read64(const void* memPtr);
|
||||||
|
MEM_STATIC size_t MEM_readST(const void* memPtr);
|
||||||
|
|
||||||
|
MEM_STATIC void MEM_write16(void* memPtr, U16 value);
|
||||||
|
MEM_STATIC void MEM_write32(void* memPtr, U32 value);
|
||||||
|
MEM_STATIC void MEM_write64(void* memPtr, U64 value);
|
||||||
|
|
||||||
|
/*=== Little endian unaligned read/write ===*/
|
||||||
|
MEM_STATIC U16 MEM_readLE16(const void* memPtr);
|
||||||
|
MEM_STATIC U32 MEM_readLE24(const void* memPtr);
|
||||||
|
MEM_STATIC U32 MEM_readLE32(const void* memPtr);
|
||||||
|
MEM_STATIC U64 MEM_readLE64(const void* memPtr);
|
||||||
|
MEM_STATIC size_t MEM_readLEST(const void* memPtr);
|
||||||
|
|
||||||
|
MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val);
|
||||||
|
MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val);
|
||||||
|
MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32);
|
||||||
|
MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64);
|
||||||
|
MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val);
|
||||||
|
|
||||||
|
/*=== Big endian unaligned read/write ===*/
|
||||||
|
MEM_STATIC U32 MEM_readBE32(const void* memPtr);
|
||||||
|
MEM_STATIC U64 MEM_readBE64(const void* memPtr);
|
||||||
|
MEM_STATIC size_t MEM_readBEST(const void* memPtr);
|
||||||
|
|
||||||
|
MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32);
|
||||||
|
MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64);
|
||||||
|
MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val);
|
||||||
|
|
||||||
|
/*=== Byteswap ===*/
|
||||||
|
MEM_STATIC U32 MEM_swap32(U32 in);
|
||||||
|
MEM_STATIC U64 MEM_swap64(U64 in);
|
||||||
|
MEM_STATIC size_t MEM_swapST(size_t in);
|
||||||
|
|
||||||
|
/*-**************************************************************
|
||||||
|
* Memory I/O Implementation
|
||||||
|
*****************************************************************/
|
||||||
|
MEM_STATIC unsigned MEM_32bits(void)
|
||||||
|
{
|
||||||
|
return sizeof(size_t) == 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC unsigned MEM_64bits(void)
|
||||||
|
{
|
||||||
|
return sizeof(size_t) == 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__LITTLE_ENDIAN)
|
||||||
|
#define MEM_LITTLE_ENDIAN 1
|
||||||
|
#else
|
||||||
|
#define MEM_LITTLE_ENDIAN 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MEM_STATIC unsigned MEM_isLittleEndian(void)
|
||||||
|
{
|
||||||
|
return MEM_LITTLE_ENDIAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC U16 MEM_read16(const void *memPtr)
|
||||||
|
{
|
||||||
|
return get_unaligned((const U16 *)memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC U32 MEM_read32(const void *memPtr)
|
||||||
|
{
|
||||||
|
return get_unaligned((const U32 *)memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC U64 MEM_read64(const void *memPtr)
|
||||||
|
{
|
||||||
|
return get_unaligned((const U64 *)memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC size_t MEM_readST(const void *memPtr)
|
||||||
|
{
|
||||||
|
return get_unaligned((const size_t *)memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void MEM_write16(void *memPtr, U16 value)
|
||||||
|
{
|
||||||
|
put_unaligned(value, (U16 *)memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void MEM_write32(void *memPtr, U32 value)
|
||||||
|
{
|
||||||
|
put_unaligned(value, (U32 *)memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void MEM_write64(void *memPtr, U64 value)
|
||||||
|
{
|
||||||
|
put_unaligned(value, (U64 *)memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*=== Little endian r/w ===*/
|
||||||
|
|
||||||
|
MEM_STATIC U16 MEM_readLE16(const void *memPtr)
|
||||||
|
{
|
||||||
|
return get_unaligned_le16(memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void MEM_writeLE16(void *memPtr, U16 val)
|
||||||
|
{
|
||||||
|
put_unaligned_le16(val, memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC U32 MEM_readLE24(const void *memPtr)
|
||||||
|
{
|
||||||
|
return MEM_readLE16(memPtr) + (((const BYTE *)memPtr)[2] << 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void MEM_writeLE24(void *memPtr, U32 val)
|
||||||
|
{
|
||||||
|
MEM_writeLE16(memPtr, (U16)val);
|
||||||
|
((BYTE *)memPtr)[2] = (BYTE)(val >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC U32 MEM_readLE32(const void *memPtr)
|
||||||
|
{
|
||||||
|
return get_unaligned_le32(memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void MEM_writeLE32(void *memPtr, U32 val32)
|
||||||
|
{
|
||||||
|
put_unaligned_le32(val32, memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC U64 MEM_readLE64(const void *memPtr)
|
||||||
|
{
|
||||||
|
return get_unaligned_le64(memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void MEM_writeLE64(void *memPtr, U64 val64)
|
||||||
|
{
|
||||||
|
put_unaligned_le64(val64, 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void MEM_writeLEST(void *memPtr, size_t val)
|
||||||
|
{
|
||||||
|
if (MEM_32bits())
|
||||||
|
MEM_writeLE32(memPtr, (U32)val);
|
||||||
|
else
|
||||||
|
MEM_writeLE64(memPtr, (U64)val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*=== Big endian r/w ===*/
|
||||||
|
|
||||||
|
MEM_STATIC U32 MEM_readBE32(const void *memPtr)
|
||||||
|
{
|
||||||
|
return get_unaligned_be32(memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void MEM_writeBE32(void *memPtr, U32 val32)
|
||||||
|
{
|
||||||
|
put_unaligned_be32(val32, memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC U64 MEM_readBE64(const void *memPtr)
|
||||||
|
{
|
||||||
|
return get_unaligned_be64(memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void MEM_writeBE64(void *memPtr, U64 val64)
|
||||||
|
{
|
||||||
|
put_unaligned_be64(val64, memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC size_t MEM_readBEST(const void *memPtr)
|
||||||
|
{
|
||||||
|
if (MEM_32bits())
|
||||||
|
return (size_t)MEM_readBE32(memPtr);
|
||||||
|
else
|
||||||
|
return (size_t)MEM_readBE64(memPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC void MEM_writeBEST(void *memPtr, size_t val)
|
||||||
|
{
|
||||||
|
if (MEM_32bits())
|
||||||
|
MEM_writeBE32(memPtr, (U32)val);
|
||||||
|
else
|
||||||
|
MEM_writeBE64(memPtr, (U64)val);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC U32 MEM_swap32(U32 in)
|
||||||
|
{
|
||||||
|
return swab32(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC U64 MEM_swap64(U64 in)
|
||||||
|
{
|
||||||
|
return swab64(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC size_t MEM_swapST(size_t in)
|
||||||
|
{
|
||||||
|
if (MEM_32bits())
|
||||||
|
return (size_t)MEM_swap32((U32)in);
|
||||||
|
else
|
||||||
|
return (size_t)MEM_swap64((U64)in);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* MEM_H_MODULE */
|
93
lib/zstd/common/portability_macros.h
Normal file
93
lib/zstd/common/portability_macros.h
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZSTD_PORTABILITY_MACROS_H
|
||||||
|
#define ZSTD_PORTABILITY_MACROS_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This header file contains macro defintions to support portability.
|
||||||
|
* This header is shared between C and ASM code, so it MUST only
|
||||||
|
* contain macro definitions. It MUST not contain any C code.
|
||||||
|
*
|
||||||
|
* This header ONLY defines macros to detect platforms/feature support.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* compat. with non-clang compilers */
|
||||||
|
#ifndef __has_attribute
|
||||||
|
#define __has_attribute(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* compat. with non-clang compilers */
|
||||||
|
#ifndef __has_builtin
|
||||||
|
# define __has_builtin(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* compat. with non-clang compilers */
|
||||||
|
#ifndef __has_feature
|
||||||
|
# define __has_feature(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* detects whether we are being compiled under msan */
|
||||||
|
|
||||||
|
/* detects whether we are being compiled under asan */
|
||||||
|
|
||||||
|
/* detects whether we are being compiled under dfsan */
|
||||||
|
|
||||||
|
/* Mark the internal assembly functions as hidden */
|
||||||
|
#ifdef __ELF__
|
||||||
|
# define ZSTD_HIDE_ASM_FUNCTION(func) .hidden func
|
||||||
|
#else
|
||||||
|
# define ZSTD_HIDE_ASM_FUNCTION(func)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Enable runtime BMI2 dispatch based on the CPU.
|
||||||
|
* Enabled for clang & gcc >=4.8 on x86 when BMI2 isn't enabled by default.
|
||||||
|
*/
|
||||||
|
#ifndef DYNAMIC_BMI2
|
||||||
|
#if ((defined(__clang__) && __has_attribute(__target__)) \
|
||||||
|
|| (defined(__GNUC__) \
|
||||||
|
&& (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))) \
|
||||||
|
&& (defined(__x86_64__) || defined(_M_X64)) \
|
||||||
|
&& !defined(__BMI2__)
|
||||||
|
# define DYNAMIC_BMI2 1
|
||||||
|
#else
|
||||||
|
# define DYNAMIC_BMI2 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only enable assembly for GNUC comptabile compilers,
|
||||||
|
* because other platforms may not support GAS assembly syntax.
|
||||||
|
*
|
||||||
|
* Only enable assembly for Linux / MacOS, other platforms may
|
||||||
|
* work, but they haven't been tested. This could likely be
|
||||||
|
* extended to BSD systems.
|
||||||
|
*
|
||||||
|
* Disable assembly when MSAN is enabled, because MSAN requires
|
||||||
|
* 100% of code to be instrumented to work.
|
||||||
|
*/
|
||||||
|
#define ZSTD_ASM_SUPPORTED 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determines whether we should enable assembly for x86-64
|
||||||
|
* with BMI2.
|
||||||
|
*
|
||||||
|
* Enable if all of the following conditions hold:
|
||||||
|
* - ASM hasn't been explicitly disabled by defining ZSTD_DISABLE_ASM
|
||||||
|
* - Assembly is supported
|
||||||
|
* - We are compiling for x86-64 and either:
|
||||||
|
* - DYNAMIC_BMI2 is enabled
|
||||||
|
* - BMI2 is supported at compile time
|
||||||
|
*/
|
||||||
|
#define ZSTD_ENABLE_ASM_X86_64_BMI2 0
|
||||||
|
|
||||||
|
#endif /* ZSTD_PORTABILITY_MACROS_H */
|
83
lib/zstd/common/zstd_common.c
Normal file
83
lib/zstd/common/zstd_common.c
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Yann Collet, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-*************************************
|
||||||
|
* Dependencies
|
||||||
|
***************************************/
|
||||||
|
#define ZSTD_DEPS_NEED_MALLOC
|
||||||
|
#include "zstd_deps.h" /* ZSTD_malloc, ZSTD_calloc, ZSTD_free, ZSTD_memset */
|
||||||
|
#include "error_private.h"
|
||||||
|
#include "zstd_internal.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*-****************************************
|
||||||
|
* Version
|
||||||
|
******************************************/
|
||||||
|
unsigned ZSTD_versionNumber(void) { return ZSTD_VERSION_NUMBER; }
|
||||||
|
|
||||||
|
const char* ZSTD_versionString(void) { return ZSTD_VERSION_STRING; }
|
||||||
|
|
||||||
|
|
||||||
|
/*-****************************************
|
||||||
|
* ZSTD Error Management
|
||||||
|
******************************************/
|
||||||
|
#undef ZSTD_isError /* defined within zstd_internal.h */
|
||||||
|
/*! ZSTD_isError() :
|
||||||
|
* tells if a return value is an error code
|
||||||
|
* symbol is required for external callers */
|
||||||
|
unsigned ZSTD_isError(size_t code) { return ERR_isError(code); }
|
||||||
|
|
||||||
|
/*! ZSTD_getErrorName() :
|
||||||
|
* provides error code string from function result (useful for debugging) */
|
||||||
|
const char* ZSTD_getErrorName(size_t code) { return ERR_getErrorName(code); }
|
||||||
|
|
||||||
|
/*! ZSTD_getError() :
|
||||||
|
* convert a `size_t` function result into a proper ZSTD_errorCode enum */
|
||||||
|
ZSTD_ErrorCode ZSTD_getErrorCode(size_t code) { return ERR_getErrorCode(code); }
|
||||||
|
|
||||||
|
/*! ZSTD_getErrorString() :
|
||||||
|
* provides error code string from enum */
|
||||||
|
const char* ZSTD_getErrorString(ZSTD_ErrorCode code) { return ERR_getErrorString(code); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*=**************************************************************
|
||||||
|
* Custom allocator
|
||||||
|
****************************************************************/
|
||||||
|
void* ZSTD_customMalloc(size_t size, ZSTD_customMem customMem)
|
||||||
|
{
|
||||||
|
if (customMem.customAlloc)
|
||||||
|
return customMem.customAlloc(customMem.opaque, size);
|
||||||
|
return ZSTD_malloc(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* ZSTD_customCalloc(size_t size, ZSTD_customMem customMem)
|
||||||
|
{
|
||||||
|
if (customMem.customAlloc) {
|
||||||
|
/* calloc implemented as malloc+memset;
|
||||||
|
* not as efficient as calloc, but next best guess for custom malloc */
|
||||||
|
void* const ptr = customMem.customAlloc(customMem.opaque, size);
|
||||||
|
ZSTD_memset(ptr, 0, size);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
return ZSTD_calloc(1, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZSTD_customFree(void* ptr, ZSTD_customMem customMem)
|
||||||
|
{
|
||||||
|
if (ptr!=NULL) {
|
||||||
|
if (customMem.customFree)
|
||||||
|
customMem.customFree(customMem.opaque, ptr);
|
||||||
|
else
|
||||||
|
ZSTD_free(ptr);
|
||||||
|
}
|
||||||
|
}
|
125
lib/zstd/common/zstd_deps.h
Normal file
125
lib/zstd/common/zstd_deps.h
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file provides common libc dependencies that zstd requires.
|
||||||
|
* The purpose is to allow replacing this file with a custom implementation
|
||||||
|
* to compile zstd without libc support.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Need:
|
||||||
|
* NULL
|
||||||
|
* INT_MAX
|
||||||
|
* UINT_MAX
|
||||||
|
* ZSTD_memcpy()
|
||||||
|
* ZSTD_memset()
|
||||||
|
* ZSTD_memmove()
|
||||||
|
*/
|
||||||
|
#ifndef ZSTD_DEPS_COMMON
|
||||||
|
#define ZSTD_DEPS_COMMON
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/stddef.h>
|
||||||
|
|
||||||
|
#define ZSTD_memcpy(d,s,n) __builtin_memcpy((d),(s),(n))
|
||||||
|
#define ZSTD_memmove(d,s,n) __builtin_memmove((d),(s),(n))
|
||||||
|
#define ZSTD_memset(d,s,n) __builtin_memset((d),(s),(n))
|
||||||
|
|
||||||
|
#endif /* ZSTD_DEPS_COMMON */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Define malloc as always failing. That means the user must
|
||||||
|
* either use ZSTD_customMem or statically allocate memory.
|
||||||
|
* Need:
|
||||||
|
* ZSTD_malloc()
|
||||||
|
* ZSTD_free()
|
||||||
|
* ZSTD_calloc()
|
||||||
|
*/
|
||||||
|
#ifdef ZSTD_DEPS_NEED_MALLOC
|
||||||
|
#ifndef ZSTD_DEPS_MALLOC
|
||||||
|
#define ZSTD_DEPS_MALLOC
|
||||||
|
|
||||||
|
#define ZSTD_malloc(s) ({ (void)(s); NULL; })
|
||||||
|
#define ZSTD_free(p) ((void)(p))
|
||||||
|
#define ZSTD_calloc(n,s) ({ (void)(n); (void)(s); NULL; })
|
||||||
|
|
||||||
|
#endif /* ZSTD_DEPS_MALLOC */
|
||||||
|
#endif /* ZSTD_DEPS_NEED_MALLOC */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Provides 64-bit math support.
|
||||||
|
* Need:
|
||||||
|
* U64 ZSTD_div64(U64 dividend, U32 divisor)
|
||||||
|
*/
|
||||||
|
#ifdef ZSTD_DEPS_NEED_MATH64
|
||||||
|
#ifndef ZSTD_DEPS_MATH64
|
||||||
|
#define ZSTD_DEPS_MATH64
|
||||||
|
|
||||||
|
#include <linux/math64.h>
|
||||||
|
|
||||||
|
static uint64_t ZSTD_div64(uint64_t dividend, uint32_t divisor) {
|
||||||
|
return div_u64(dividend, divisor);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ZSTD_DEPS_MATH64 */
|
||||||
|
#endif /* ZSTD_DEPS_NEED_MATH64 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is only requested when DEBUGLEVEL >= 1, meaning
|
||||||
|
* it is disabled in production.
|
||||||
|
* Need:
|
||||||
|
* assert()
|
||||||
|
*/
|
||||||
|
#ifdef ZSTD_DEPS_NEED_ASSERT
|
||||||
|
#ifndef ZSTD_DEPS_ASSERT
|
||||||
|
#define ZSTD_DEPS_ASSERT
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
|
||||||
|
#define assert(x) WARN_ON((x))
|
||||||
|
|
||||||
|
#endif /* ZSTD_DEPS_ASSERT */
|
||||||
|
#endif /* ZSTD_DEPS_NEED_ASSERT */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is only requested when DEBUGLEVEL >= 2, meaning
|
||||||
|
* it is disabled in production.
|
||||||
|
* Need:
|
||||||
|
* ZSTD_DEBUG_PRINT()
|
||||||
|
*/
|
||||||
|
#ifdef ZSTD_DEPS_NEED_IO
|
||||||
|
#ifndef ZSTD_DEPS_IO
|
||||||
|
#define ZSTD_DEPS_IO
|
||||||
|
|
||||||
|
#include <linux/printk.h>
|
||||||
|
|
||||||
|
#define ZSTD_DEBUG_PRINT(...) pr_debug(__VA_ARGS__)
|
||||||
|
|
||||||
|
#endif /* ZSTD_DEPS_IO */
|
||||||
|
#endif /* ZSTD_DEPS_NEED_IO */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only requested when MSAN is enabled.
|
||||||
|
* Need:
|
||||||
|
* intptr_t
|
||||||
|
*/
|
||||||
|
#ifdef ZSTD_DEPS_NEED_STDINT
|
||||||
|
#ifndef ZSTD_DEPS_STDINT
|
||||||
|
#define ZSTD_DEPS_STDINT
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The Linux Kernel doesn't provide intptr_t, only uintptr_t, which
|
||||||
|
* is an unsigned long.
|
||||||
|
*/
|
||||||
|
typedef long intptr_t;
|
||||||
|
|
||||||
|
#endif /* ZSTD_DEPS_STDINT */
|
||||||
|
#endif /* ZSTD_DEPS_NEED_STDINT */
|
443
lib/zstd/common/zstd_internal.h
Normal file
443
lib/zstd/common/zstd_internal.h
Normal file
|
@ -0,0 +1,443 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Yann Collet, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZSTD_CCOMMON_H_MODULE
|
||||||
|
#define ZSTD_CCOMMON_H_MODULE
|
||||||
|
|
||||||
|
/* this module contains definitions which must be identical
|
||||||
|
* across compression, decompression and dictBuilder.
|
||||||
|
* It also contains a few functions useful to at least 2 of them
|
||||||
|
* and which benefit from being inlined */
|
||||||
|
|
||||||
|
/*-*************************************
|
||||||
|
* Dependencies
|
||||||
|
***************************************/
|
||||||
|
#include "compiler.h"
|
||||||
|
#include "cpu.h"
|
||||||
|
#include "mem.h"
|
||||||
|
#include "debug.h" /* assert, DEBUGLOG, RAWLOG, g_debuglevel */
|
||||||
|
#include "error_private.h"
|
||||||
|
#define ZSTD_STATIC_LINKING_ONLY
|
||||||
|
#include <linux/zstd.h>
|
||||||
|
#define FSE_STATIC_LINKING_ONLY
|
||||||
|
#include "fse.h"
|
||||||
|
#define HUF_STATIC_LINKING_ONLY
|
||||||
|
#include "huf.h"
|
||||||
|
#include <linux/xxhash.h> /* XXH_reset, update, digest */
|
||||||
|
#define ZSTD_TRACE 0
|
||||||
|
|
||||||
|
|
||||||
|
/* ---- static assert (debug) --- */
|
||||||
|
#define ZSTD_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c)
|
||||||
|
#define ZSTD_isError ERR_isError /* for inlining */
|
||||||
|
#define FSE_isError ERR_isError
|
||||||
|
#define HUF_isError ERR_isError
|
||||||
|
|
||||||
|
|
||||||
|
/*-*************************************
|
||||||
|
* shared macros
|
||||||
|
***************************************/
|
||||||
|
#undef MIN
|
||||||
|
#undef MAX
|
||||||
|
#define MIN(a,b) ((a)<(b) ? (a) : (b))
|
||||||
|
#define MAX(a,b) ((a)>(b) ? (a) : (b))
|
||||||
|
#define BOUNDED(min,val,max) (MAX(min,MIN(val,max)))
|
||||||
|
|
||||||
|
|
||||||
|
/*-*************************************
|
||||||
|
* Common constants
|
||||||
|
***************************************/
|
||||||
|
#define ZSTD_OPT_NUM (1<<12)
|
||||||
|
|
||||||
|
#define ZSTD_REP_NUM 3 /* number of repcodes */
|
||||||
|
static UNUSED_ATTR const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 };
|
||||||
|
|
||||||
|
#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 ZSTD_WINDOWLOG_ABSOLUTEMIN 10
|
||||||
|
static UNUSED_ATTR const size_t ZSTD_fcs_fieldSize[4] = { 0, 2, 4, 8 };
|
||||||
|
static UNUSED_ATTR const size_t ZSTD_did_fieldSize[4] = { 0, 1, 2, 4 };
|
||||||
|
|
||||||
|
#define ZSTD_FRAMEIDSIZE 4 /* magic number size */
|
||||||
|
|
||||||
|
#define ZSTD_BLOCKHEADERSIZE 3 /* C standard doesn't allow `static const` variable to be init using another `static const` variable */
|
||||||
|
static UNUSED_ATTR const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE;
|
||||||
|
typedef enum { bt_raw, bt_rle, bt_compressed, bt_reserved } blockType_e;
|
||||||
|
|
||||||
|
#define ZSTD_FRAMECHECKSUMSIZE 4
|
||||||
|
|
||||||
|
#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 HufLog 12
|
||||||
|
typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingType_e;
|
||||||
|
|
||||||
|
#define LONGNBSEQ 0x7F00
|
||||||
|
|
||||||
|
#define MINMATCH 3
|
||||||
|
|
||||||
|
#define Litbits 8
|
||||||
|
#define MaxLit ((1<<Litbits) - 1)
|
||||||
|
#define MaxML 52
|
||||||
|
#define MaxLL 35
|
||||||
|
#define DefaultMaxOff 28
|
||||||
|
#define MaxOff 31
|
||||||
|
#define MaxSeq MAX(MaxLL, MaxML) /* Assumption : MaxOff < MaxLL,MaxML */
|
||||||
|
#define MLFSELog 9
|
||||||
|
#define LLFSELog 9
|
||||||
|
#define OffFSELog 8
|
||||||
|
#define MaxFSELog MAX(MAX(MLFSELog, LLFSELog), OffFSELog)
|
||||||
|
|
||||||
|
#define ZSTD_MAX_HUF_HEADER_SIZE 128 /* header + <= 127 byte tree description */
|
||||||
|
/* Each table cannot take more than #symbols * FSELog bits */
|
||||||
|
#define ZSTD_MAX_FSE_HEADERS_SIZE (((MaxML + 1) * MLFSELog + (MaxLL + 1) * LLFSELog + (MaxOff + 1) * OffFSELog + 7) / 8)
|
||||||
|
|
||||||
|
static UNUSED_ATTR const U8 LL_bits[MaxLL+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
|
||||||
|
};
|
||||||
|
static UNUSED_ATTR const S16 LL_defaultNorm[MaxLL+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
|
||||||
|
};
|
||||||
|
#define LL_DEFAULTNORMLOG 6 /* for static allocation */
|
||||||
|
static UNUSED_ATTR const U32 LL_defaultNormLog = LL_DEFAULTNORMLOG;
|
||||||
|
|
||||||
|
static UNUSED_ATTR const U8 ML_bits[MaxML+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
|
||||||
|
};
|
||||||
|
static UNUSED_ATTR const S16 ML_defaultNorm[MaxML+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
|
||||||
|
};
|
||||||
|
#define ML_DEFAULTNORMLOG 6 /* for static allocation */
|
||||||
|
static UNUSED_ATTR const U32 ML_defaultNormLog = ML_DEFAULTNORMLOG;
|
||||||
|
|
||||||
|
static UNUSED_ATTR const S16 OF_defaultNorm[DefaultMaxOff+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
|
||||||
|
};
|
||||||
|
#define OF_DEFAULTNORMLOG 5 /* for static allocation */
|
||||||
|
static UNUSED_ATTR const U32 OF_defaultNormLog = OF_DEFAULTNORMLOG;
|
||||||
|
|
||||||
|
|
||||||
|
/*-*******************************************
|
||||||
|
* Shared functions to include for inlining
|
||||||
|
*********************************************/
|
||||||
|
static void ZSTD_copy8(void* dst, const void* src) {
|
||||||
|
#if defined(ZSTD_ARCH_ARM_NEON)
|
||||||
|
vst1_u8((uint8_t*)dst, vld1_u8((const uint8_t*)src));
|
||||||
|
#else
|
||||||
|
ZSTD_memcpy(dst, src, 8);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#define COPY8(d,s) { ZSTD_copy8(d,s); d+=8; s+=8; }
|
||||||
|
|
||||||
|
/* Need to use memmove here since the literal buffer can now be located within
|
||||||
|
the dst buffer. In circumstances where the op "catches up" to where the
|
||||||
|
literal buffer is, there can be partial overlaps in this call on the final
|
||||||
|
copy if the literal is being shifted by less than 16 bytes. */
|
||||||
|
static void ZSTD_copy16(void* dst, const void* src) {
|
||||||
|
#if defined(ZSTD_ARCH_ARM_NEON)
|
||||||
|
vst1q_u8((uint8_t*)dst, vld1q_u8((const uint8_t*)src));
|
||||||
|
#elif defined(ZSTD_ARCH_X86_SSE2)
|
||||||
|
_mm_storeu_si128((__m128i*)dst, _mm_loadu_si128((const __m128i*)src));
|
||||||
|
#elif defined(__clang__)
|
||||||
|
ZSTD_memmove(dst, src, 16);
|
||||||
|
#else
|
||||||
|
/* ZSTD_memmove is not inlined properly by gcc */
|
||||||
|
BYTE copy16_buf[16];
|
||||||
|
ZSTD_memcpy(copy16_buf, src, 16);
|
||||||
|
ZSTD_memcpy(dst, copy16_buf, 16);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#define COPY16(d,s) { ZSTD_copy16(d,s); d+=16; s+=16; }
|
||||||
|
|
||||||
|
#define WILDCOPY_OVERLENGTH 32
|
||||||
|
#define WILDCOPY_VECLEN 16
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ZSTD_no_overlap,
|
||||||
|
ZSTD_overlap_src_before_dst
|
||||||
|
/* ZSTD_overlap_dst_before_src, */
|
||||||
|
} ZSTD_overlap_e;
|
||||||
|
|
||||||
|
/*! ZSTD_wildcopy() :
|
||||||
|
* Custom version of ZSTD_memcpy(), can over read/write up to WILDCOPY_OVERLENGTH bytes (if length==0)
|
||||||
|
* @param ovtype controls the overlap detection
|
||||||
|
* - ZSTD_no_overlap: The source and destination are guaranteed to be at least WILDCOPY_VECLEN bytes apart.
|
||||||
|
* - ZSTD_overlap_src_before_dst: The src and dst may overlap, but they MUST be at least 8 bytes apart.
|
||||||
|
* The src buffer must be before the dst buffer.
|
||||||
|
*/
|
||||||
|
MEM_STATIC FORCE_INLINE_ATTR
|
||||||
|
void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length, ZSTD_overlap_e const ovtype)
|
||||||
|
{
|
||||||
|
ptrdiff_t diff = (BYTE*)dst - (const BYTE*)src;
|
||||||
|
const BYTE* ip = (const BYTE*)src;
|
||||||
|
BYTE* op = (BYTE*)dst;
|
||||||
|
BYTE* const oend = op + length;
|
||||||
|
|
||||||
|
if (ovtype == ZSTD_overlap_src_before_dst && diff < WILDCOPY_VECLEN) {
|
||||||
|
/* Handle short offset copies. */
|
||||||
|
do {
|
||||||
|
COPY8(op, ip)
|
||||||
|
} while (op < oend);
|
||||||
|
} else {
|
||||||
|
assert(diff >= WILDCOPY_VECLEN || diff <= -WILDCOPY_VECLEN);
|
||||||
|
/* Separate out the first COPY16() call because the copy length is
|
||||||
|
* almost certain to be short, so the branches have different
|
||||||
|
* probabilities. Since it is almost certain to be short, only do
|
||||||
|
* one COPY16() in the first call. Then, do two calls per loop since
|
||||||
|
* at that point it is more likely to have a high trip count.
|
||||||
|
*/
|
||||||
|
#ifdef __aarch64__
|
||||||
|
do {
|
||||||
|
COPY16(op, ip);
|
||||||
|
}
|
||||||
|
while (op < oend);
|
||||||
|
#else
|
||||||
|
ZSTD_copy16(op, ip);
|
||||||
|
if (16 >= length) return;
|
||||||
|
op += 16;
|
||||||
|
ip += 16;
|
||||||
|
do {
|
||||||
|
COPY16(op, ip);
|
||||||
|
COPY16(op, ip);
|
||||||
|
}
|
||||||
|
while (op < oend);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
|
||||||
|
{
|
||||||
|
size_t const length = MIN(dstCapacity, srcSize);
|
||||||
|
if (length > 0) {
|
||||||
|
ZSTD_memcpy(dst, src, length);
|
||||||
|
}
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* define "workspace is too large" as this number of times larger than needed */
|
||||||
|
#define ZSTD_WORKSPACETOOLARGE_FACTOR 3
|
||||||
|
|
||||||
|
/* when workspace is continuously too large
|
||||||
|
* during at least this number of times,
|
||||||
|
* context's memory usage is considered wasteful,
|
||||||
|
* because it's sized to handle a worst case scenario which rarely happens.
|
||||||
|
* In which case, resize it down to free some memory */
|
||||||
|
#define ZSTD_WORKSPACETOOLARGE_MAXDURATION 128
|
||||||
|
|
||||||
|
/* Controls whether the input/output buffer is buffered or stable. */
|
||||||
|
typedef enum {
|
||||||
|
ZSTD_bm_buffered = 0, /* Buffer the input/output */
|
||||||
|
ZSTD_bm_stable = 1 /* ZSTD_inBuffer/ZSTD_outBuffer is stable */
|
||||||
|
} ZSTD_bufferMode_e;
|
||||||
|
|
||||||
|
|
||||||
|
/*-*******************************************
|
||||||
|
* Private declarations
|
||||||
|
*********************************************/
|
||||||
|
typedef struct seqDef_s {
|
||||||
|
U32 offBase; /* offBase == Offset + ZSTD_REP_NUM, or repcode 1,2,3 */
|
||||||
|
U16 litLength;
|
||||||
|
U16 mlBase; /* mlBase == matchLength - MINMATCH */
|
||||||
|
} seqDef;
|
||||||
|
|
||||||
|
/* Controls whether seqStore has a single "long" litLength or matchLength. See seqStore_t. */
|
||||||
|
typedef enum {
|
||||||
|
ZSTD_llt_none = 0, /* no longLengthType */
|
||||||
|
ZSTD_llt_literalLength = 1, /* represents a long literal */
|
||||||
|
ZSTD_llt_matchLength = 2 /* represents a long match */
|
||||||
|
} ZSTD_longLengthType_e;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
seqDef* sequencesStart;
|
||||||
|
seqDef* sequences; /* ptr to end of sequences */
|
||||||
|
BYTE* litStart;
|
||||||
|
BYTE* lit; /* ptr to end of literals */
|
||||||
|
BYTE* llCode;
|
||||||
|
BYTE* mlCode;
|
||||||
|
BYTE* ofCode;
|
||||||
|
size_t maxNbSeq;
|
||||||
|
size_t maxNbLit;
|
||||||
|
|
||||||
|
/* longLengthPos and longLengthType to allow us to represent either a single litLength or matchLength
|
||||||
|
* in the seqStore that has a value larger than U16 (if it exists). To do so, we increment
|
||||||
|
* the existing value of the litLength or matchLength by 0x10000.
|
||||||
|
*/
|
||||||
|
ZSTD_longLengthType_e longLengthType;
|
||||||
|
U32 longLengthPos; /* Index of the sequence to apply long length modification to */
|
||||||
|
} seqStore_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
U32 litLength;
|
||||||
|
U32 matchLength;
|
||||||
|
} ZSTD_sequenceLength;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the ZSTD_sequenceLength for the given sequences. It handles the decoding of long sequences
|
||||||
|
* indicated by longLengthPos and longLengthType, and adds MINMATCH back to matchLength.
|
||||||
|
*/
|
||||||
|
MEM_STATIC ZSTD_sequenceLength ZSTD_getSequenceLength(seqStore_t const* seqStore, seqDef const* seq)
|
||||||
|
{
|
||||||
|
ZSTD_sequenceLength seqLen;
|
||||||
|
seqLen.litLength = seq->litLength;
|
||||||
|
seqLen.matchLength = seq->mlBase + MINMATCH;
|
||||||
|
if (seqStore->longLengthPos == (U32)(seq - seqStore->sequencesStart)) {
|
||||||
|
if (seqStore->longLengthType == ZSTD_llt_literalLength) {
|
||||||
|
seqLen.litLength += 0xFFFF;
|
||||||
|
}
|
||||||
|
if (seqStore->longLengthType == ZSTD_llt_matchLength) {
|
||||||
|
seqLen.matchLength += 0xFFFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return seqLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Contains the compressed frame size and an upper-bound for the decompressed frame size.
|
||||||
|
* Note: before using `compressedSize`, check for errors using ZSTD_isError().
|
||||||
|
* similarly, before using `decompressedBound`, check for errors using:
|
||||||
|
* `decompressedBound != ZSTD_CONTENTSIZE_ERROR`
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
size_t compressedSize;
|
||||||
|
unsigned long long decompressedBound;
|
||||||
|
} ZSTD_frameSizeInfo; /* decompress & legacy */
|
||||||
|
|
||||||
|
const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx); /* compress & dictBuilder */
|
||||||
|
void ZSTD_seqToCodes(const seqStore_t* seqStorePtr); /* compress, dictBuilder, decodeCorpus (shouldn't get its definition from here) */
|
||||||
|
|
||||||
|
/* custom memory allocation functions */
|
||||||
|
void* ZSTD_customMalloc(size_t size, ZSTD_customMem customMem);
|
||||||
|
void* ZSTD_customCalloc(size_t size, ZSTD_customMem customMem);
|
||||||
|
void ZSTD_customFree(void* ptr, ZSTD_customMem customMem);
|
||||||
|
|
||||||
|
|
||||||
|
MEM_STATIC U32 ZSTD_highbit32(U32 val) /* compress, dictBuilder, decodeCorpus */
|
||||||
|
{
|
||||||
|
assert(val != 0);
|
||||||
|
{
|
||||||
|
# if (__GNUC__ >= 3) /* GCC Intrinsic */
|
||||||
|
return __builtin_clz (val) ^ 31;
|
||||||
|
# else /* Software version */
|
||||||
|
static const U32 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;
|
||||||
|
v |= v >> 1;
|
||||||
|
v |= v >> 2;
|
||||||
|
v |= v >> 4;
|
||||||
|
v |= v >> 8;
|
||||||
|
v |= v >> 16;
|
||||||
|
return DeBruijnClz[(v * 0x07C4ACDDU) >> 27];
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Counts the number of trailing zeros of a `size_t`.
|
||||||
|
* Most compilers should support CTZ as a builtin. A backup
|
||||||
|
* implementation is provided if the builtin isn't supported, but
|
||||||
|
* it may not be terribly efficient.
|
||||||
|
*/
|
||||||
|
MEM_STATIC unsigned ZSTD_countTrailingZeros(size_t val)
|
||||||
|
{
|
||||||
|
if (MEM_64bits()) {
|
||||||
|
# if (__GNUC__ >= 4)
|
||||||
|
return __builtin_ctzll((U64)val);
|
||||||
|
# else
|
||||||
|
static const int DeBruijnBytePos[64] = { 0, 1, 2, 7, 3, 13, 8, 19,
|
||||||
|
4, 25, 14, 28, 9, 34, 20, 56,
|
||||||
|
5, 17, 26, 54, 15, 41, 29, 43,
|
||||||
|
10, 31, 38, 35, 21, 45, 49, 57,
|
||||||
|
63, 6, 12, 18, 24, 27, 33, 55,
|
||||||
|
16, 53, 40, 42, 30, 37, 44, 48,
|
||||||
|
62, 11, 23, 32, 52, 39, 36, 47,
|
||||||
|
61, 22, 51, 46, 60, 50, 59, 58 };
|
||||||
|
return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
|
||||||
|
# endif
|
||||||
|
} else { /* 32 bits */
|
||||||
|
# if (__GNUC__ >= 3)
|
||||||
|
return __builtin_ctz((U32)val);
|
||||||
|
# else
|
||||||
|
static const int DeBruijnBytePos[32] = { 0, 1, 28, 2, 29, 14, 24, 3,
|
||||||
|
30, 22, 20, 15, 25, 17, 4, 8,
|
||||||
|
31, 27, 13, 23, 21, 19, 16, 7,
|
||||||
|
26, 12, 18, 6, 11, 5, 10, 9 };
|
||||||
|
return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ZSTD_invalidateRepCodes() :
|
||||||
|
* ensures next compression will not use repcodes from previous block.
|
||||||
|
* Note : only works with regular variant;
|
||||||
|
* do not use with extDict variant ! */
|
||||||
|
void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx); /* zstdmt, adaptive_compression (shouldn't get this definition from here) */
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
blockType_e blockType;
|
||||||
|
U32 lastBlock;
|
||||||
|
U32 origSize;
|
||||||
|
} blockProperties_t; /* declared here for decompress and fullbench */
|
||||||
|
|
||||||
|
/*! ZSTD_getcBlockSize() :
|
||||||
|
* Provides the size of compressed block from block header `src` */
|
||||||
|
/* Used by: decompress, fullbench (does not get its definition from here) */
|
||||||
|
size_t ZSTD_getcBlockSize(const void* src, size_t srcSize,
|
||||||
|
blockProperties_t* bpPtr);
|
||||||
|
|
||||||
|
/*! ZSTD_decodeSeqHeaders() :
|
||||||
|
* decode sequence header from src */
|
||||||
|
/* Used by: decompress, fullbench (does not get its definition from here) */
|
||||||
|
size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr,
|
||||||
|
const void* src, size_t srcSize);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @returns true iff the CPU supports dynamic BMI2 dispatch.
|
||||||
|
*/
|
||||||
|
MEM_STATIC int ZSTD_cpuSupportsBmi2(void)
|
||||||
|
{
|
||||||
|
ZSTD_cpuid_t cpuid = ZSTD_cpuid();
|
||||||
|
return ZSTD_cpuid_bmi1(cpuid) && ZSTD_cpuid_bmi2(cpuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* ZSTD_CCOMMON_H_MODULE */
|
File diff suppressed because it is too large
Load diff
1740
lib/zstd/decompress/huf_decompress.c
Normal file
1740
lib/zstd/decompress/huf_decompress.c
Normal file
File diff suppressed because it is too large
Load diff
241
lib/zstd/decompress/zstd_ddict.c
Normal file
241
lib/zstd/decompress/zstd_ddict.c
Normal file
|
@ -0,0 +1,241 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Yann Collet, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* zstd_ddict.c :
|
||||||
|
* concentrates all logic that needs to know the internals of ZSTD_DDict object */
|
||||||
|
|
||||||
|
/*-*******************************************************
|
||||||
|
* Dependencies
|
||||||
|
*********************************************************/
|
||||||
|
#include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */
|
||||||
|
#include "../common/cpu.h" /* bmi2 */
|
||||||
|
#include "../common/mem.h" /* low level memory routines */
|
||||||
|
#define FSE_STATIC_LINKING_ONLY
|
||||||
|
#include "../common/fse.h"
|
||||||
|
#define HUF_STATIC_LINKING_ONLY
|
||||||
|
#include "../common/huf.h"
|
||||||
|
#include "zstd_decompress_internal.h"
|
||||||
|
#include "zstd_ddict.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-*******************************************************
|
||||||
|
* Types
|
||||||
|
*********************************************************/
|
||||||
|
struct ZSTD_DDict_s {
|
||||||
|
void* dictBuffer;
|
||||||
|
const void* dictContent;
|
||||||
|
size_t dictSize;
|
||||||
|
ZSTD_entropyDTables_t entropy;
|
||||||
|
U32 dictID;
|
||||||
|
U32 entropyPresent;
|
||||||
|
ZSTD_customMem cMem;
|
||||||
|
}; /* typedef'd to ZSTD_DDict within "zstd.h" */
|
||||||
|
|
||||||
|
const void* ZSTD_DDict_dictContent(const ZSTD_DDict* ddict)
|
||||||
|
{
|
||||||
|
assert(ddict != NULL);
|
||||||
|
return ddict->dictContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ZSTD_DDict_dictSize(const ZSTD_DDict* ddict)
|
||||||
|
{
|
||||||
|
assert(ddict != NULL);
|
||||||
|
return ddict->dictSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZSTD_copyDDictParameters(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)
|
||||||
|
{
|
||||||
|
DEBUGLOG(4, "ZSTD_copyDDictParameters");
|
||||||
|
assert(dctx != NULL);
|
||||||
|
assert(ddict != NULL);
|
||||||
|
dctx->dictID = ddict->dictID;
|
||||||
|
dctx->prefixStart = ddict->dictContent;
|
||||||
|
dctx->virtualStart = ddict->dictContent;
|
||||||
|
dctx->dictEnd = (const BYTE*)ddict->dictContent + ddict->dictSize;
|
||||||
|
dctx->previousDstEnd = dctx->dictEnd;
|
||||||
|
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||||
|
dctx->dictContentBeginForFuzzing = dctx->prefixStart;
|
||||||
|
dctx->dictContentEndForFuzzing = dctx->previousDstEnd;
|
||||||
|
#endif
|
||||||
|
if (ddict->entropyPresent) {
|
||||||
|
dctx->litEntropy = 1;
|
||||||
|
dctx->fseEntropy = 1;
|
||||||
|
dctx->LLTptr = ddict->entropy.LLTable;
|
||||||
|
dctx->MLTptr = ddict->entropy.MLTable;
|
||||||
|
dctx->OFTptr = ddict->entropy.OFTable;
|
||||||
|
dctx->HUFptr = ddict->entropy.hufTable;
|
||||||
|
dctx->entropy.rep[0] = ddict->entropy.rep[0];
|
||||||
|
dctx->entropy.rep[1] = ddict->entropy.rep[1];
|
||||||
|
dctx->entropy.rep[2] = ddict->entropy.rep[2];
|
||||||
|
} else {
|
||||||
|
dctx->litEntropy = 0;
|
||||||
|
dctx->fseEntropy = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
ZSTD_loadEntropy_intoDDict(ZSTD_DDict* ddict,
|
||||||
|
ZSTD_dictContentType_e dictContentType)
|
||||||
|
{
|
||||||
|
ddict->dictID = 0;
|
||||||
|
ddict->entropyPresent = 0;
|
||||||
|
if (dictContentType == ZSTD_dct_rawContent) return 0;
|
||||||
|
|
||||||
|
if (ddict->dictSize < 8) {
|
||||||
|
if (dictContentType == ZSTD_dct_fullDict)
|
||||||
|
return ERROR(dictionary_corrupted); /* only accept specified dictionaries */
|
||||||
|
return 0; /* pure content mode */
|
||||||
|
}
|
||||||
|
{ U32 const magic = MEM_readLE32(ddict->dictContent);
|
||||||
|
if (magic != ZSTD_MAGIC_DICTIONARY) {
|
||||||
|
if (dictContentType == ZSTD_dct_fullDict)
|
||||||
|
return ERROR(dictionary_corrupted); /* only accept specified dictionaries */
|
||||||
|
return 0; /* pure content mode */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ddict->dictID = MEM_readLE32((const char*)ddict->dictContent + ZSTD_FRAMEIDSIZE);
|
||||||
|
|
||||||
|
/* load entropy tables */
|
||||||
|
RETURN_ERROR_IF(ZSTD_isError(ZSTD_loadDEntropy(
|
||||||
|
&ddict->entropy, ddict->dictContent, ddict->dictSize)),
|
||||||
|
dictionary_corrupted, "");
|
||||||
|
ddict->entropyPresent = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static size_t ZSTD_initDDict_internal(ZSTD_DDict* ddict,
|
||||||
|
const void* dict, size_t dictSize,
|
||||||
|
ZSTD_dictLoadMethod_e dictLoadMethod,
|
||||||
|
ZSTD_dictContentType_e dictContentType)
|
||||||
|
{
|
||||||
|
if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dict) || (!dictSize)) {
|
||||||
|
ddict->dictBuffer = NULL;
|
||||||
|
ddict->dictContent = dict;
|
||||||
|
if (!dict) dictSize = 0;
|
||||||
|
} else {
|
||||||
|
void* const internalBuffer = ZSTD_customMalloc(dictSize, ddict->cMem);
|
||||||
|
ddict->dictBuffer = internalBuffer;
|
||||||
|
ddict->dictContent = internalBuffer;
|
||||||
|
if (!internalBuffer) return ERROR(memory_allocation);
|
||||||
|
ZSTD_memcpy(internalBuffer, dict, dictSize);
|
||||||
|
}
|
||||||
|
ddict->dictSize = dictSize;
|
||||||
|
ddict->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */
|
||||||
|
|
||||||
|
/* parse dictionary content */
|
||||||
|
FORWARD_IF_ERROR( ZSTD_loadEntropy_intoDDict(ddict, dictContentType) , "");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize,
|
||||||
|
ZSTD_dictLoadMethod_e dictLoadMethod,
|
||||||
|
ZSTD_dictContentType_e dictContentType,
|
||||||
|
ZSTD_customMem customMem)
|
||||||
|
{
|
||||||
|
if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL;
|
||||||
|
|
||||||
|
{ ZSTD_DDict* const ddict = (ZSTD_DDict*) ZSTD_customMalloc(sizeof(ZSTD_DDict), customMem);
|
||||||
|
if (ddict == NULL) return NULL;
|
||||||
|
ddict->cMem = customMem;
|
||||||
|
{ size_t const initResult = ZSTD_initDDict_internal(ddict,
|
||||||
|
dict, dictSize,
|
||||||
|
dictLoadMethod, dictContentType);
|
||||||
|
if (ZSTD_isError(initResult)) {
|
||||||
|
ZSTD_freeDDict(ddict);
|
||||||
|
return NULL;
|
||||||
|
} }
|
||||||
|
return ddict;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! ZSTD_createDDict() :
|
||||||
|
* Create a digested dictionary, to start decompression without startup delay.
|
||||||
|
* `dict` content is copied inside DDict.
|
||||||
|
* Consequently, `dict` can be released after `ZSTD_DDict` creation */
|
||||||
|
ZSTD_DDict* ZSTD_createDDict(const void* dict, size_t dictSize)
|
||||||
|
{
|
||||||
|
ZSTD_customMem const allocator = { NULL, NULL, NULL };
|
||||||
|
return ZSTD_createDDict_advanced(dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto, allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! ZSTD_createDDict_byReference() :
|
||||||
|
* Create a digested dictionary, to start decompression without startup delay.
|
||||||
|
* Dictionary content is simply referenced, it will be accessed during decompression.
|
||||||
|
* Warning : dictBuffer must outlive DDict (DDict must be freed before dictBuffer) */
|
||||||
|
ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize)
|
||||||
|
{
|
||||||
|
ZSTD_customMem const allocator = { NULL, NULL, NULL };
|
||||||
|
return ZSTD_createDDict_advanced(dictBuffer, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto, allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const ZSTD_DDict* ZSTD_initStaticDDict(
|
||||||
|
void* sBuffer, size_t sBufferSize,
|
||||||
|
const void* dict, size_t dictSize,
|
||||||
|
ZSTD_dictLoadMethod_e dictLoadMethod,
|
||||||
|
ZSTD_dictContentType_e dictContentType)
|
||||||
|
{
|
||||||
|
size_t const neededSpace = sizeof(ZSTD_DDict)
|
||||||
|
+ (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize);
|
||||||
|
ZSTD_DDict* const ddict = (ZSTD_DDict*)sBuffer;
|
||||||
|
assert(sBuffer != NULL);
|
||||||
|
assert(dict != NULL);
|
||||||
|
if ((size_t)sBuffer & 7) return NULL; /* 8-aligned */
|
||||||
|
if (sBufferSize < neededSpace) return NULL;
|
||||||
|
if (dictLoadMethod == ZSTD_dlm_byCopy) {
|
||||||
|
ZSTD_memcpy(ddict+1, dict, dictSize); /* local copy */
|
||||||
|
dict = ddict+1;
|
||||||
|
}
|
||||||
|
if (ZSTD_isError( ZSTD_initDDict_internal(ddict,
|
||||||
|
dict, dictSize,
|
||||||
|
ZSTD_dlm_byRef, dictContentType) ))
|
||||||
|
return NULL;
|
||||||
|
return ddict;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t ZSTD_freeDDict(ZSTD_DDict* ddict)
|
||||||
|
{
|
||||||
|
if (ddict==NULL) return 0; /* support free on NULL */
|
||||||
|
{ ZSTD_customMem const cMem = ddict->cMem;
|
||||||
|
ZSTD_customFree(ddict->dictBuffer, cMem);
|
||||||
|
ZSTD_customFree(ddict, cMem);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! ZSTD_estimateDDictSize() :
|
||||||
|
* Estimate amount of memory that will be needed to create a dictionary for decompression.
|
||||||
|
* Note : dictionary created by reference using ZSTD_dlm_byRef are smaller */
|
||||||
|
size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod)
|
||||||
|
{
|
||||||
|
return sizeof(ZSTD_DDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict)
|
||||||
|
{
|
||||||
|
if (ddict==NULL) return 0; /* support sizeof on NULL */
|
||||||
|
return sizeof(*ddict) + (ddict->dictBuffer ? ddict->dictSize : 0) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! ZSTD_getDictID_fromDDict() :
|
||||||
|
* Provides the dictID of the dictionary loaded into `ddict`.
|
||||||
|
* If @return == 0, the dictionary is not conformant to Zstandard specification, or empty.
|
||||||
|
* Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */
|
||||||
|
unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict)
|
||||||
|
{
|
||||||
|
if (ddict==NULL) return 0;
|
||||||
|
return ZSTD_getDictID_fromDict(ddict->dictContent, ddict->dictSize);
|
||||||
|
}
|
44
lib/zstd/decompress/zstd_ddict.h
Normal file
44
lib/zstd/decompress/zstd_ddict.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Yann Collet, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef ZSTD_DDICT_H
|
||||||
|
#define ZSTD_DDICT_H
|
||||||
|
|
||||||
|
/*-*******************************************************
|
||||||
|
* Dependencies
|
||||||
|
*********************************************************/
|
||||||
|
#include "../common/zstd_deps.h" /* size_t */
|
||||||
|
#include <linux/zstd.h> /* ZSTD_DDict, and several public functions */
|
||||||
|
|
||||||
|
|
||||||
|
/*-*******************************************************
|
||||||
|
* Interface
|
||||||
|
*********************************************************/
|
||||||
|
|
||||||
|
/* note: several prototypes are already published in `zstd.h` :
|
||||||
|
* ZSTD_createDDict()
|
||||||
|
* ZSTD_createDDict_byReference()
|
||||||
|
* ZSTD_createDDict_advanced()
|
||||||
|
* ZSTD_freeDDict()
|
||||||
|
* ZSTD_initStaticDDict()
|
||||||
|
* ZSTD_sizeof_DDict()
|
||||||
|
* ZSTD_estimateDDictSize()
|
||||||
|
* ZSTD_getDictID_fromDict()
|
||||||
|
*/
|
||||||
|
|
||||||
|
const void* ZSTD_DDict_dictContent(const ZSTD_DDict* ddict);
|
||||||
|
size_t ZSTD_DDict_dictSize(const ZSTD_DDict* ddict);
|
||||||
|
|
||||||
|
void ZSTD_copyDDictParameters(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* ZSTD_DDICT_H */
|
2131
lib/zstd/decompress/zstd_decompress.c
Normal file
2131
lib/zstd/decompress/zstd_decompress.c
Normal file
File diff suppressed because it is too large
Load diff
2072
lib/zstd/decompress/zstd_decompress_block.c
Normal file
2072
lib/zstd/decompress/zstd_decompress_block.c
Normal file
File diff suppressed because it is too large
Load diff
68
lib/zstd/decompress/zstd_decompress_block.h
Normal file
68
lib/zstd/decompress/zstd_decompress_block.h
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Yann Collet, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef ZSTD_DEC_BLOCK_H
|
||||||
|
#define ZSTD_DEC_BLOCK_H
|
||||||
|
|
||||||
|
/*-*******************************************************
|
||||||
|
* Dependencies
|
||||||
|
*********************************************************/
|
||||||
|
#include "../common/zstd_deps.h" /* size_t */
|
||||||
|
#include <linux/zstd.h> /* DCtx, and some public functions */
|
||||||
|
#include "../common/zstd_internal.h" /* blockProperties_t, and some public functions */
|
||||||
|
#include "zstd_decompress_internal.h" /* ZSTD_seqSymbol */
|
||||||
|
|
||||||
|
|
||||||
|
/* === Prototypes === */
|
||||||
|
|
||||||
|
/* note: prototypes already published within `zstd.h` :
|
||||||
|
* ZSTD_decompressBlock()
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* note: prototypes already published within `zstd_internal.h` :
|
||||||
|
* ZSTD_getcBlockSize()
|
||||||
|
* ZSTD_decodeSeqHeaders()
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Streaming state is used to inform allocation of the literal buffer */
|
||||||
|
typedef enum {
|
||||||
|
not_streaming = 0,
|
||||||
|
is_streaming = 1
|
||||||
|
} streaming_operation;
|
||||||
|
|
||||||
|
/* ZSTD_decompressBlock_internal() :
|
||||||
|
* decompress block, starting at `src`,
|
||||||
|
* into destination buffer `dst`.
|
||||||
|
* @return : decompressed block size,
|
||||||
|
* or an error code (which can be tested using ZSTD_isError())
|
||||||
|
*/
|
||||||
|
size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
|
||||||
|
void* dst, size_t dstCapacity,
|
||||||
|
const void* src, size_t srcSize, const int frame, const streaming_operation streaming);
|
||||||
|
|
||||||
|
/* ZSTD_buildFSETable() :
|
||||||
|
* generate FSE decoding table for one symbol (ll, ml or off)
|
||||||
|
* this function must be called with valid parameters only
|
||||||
|
* (dt is large enough, normalizedCounter distribution total is a power of 2, max is within range, etc.)
|
||||||
|
* in which case it cannot fail.
|
||||||
|
* The workspace must be 4-byte aligned and at least ZSTD_BUILD_FSE_TABLE_WKSP_SIZE bytes, which is
|
||||||
|
* defined in zstd_decompress_internal.h.
|
||||||
|
* Internal use only.
|
||||||
|
*/
|
||||||
|
void ZSTD_buildFSETable(ZSTD_seqSymbol* dt,
|
||||||
|
const short* normalizedCounter, unsigned maxSymbolValue,
|
||||||
|
const U32* baseValue, const U8* nbAdditionalBits,
|
||||||
|
unsigned tableLog, void* wksp, size_t wkspSize,
|
||||||
|
int bmi2);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* ZSTD_DEC_BLOCK_H */
|
228
lib/zstd/decompress/zstd_decompress_internal.h
Normal file
228
lib/zstd/decompress/zstd_decompress_internal.h
Normal file
|
@ -0,0 +1,228 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Yann Collet, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* zstd_decompress_internal:
|
||||||
|
* objects and definitions shared within lib/decompress modules */
|
||||||
|
|
||||||
|
#ifndef ZSTD_DECOMPRESS_INTERNAL_H
|
||||||
|
#define ZSTD_DECOMPRESS_INTERNAL_H
|
||||||
|
|
||||||
|
|
||||||
|
/*-*******************************************************
|
||||||
|
* Dependencies
|
||||||
|
*********************************************************/
|
||||||
|
#include "../common/mem.h" /* BYTE, U16, U32 */
|
||||||
|
#include "../common/zstd_internal.h" /* constants : MaxLL, MaxML, MaxOff, LLFSELog, etc. */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-*******************************************************
|
||||||
|
* Constants
|
||||||
|
*********************************************************/
|
||||||
|
static UNUSED_ATTR 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 UNUSED_ATTR const U32 OF_base[MaxOff+1] = {
|
||||||
|
0, 1, 1, 5, 0xD, 0x1D, 0x3D, 0x7D,
|
||||||
|
0xFD, 0x1FD, 0x3FD, 0x7FD, 0xFFD, 0x1FFD, 0x3FFD, 0x7FFD,
|
||||||
|
0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD, 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD,
|
||||||
|
0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD, 0x1FFFFFFD, 0x3FFFFFFD, 0x7FFFFFFD };
|
||||||
|
|
||||||
|
static UNUSED_ATTR const U8 OF_bits[MaxOff+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 };
|
||||||
|
|
||||||
|
static UNUSED_ATTR const U32 ML_base[MaxML+1] = {
|
||||||
|
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, 33, 34,
|
||||||
|
35, 37, 39, 41, 43, 47, 51, 59,
|
||||||
|
67, 83, 99, 0x83, 0x103, 0x203, 0x403, 0x803,
|
||||||
|
0x1003, 0x2003, 0x4003, 0x8003, 0x10003 };
|
||||||
|
|
||||||
|
|
||||||
|
/*-*******************************************************
|
||||||
|
* Decompression types
|
||||||
|
*********************************************************/
|
||||||
|
typedef struct {
|
||||||
|
U32 fastMode;
|
||||||
|
U32 tableLog;
|
||||||
|
} ZSTD_seqSymbol_header;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
U16 nextState;
|
||||||
|
BYTE nbAdditionalBits;
|
||||||
|
BYTE nbBits;
|
||||||
|
U32 baseValue;
|
||||||
|
} ZSTD_seqSymbol;
|
||||||
|
|
||||||
|
#define SEQSYMBOL_TABLE_SIZE(log) (1 + (1 << (log)))
|
||||||
|
|
||||||
|
#define ZSTD_BUILD_FSE_TABLE_WKSP_SIZE (sizeof(S16) * (MaxSeq + 1) + (1u << MaxFSELog) + sizeof(U64))
|
||||||
|
#define ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32 ((ZSTD_BUILD_FSE_TABLE_WKSP_SIZE + sizeof(U32) - 1) / sizeof(U32))
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ZSTD_seqSymbol LLTable[SEQSYMBOL_TABLE_SIZE(LLFSELog)]; /* Note : Space reserved for FSE Tables */
|
||||||
|
ZSTD_seqSymbol OFTable[SEQSYMBOL_TABLE_SIZE(OffFSELog)]; /* is also used as temporary workspace while building hufTable during DDict creation */
|
||||||
|
ZSTD_seqSymbol MLTable[SEQSYMBOL_TABLE_SIZE(MLFSELog)]; /* and therefore must be at least HUF_DECOMPRESS_WORKSPACE_SIZE large */
|
||||||
|
HUF_DTable hufTable[HUF_DTABLE_SIZE(HufLog)]; /* can accommodate HUF_decompress4X */
|
||||||
|
U32 rep[ZSTD_REP_NUM];
|
||||||
|
U32 workspace[ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32];
|
||||||
|
} ZSTD_entropyDTables_t;
|
||||||
|
|
||||||
|
typedef enum { ZSTDds_getFrameHeaderSize, ZSTDds_decodeFrameHeader,
|
||||||
|
ZSTDds_decodeBlockHeader, ZSTDds_decompressBlock,
|
||||||
|
ZSTDds_decompressLastBlock, ZSTDds_checkChecksum,
|
||||||
|
ZSTDds_decodeSkippableHeader, ZSTDds_skipFrame } ZSTD_dStage;
|
||||||
|
|
||||||
|
typedef enum { zdss_init=0, zdss_loadHeader,
|
||||||
|
zdss_read, zdss_load, zdss_flush } ZSTD_dStreamStage;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ZSTD_use_indefinitely = -1, /* Use the dictionary indefinitely */
|
||||||
|
ZSTD_dont_use = 0, /* Do not use the dictionary (if one exists free it) */
|
||||||
|
ZSTD_use_once = 1 /* Use the dictionary once and set to ZSTD_dont_use */
|
||||||
|
} ZSTD_dictUses_e;
|
||||||
|
|
||||||
|
/* Hashset for storing references to multiple ZSTD_DDict within ZSTD_DCtx */
|
||||||
|
typedef struct {
|
||||||
|
const ZSTD_DDict** ddictPtrTable;
|
||||||
|
size_t ddictPtrTableSize;
|
||||||
|
size_t ddictPtrCount;
|
||||||
|
} ZSTD_DDictHashSet;
|
||||||
|
|
||||||
|
#ifndef ZSTD_DECODER_INTERNAL_BUFFER
|
||||||
|
# define ZSTD_DECODER_INTERNAL_BUFFER (1 << 16)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ZSTD_LBMIN 64
|
||||||
|
#define ZSTD_LBMAX (128 << 10)
|
||||||
|
|
||||||
|
/* extra buffer, compensates when dst is not large enough to store litBuffer */
|
||||||
|
#define ZSTD_LITBUFFEREXTRASIZE BOUNDED(ZSTD_LBMIN, ZSTD_DECODER_INTERNAL_BUFFER, ZSTD_LBMAX)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ZSTD_not_in_dst = 0, /* Stored entirely within litExtraBuffer */
|
||||||
|
ZSTD_in_dst = 1, /* Stored entirely within dst (in memory after current output write) */
|
||||||
|
ZSTD_split = 2 /* Split between litExtraBuffer and dst */
|
||||||
|
} ZSTD_litLocation_e;
|
||||||
|
|
||||||
|
struct ZSTD_DCtx_s
|
||||||
|
{
|
||||||
|
const ZSTD_seqSymbol* LLTptr;
|
||||||
|
const ZSTD_seqSymbol* MLTptr;
|
||||||
|
const ZSTD_seqSymbol* OFTptr;
|
||||||
|
const HUF_DTable* HUFptr;
|
||||||
|
ZSTD_entropyDTables_t entropy;
|
||||||
|
U32 workspace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; /* space needed when building huffman tables */
|
||||||
|
const void* previousDstEnd; /* detect continuity */
|
||||||
|
const void* prefixStart; /* start of current segment */
|
||||||
|
const void* virtualStart; /* virtual start of previous segment if it was just before current one */
|
||||||
|
const void* dictEnd; /* end of previous segment */
|
||||||
|
size_t expected;
|
||||||
|
ZSTD_frameHeader fParams;
|
||||||
|
U64 processedCSize;
|
||||||
|
U64 decodedSize;
|
||||||
|
blockType_e bType; /* used in ZSTD_decompressContinue(), store blockType between block header decoding and block decompression stages */
|
||||||
|
ZSTD_dStage stage;
|
||||||
|
U32 litEntropy;
|
||||||
|
U32 fseEntropy;
|
||||||
|
struct xxh64_state xxhState;
|
||||||
|
size_t headerSize;
|
||||||
|
ZSTD_format_e format;
|
||||||
|
ZSTD_forceIgnoreChecksum_e forceIgnoreChecksum; /* User specified: if == 1, will ignore checksums in compressed frame. Default == 0 */
|
||||||
|
U32 validateChecksum; /* if == 1, will validate checksum. Is == 1 if (fParams.checksumFlag == 1) and (forceIgnoreChecksum == 0). */
|
||||||
|
const BYTE* litPtr;
|
||||||
|
ZSTD_customMem customMem;
|
||||||
|
size_t litSize;
|
||||||
|
size_t rleSize;
|
||||||
|
size_t staticSize;
|
||||||
|
#if DYNAMIC_BMI2 != 0
|
||||||
|
int bmi2; /* == 1 if the CPU supports BMI2 and 0 otherwise. CPU support is determined dynamically once per context lifetime. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* dictionary */
|
||||||
|
ZSTD_DDict* ddictLocal;
|
||||||
|
const ZSTD_DDict* ddict; /* set by ZSTD_initDStream_usingDDict(), or ZSTD_DCtx_refDDict() */
|
||||||
|
U32 dictID;
|
||||||
|
int ddictIsCold; /* if == 1 : dictionary is "new" for working context, and presumed "cold" (not in cpu cache) */
|
||||||
|
ZSTD_dictUses_e dictUses;
|
||||||
|
ZSTD_DDictHashSet* ddictSet; /* Hash set for multiple ddicts */
|
||||||
|
ZSTD_refMultipleDDicts_e refMultipleDDicts; /* User specified: if == 1, will allow references to multiple DDicts. Default == 0 (disabled) */
|
||||||
|
|
||||||
|
/* streaming */
|
||||||
|
ZSTD_dStreamStage streamStage;
|
||||||
|
char* inBuff;
|
||||||
|
size_t inBuffSize;
|
||||||
|
size_t inPos;
|
||||||
|
size_t maxWindowSize;
|
||||||
|
char* outBuff;
|
||||||
|
size_t outBuffSize;
|
||||||
|
size_t outStart;
|
||||||
|
size_t outEnd;
|
||||||
|
size_t lhSize;
|
||||||
|
U32 hostageByte;
|
||||||
|
int noForwardProgress;
|
||||||
|
ZSTD_bufferMode_e outBufferMode;
|
||||||
|
ZSTD_outBuffer expectedOutBuffer;
|
||||||
|
|
||||||
|
/* workspace */
|
||||||
|
BYTE* litBuffer;
|
||||||
|
const BYTE* litBufferEnd;
|
||||||
|
ZSTD_litLocation_e litBufferLocation;
|
||||||
|
BYTE litExtraBuffer[ZSTD_LITBUFFEREXTRASIZE + WILDCOPY_OVERLENGTH]; /* literal buffer can be split between storage within dst and within this scratch buffer */
|
||||||
|
BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX];
|
||||||
|
|
||||||
|
size_t oversizedDuration;
|
||||||
|
|
||||||
|
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||||
|
void const* dictContentBeginForFuzzing;
|
||||||
|
void const* dictContentEndForFuzzing;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Tracing */
|
||||||
|
}; /* typedef'd to ZSTD_DCtx within "zstd.h" */
|
||||||
|
|
||||||
|
MEM_STATIC int ZSTD_DCtx_get_bmi2(const struct ZSTD_DCtx_s *dctx) {
|
||||||
|
#if DYNAMIC_BMI2 != 0
|
||||||
|
return dctx->bmi2;
|
||||||
|
#else
|
||||||
|
(void)dctx;
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-*******************************************************
|
||||||
|
* Shared internal functions
|
||||||
|
*********************************************************/
|
||||||
|
|
||||||
|
/*! ZSTD_loadDEntropy() :
|
||||||
|
* dict : must point at beginning of a valid zstd dictionary.
|
||||||
|
* @return : size of dictionary header (size of magic number + dict ID + entropy tables) */
|
||||||
|
size_t ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy,
|
||||||
|
const void* const dict, size_t const dictSize);
|
||||||
|
|
||||||
|
/*! ZSTD_checkContinuity() :
|
||||||
|
* check if next `dst` follows previous position, where decompression ended.
|
||||||
|
* If yes, do nothing (continue on current segment).
|
||||||
|
* If not, classify previous segment as "external dictionary", and start a new segment.
|
||||||
|
* This function cannot fail. */
|
||||||
|
void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst, size_t dstSize);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* ZSTD_DECOMPRESS_INTERNAL_H */
|
34
lib/zstd/decompress_sources.h
Normal file
34
lib/zstd/decompress_sources.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file includes every .c file needed for decompression.
|
||||||
|
* It is used by lib/decompress_unzstd.c to include the decompression
|
||||||
|
* source into the translation-unit, so it can be used for kernel
|
||||||
|
* decompression.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable the ASM Huffman implementation because we need to
|
||||||
|
* include all the sources.
|
||||||
|
*/
|
||||||
|
#define ZSTD_DISABLE_ASM 1
|
||||||
|
|
||||||
|
#include "common/debug.c"
|
||||||
|
#include "common/entropy_common.c"
|
||||||
|
#include "common/error_private.c"
|
||||||
|
#include "common/fse_decompress.c"
|
||||||
|
#include "common/zstd_common.c"
|
||||||
|
#include "decompress/huf_decompress.c"
|
||||||
|
#include "decompress/zstd_ddict.c"
|
||||||
|
#include "decompress/zstd_decompress.c"
|
||||||
|
#include "decompress/zstd_decompress_block.c"
|
||||||
|
#include "zstd_decompress_module.c"
|
|
@ -1,213 +0,0 @@
|
||||||
// SPDX-License-Identifier: (GPL-2.0 or BSD-2-Clause)
|
|
||||||
/*
|
|
||||||
* Common functions of New Generation Entropy library
|
|
||||||
* Copyright (C) 2016, Yann Collet.
|
|
||||||
*
|
|
||||||
* You can contact the author at :
|
|
||||||
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* *************************************
|
|
||||||
* Dependencies
|
|
||||||
***************************************/
|
|
||||||
#include "error_private.h" /* ERR_*, ERROR */
|
|
||||||
#include "fse.h"
|
|
||||||
#include "huf.h"
|
|
||||||
#include "mem.h"
|
|
||||||
|
|
||||||
/*=== Version ===*/
|
|
||||||
unsigned FSE_versionNumber(void) { return FSE_VERSION_NUMBER; }
|
|
||||||
|
|
||||||
/*=== Error Management ===*/
|
|
||||||
unsigned FSE_isError(size_t code) { return ERR_isError(code); }
|
|
||||||
|
|
||||||
unsigned HUF_isError(size_t code) { return ERR_isError(code); }
|
|
||||||
|
|
||||||
/*-**************************************************************
|
|
||||||
* FSE NCount encoding-decoding
|
|
||||||
****************************************************************/
|
|
||||||
size_t FSE_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 = ZSTD_readLE32(ip);
|
|
||||||
nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG; /* extract tableLog */
|
|
||||||
if (nbBits > FSE_TABLELOG_ABSOLUTE_MAX)
|
|
||||||
return ERROR(tableLog_tooLarge);
|
|
||||||
bitStream >>= 4;
|
|
||||||
bitCount = 4;
|
|
||||||
*tableLogPtr = nbBits;
|
|
||||||
remaining = (1 << nbBits) + 1;
|
|
||||||
threshold = 1 << nbBits;
|
|
||||||
nbBits++;
|
|
||||||
|
|
||||||
while ((remaining > 1) & (charnum <= *maxSVPtr)) {
|
|
||||||
if (previous0) {
|
|
||||||
unsigned n0 = charnum;
|
|
||||||
while ((bitStream & 0xFFFF) == 0xFFFF) {
|
|
||||||
n0 += 24;
|
|
||||||
if (ip < iend - 5) {
|
|
||||||
ip += 2;
|
|
||||||
bitStream = ZSTD_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 = ZSTD_readLE32(ip) >> bitCount;
|
|
||||||
} else {
|
|
||||||
bitStream >>= 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
int const max = (2 * threshold - 1) - remaining;
|
|
||||||
int count;
|
|
||||||
|
|
||||||
if ((bitStream & (threshold - 1)) < (U32)max) {
|
|
||||||
count = bitStream & (threshold - 1);
|
|
||||||
bitCount += nbBits - 1;
|
|
||||||
} else {
|
|
||||||
count = bitStream & (2 * threshold - 1);
|
|
||||||
if (count >= threshold)
|
|
||||||
count -= max;
|
|
||||||
bitCount += nbBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
count--; /* extra accuracy */
|
|
||||||
remaining -= count < 0 ? -count : count; /* -1 means +1 */
|
|
||||||
normalizedCounter[charnum++] = (short)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 = ZSTD_readLE32(ip) >> (bitCount & 31);
|
|
||||||
}
|
|
||||||
} /* while ((remaining>1) & (charnum<=*maxSVPtr)) */
|
|
||||||
if (remaining != 1)
|
|
||||||
return ERROR(corruption_detected);
|
|
||||||
if (bitCount > 32)
|
|
||||||
return ERROR(corruption_detected);
|
|
||||||
*maxSVPtr = charnum - 1;
|
|
||||||
|
|
||||||
ip += (bitCount + 7) >> 3;
|
|
||||||
return ip - istart;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! HUF_readStats() :
|
|
||||||
Read compact Huffman tree, saved by HUF_writeCTable().
|
|
||||||
`huffWeight` is destination buffer.
|
|
||||||
`rankStats` is assumed to be a table of at least HUF_TABLELOG_MAX U32.
|
|
||||||
@return : size read from `src` , or an error Code .
|
|
||||||
Note : Needed by HUF_readCTable() and HUF_readDTableX?() .
|
|
||||||
*/
|
|
||||||
size_t HUF_readStats_wksp(BYTE *huffWeight, size_t hwSize, U32 *rankStats, U32 *nbSymbolsPtr, U32 *tableLogPtr, const void *src, size_t srcSize, void *workspace, size_t workspaceSize)
|
|
||||||
{
|
|
||||||
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 */
|
|
||||||
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 < oSize; n += 2) {
|
|
||||||
huffWeight[n] = ip[n / 2] >> 4;
|
|
||||||
huffWeight[n + 1] = ip[n / 2] & 15;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else { /* header compressed with FSE (normal case) */
|
|
||||||
if (iSize + 1 > srcSize)
|
|
||||||
return ERROR(srcSize_wrong);
|
|
||||||
oSize = FSE_decompress_wksp(huffWeight, hwSize - 1, ip + 1, iSize, 6, workspace, workspaceSize); /* max (hwSize-1) values decoded, as last one is implied */
|
|
||||||
if (FSE_isError(oSize))
|
|
||||||
return oSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* collect weight stats */
|
|
||||||
memset(rankStats, 0, (HUF_TABLELOG_MAX + 1) * sizeof(U32));
|
|
||||||
weightTotal = 0;
|
|
||||||
{
|
|
||||||
U32 n;
|
|
||||||
for (n = 0; n < oSize; n++) {
|
|
||||||
if (huffWeight[n] >= HUF_TABLELOG_MAX)
|
|
||||||
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 = BIT_highbit32(weightTotal) + 1;
|
|
||||||
if (tableLog > HUF_TABLELOG_MAX)
|
|
||||||
return ERROR(corruption_detected);
|
|
||||||
*tableLogPtr = tableLog;
|
|
||||||
/* determine last weight */
|
|
||||||
{
|
|
||||||
U32 const total = 1 << tableLog;
|
|
||||||
U32 const rest = total - weightTotal;
|
|
||||||
U32 const verif = 1 << BIT_highbit32(rest);
|
|
||||||
U32 const lastWeight = BIT_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;
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
/* SPDX-License-Identifier: (GPL-2.0 or BSD-3-Clause-Clear) */
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Note : this module is expected to remain private, do not expose it */
|
|
||||||
|
|
||||||
#ifndef ERROR_H_MODULE
|
|
||||||
#define ERROR_H_MODULE
|
|
||||||
|
|
||||||
/* ****************************************
|
|
||||||
* Dependencies
|
|
||||||
******************************************/
|
|
||||||
#include <linux/types.h> /* size_t */
|
|
||||||
#include <linux/zstd.h> /* enum list */
|
|
||||||
|
|
||||||
/* ****************************************
|
|
||||||
* Compiler-specific
|
|
||||||
******************************************/
|
|
||||||
#define ERR_STATIC static __attribute__((unused))
|
|
||||||
|
|
||||||
/*-****************************************
|
|
||||||
* Customization (error_public.h)
|
|
||||||
******************************************/
|
|
||||||
typedef ZSTD_ErrorCode ERR_enum;
|
|
||||||
#define PREFIX(name) ZSTD_error_##name
|
|
||||||
|
|
||||||
/*-****************************************
|
|
||||||
* Error codes handling
|
|
||||||
******************************************/
|
|
||||||
#define ERROR(name) ((size_t)-PREFIX(name))
|
|
||||||
|
|
||||||
ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); }
|
|
||||||
|
|
||||||
ERR_STATIC ERR_enum ERR_getErrorCode(size_t code)
|
|
||||||
{
|
|
||||||
if (!ERR_isError(code))
|
|
||||||
return (ERR_enum)0;
|
|
||||||
return (ERR_enum)(0 - code);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* ERROR_H_MODULE */
|
|
545
lib/zstd/fse.h
545
lib/zstd/fse.h
|
@ -1,545 +0,0 @@
|
||||||
/* SPDX-License-Identifier: (GPL-2.0 or BSD-2-Clause) */
|
|
||||||
/*
|
|
||||||
* FSE : Finite State Entropy codec
|
|
||||||
* Public Prototypes declaration
|
|
||||||
* Copyright (C) 2013-2016, Yann Collet.
|
|
||||||
*
|
|
||||||
* You can contact the author at :
|
|
||||||
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
|
||||||
*/
|
|
||||||
#ifndef FSE_H
|
|
||||||
#define FSE_H
|
|
||||||
|
|
||||||
/*-*****************************************
|
|
||||||
* Dependencies
|
|
||||||
******************************************/
|
|
||||||
#include <linux/types.h> /* size_t, ptrdiff_t */
|
|
||||||
|
|
||||||
/*-*****************************************
|
|
||||||
* FSE_PUBLIC_API : control library symbols visibility
|
|
||||||
******************************************/
|
|
||||||
#define FSE_PUBLIC_API
|
|
||||||
|
|
||||||
/*------ Version ------*/
|
|
||||||
#define FSE_VERSION_MAJOR 0
|
|
||||||
#define FSE_VERSION_MINOR 9
|
|
||||||
#define FSE_VERSION_RELEASE 0
|
|
||||||
|
|
||||||
#define FSE_LIB_VERSION FSE_VERSION_MAJOR.FSE_VERSION_MINOR.FSE_VERSION_RELEASE
|
|
||||||
#define FSE_QUOTE(str) #str
|
|
||||||
#define FSE_EXPAND_AND_QUOTE(str) FSE_QUOTE(str)
|
|
||||||
#define FSE_VERSION_STRING FSE_EXPAND_AND_QUOTE(FSE_LIB_VERSION)
|
|
||||||
|
|
||||||
#define FSE_VERSION_NUMBER (FSE_VERSION_MAJOR * 100 * 100 + FSE_VERSION_MINOR * 100 + FSE_VERSION_RELEASE)
|
|
||||||
FSE_PUBLIC_API unsigned FSE_versionNumber(void); /**< library version number; to be used when checking dll version */
|
|
||||||
|
|
||||||
/*-*****************************************
|
|
||||||
* Tool functions
|
|
||||||
******************************************/
|
|
||||||
FSE_PUBLIC_API size_t FSE_compressBound(size_t size); /* maximum compressed size */
|
|
||||||
|
|
||||||
/* Error Management */
|
|
||||||
FSE_PUBLIC_API unsigned FSE_isError(size_t code); /* tells if a return value is an error code */
|
|
||||||
|
|
||||||
/*-*****************************************
|
|
||||||
* FSE detailed API
|
|
||||||
******************************************/
|
|
||||||
/*!
|
|
||||||
FSE_compress() does the following:
|
|
||||||
1. count symbol occurrence from source[] into table count[]
|
|
||||||
2. normalize counters so that sum(count[]) == Power_of_2 (2^tableLog)
|
|
||||||
3. save normalized counters to memory buffer using writeNCount()
|
|
||||||
4. build encoding table 'CTable' from normalized counters
|
|
||||||
5. encode the data stream using encoding table 'CTable'
|
|
||||||
|
|
||||||
FSE_decompress() does the following:
|
|
||||||
1. read normalized counters with readNCount()
|
|
||||||
2. build decoding table 'DTable' from normalized counters
|
|
||||||
3. decode the data stream using decoding table 'DTable'
|
|
||||||
|
|
||||||
The following API allows targeting specific sub-functions for advanced tasks.
|
|
||||||
For example, it's possible to compress several blocks using the same 'CTable',
|
|
||||||
or to save and provide normalized distribution using external method.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* *** COMPRESSION *** */
|
|
||||||
/*! FSE_optimalTableLog():
|
|
||||||
dynamically downsize 'tableLog' when conditions are met.
|
|
||||||
It saves CPU time, by using smaller tables, while preserving or even improving compression ratio.
|
|
||||||
@return : recommended tableLog (necessarily <= 'maxTableLog') */
|
|
||||||
FSE_PUBLIC_API unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue);
|
|
||||||
|
|
||||||
/*! FSE_normalizeCount():
|
|
||||||
normalize counts so that sum(count[]) == Power_of_2 (2^tableLog)
|
|
||||||
'normalizedCounter' is a table of short, of minimum size (maxSymbolValue+1).
|
|
||||||
@return : tableLog,
|
|
||||||
or an errorCode, which can be tested using FSE_isError() */
|
|
||||||
FSE_PUBLIC_API size_t FSE_normalizeCount(short *normalizedCounter, unsigned tableLog, const unsigned *count, size_t srcSize, unsigned maxSymbolValue);
|
|
||||||
|
|
||||||
/*! FSE_NCountWriteBound():
|
|
||||||
Provides the maximum possible size of an FSE normalized table, given 'maxSymbolValue' and 'tableLog'.
|
|
||||||
Typically useful for allocation purpose. */
|
|
||||||
FSE_PUBLIC_API size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog);
|
|
||||||
|
|
||||||
/*! FSE_writeNCount():
|
|
||||||
Compactly save 'normalizedCounter' into 'buffer'.
|
|
||||||
@return : size of the compressed table,
|
|
||||||
or an errorCode, which can be tested using FSE_isError(). */
|
|
||||||
FSE_PUBLIC_API size_t FSE_writeNCount(void *buffer, size_t bufferSize, const short *normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);
|
|
||||||
|
|
||||||
/*! Constructor and Destructor of FSE_CTable.
|
|
||||||
Note that FSE_CTable size depends on 'tableLog' and 'maxSymbolValue' */
|
|
||||||
typedef unsigned FSE_CTable; /* don't allocate that. It's only meant to be more restrictive than void* */
|
|
||||||
|
|
||||||
/*! FSE_compress_usingCTable():
|
|
||||||
Compress `src` using `ct` into `dst` which must be already allocated.
|
|
||||||
@return : size of compressed data (<= `dstCapacity`),
|
|
||||||
or 0 if compressed data could not fit into `dst`,
|
|
||||||
or an errorCode, which can be tested using FSE_isError() */
|
|
||||||
FSE_PUBLIC_API size_t FSE_compress_usingCTable(void *dst, size_t dstCapacity, const void *src, size_t srcSize, const FSE_CTable *ct);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Tutorial :
|
|
||||||
----------
|
|
||||||
The first step is to count all symbols. FSE_count() does this job very fast.
|
|
||||||
Result will be saved into 'count', a table of unsigned int, which must be already allocated, and have 'maxSymbolValuePtr[0]+1' cells.
|
|
||||||
'src' is a table of bytes of size 'srcSize'. All values within 'src' MUST be <= maxSymbolValuePtr[0]
|
|
||||||
maxSymbolValuePtr[0] will be updated, with its real value (necessarily <= original value)
|
|
||||||
FSE_count() will return the number of occurrence of the most frequent symbol.
|
|
||||||
This can be used to know if there is a single symbol within 'src', and to quickly evaluate its compressibility.
|
|
||||||
If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()).
|
|
||||||
|
|
||||||
The next step is to normalize the frequencies.
|
|
||||||
FSE_normalizeCount() will ensure that sum of frequencies is == 2 ^'tableLog'.
|
|
||||||
It also guarantees a minimum of 1 to any Symbol with frequency >= 1.
|
|
||||||
You can use 'tableLog'==0 to mean "use default tableLog value".
|
|
||||||
If you are unsure of which tableLog value to use, you can ask FSE_optimalTableLog(),
|
|
||||||
which will provide the optimal valid tableLog given sourceSize, maxSymbolValue, and a user-defined maximum (0 means "default").
|
|
||||||
|
|
||||||
The result of FSE_normalizeCount() will be saved into a table,
|
|
||||||
called 'normalizedCounter', which is a table of signed short.
|
|
||||||
'normalizedCounter' must be already allocated, and have at least 'maxSymbolValue+1' cells.
|
|
||||||
The return value is tableLog if everything proceeded as expected.
|
|
||||||
It is 0 if there is a single symbol within distribution.
|
|
||||||
If there is an error (ex: invalid tableLog value), the function will return an ErrorCode (which can be tested using FSE_isError()).
|
|
||||||
|
|
||||||
'normalizedCounter' can be saved in a compact manner to a memory area using FSE_writeNCount().
|
|
||||||
'buffer' must be already allocated.
|
|
||||||
For guaranteed success, buffer size must be at least FSE_headerBound().
|
|
||||||
The result of the function is the number of bytes written into 'buffer'.
|
|
||||||
If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError(); ex : buffer size too small).
|
|
||||||
|
|
||||||
'normalizedCounter' can then be used to create the compression table 'CTable'.
|
|
||||||
The space required by 'CTable' must be already allocated, using FSE_createCTable().
|
|
||||||
You can then use FSE_buildCTable() to fill 'CTable'.
|
|
||||||
If there is an error, both functions will return an ErrorCode (which can be tested using FSE_isError()).
|
|
||||||
|
|
||||||
'CTable' can then be used to compress 'src', with FSE_compress_usingCTable().
|
|
||||||
Similar to FSE_count(), the convention is that 'src' is assumed to be a table of char of size 'srcSize'
|
|
||||||
The function returns the size of compressed data (without header), necessarily <= `dstCapacity`.
|
|
||||||
If it returns '0', compressed data could not fit into 'dst'.
|
|
||||||
If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()).
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* *** DECOMPRESSION *** */
|
|
||||||
|
|
||||||
/*! FSE_readNCount():
|
|
||||||
Read compactly saved 'normalizedCounter' from 'rBuffer'.
|
|
||||||
@return : size read from 'rBuffer',
|
|
||||||
or an errorCode, which can be tested using FSE_isError().
|
|
||||||
maxSymbolValuePtr[0] and tableLogPtr[0] will also be updated with their respective values */
|
|
||||||
FSE_PUBLIC_API size_t FSE_readNCount(short *normalizedCounter, unsigned *maxSymbolValuePtr, unsigned *tableLogPtr, const void *rBuffer, size_t rBuffSize);
|
|
||||||
|
|
||||||
/*! Constructor and Destructor of FSE_DTable.
|
|
||||||
Note that its size depends on 'tableLog' */
|
|
||||||
typedef unsigned FSE_DTable; /* don't allocate that. It's just a way to be more restrictive than void* */
|
|
||||||
|
|
||||||
/*! FSE_buildDTable():
|
|
||||||
Builds 'dt', which must be already allocated, using FSE_createDTable().
|
|
||||||
return : 0, or an errorCode, which can be tested using FSE_isError() */
|
|
||||||
FSE_PUBLIC_API size_t FSE_buildDTable_wksp(FSE_DTable *dt, const short *normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void *workspace, size_t workspaceSize);
|
|
||||||
|
|
||||||
/*! FSE_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 FSE_isError() */
|
|
||||||
FSE_PUBLIC_API size_t FSE_decompress_usingDTable(void *dst, size_t dstCapacity, const void *cSrc, size_t cSrcSize, const FSE_DTable *dt);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Tutorial :
|
|
||||||
----------
|
|
||||||
(Note : these functions only decompress FSE-compressed blocks.
|
|
||||||
If block is uncompressed, use memcpy() instead
|
|
||||||
If block is a single repeated byte, use memset() instead )
|
|
||||||
|
|
||||||
The first step is to obtain the normalized frequencies of symbols.
|
|
||||||
This can be performed by FSE_readNCount() if it was saved using FSE_writeNCount().
|
|
||||||
'normalizedCounter' must be already allocated, and have at least 'maxSymbolValuePtr[0]+1' cells of signed short.
|
|
||||||
In practice, that means it's necessary to know 'maxSymbolValue' beforehand,
|
|
||||||
or size the table to handle worst case situations (typically 256).
|
|
||||||
FSE_readNCount() will provide 'tableLog' and 'maxSymbolValue'.
|
|
||||||
The result of FSE_readNCount() is the number of bytes read from 'rBuffer'.
|
|
||||||
Note that 'rBufferSize' must be at least 4 bytes, even if useful information is less than that.
|
|
||||||
If there is an error, the function will return an error code, which can be tested using FSE_isError().
|
|
||||||
|
|
||||||
The next step is to build the decompression tables 'FSE_DTable' from 'normalizedCounter'.
|
|
||||||
This is performed by the function FSE_buildDTable().
|
|
||||||
The space required by 'FSE_DTable' must be already allocated using FSE_createDTable().
|
|
||||||
If there is an error, the function will return an error code, which can be tested using FSE_isError().
|
|
||||||
|
|
||||||
`FSE_DTable` can then be used to decompress `cSrc`, with FSE_decompress_usingDTable().
|
|
||||||
`cSrcSize` must be strictly correct, otherwise decompression will fail.
|
|
||||||
FSE_decompress_usingDTable() result will tell how many bytes were regenerated (<=`dstCapacity`).
|
|
||||||
If there is an error, the function will return an error code, which can be tested using FSE_isError(). (ex: dst buffer too small)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* *** Dependency *** */
|
|
||||||
#include "bitstream.h"
|
|
||||||
|
|
||||||
/* *****************************************
|
|
||||||
* Static allocation
|
|
||||||
*******************************************/
|
|
||||||
/* FSE buffer bounds */
|
|
||||||
#define FSE_NCOUNTBOUND 512
|
|
||||||
#define FSE_BLOCKBOUND(size) (size + (size >> 7))
|
|
||||||
#define FSE_COMPRESSBOUND(size) (FSE_NCOUNTBOUND + FSE_BLOCKBOUND(size)) /* Macro version, useful for static allocation */
|
|
||||||
|
|
||||||
/* It is possible to statically allocate FSE CTable/DTable as a table of FSE_CTable/FSE_DTable using below macros */
|
|
||||||
#define FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) (1 + (1 << (maxTableLog - 1)) + ((maxSymbolValue + 1) * 2))
|
|
||||||
#define FSE_DTABLE_SIZE_U32(maxTableLog) (1 + (1 << maxTableLog))
|
|
||||||
|
|
||||||
/* *****************************************
|
|
||||||
* FSE advanced API
|
|
||||||
*******************************************/
|
|
||||||
/* FSE_count_wksp() :
|
|
||||||
* Same as FSE_count(), but using an externally provided scratch buffer.
|
|
||||||
* `workSpace` size must be table of >= `1024` unsigned
|
|
||||||
*/
|
|
||||||
size_t FSE_count_wksp(unsigned *count, unsigned *maxSymbolValuePtr, const void *source, size_t sourceSize, unsigned *workSpace);
|
|
||||||
|
|
||||||
/* FSE_countFast_wksp() :
|
|
||||||
* Same as FSE_countFast(), but using an externally provided scratch buffer.
|
|
||||||
* `workSpace` must be a table of minimum `1024` unsigned
|
|
||||||
*/
|
|
||||||
size_t FSE_countFast_wksp(unsigned *count, unsigned *maxSymbolValuePtr, const void *src, size_t srcSize, unsigned *workSpace);
|
|
||||||
|
|
||||||
/*! FSE_count_simple
|
|
||||||
* Same as FSE_countFast(), but does not use any additional memory (not even on stack).
|
|
||||||
* This function is unsafe, and will segfault if any value within `src` is `> *maxSymbolValuePtr` (presuming it's also the size of `count`).
|
|
||||||
*/
|
|
||||||
size_t FSE_count_simple(unsigned *count, unsigned *maxSymbolValuePtr, const void *src, size_t srcSize);
|
|
||||||
|
|
||||||
unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus);
|
|
||||||
/**< same as FSE_optimalTableLog(), which used `minus==2` */
|
|
||||||
|
|
||||||
size_t FSE_buildCTable_raw(FSE_CTable *ct, unsigned nbBits);
|
|
||||||
/**< build a fake FSE_CTable, designed for a flat distribution, where each symbol uses nbBits */
|
|
||||||
|
|
||||||
size_t FSE_buildCTable_rle(FSE_CTable *ct, unsigned char symbolValue);
|
|
||||||
/**< build a fake FSE_CTable, designed to compress always the same symbolValue */
|
|
||||||
|
|
||||||
/* FSE_buildCTable_wksp() :
|
|
||||||
* Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`).
|
|
||||||
* `wkspSize` must be >= `(1<<tableLog)`.
|
|
||||||
*/
|
|
||||||
size_t FSE_buildCTable_wksp(FSE_CTable *ct, const short *normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void *workSpace, size_t wkspSize);
|
|
||||||
|
|
||||||
size_t FSE_buildDTable_raw(FSE_DTable *dt, unsigned nbBits);
|
|
||||||
/**< build a fake FSE_DTable, designed to read a flat distribution where each symbol uses nbBits */
|
|
||||||
|
|
||||||
size_t FSE_buildDTable_rle(FSE_DTable *dt, unsigned char symbolValue);
|
|
||||||
/**< build a fake FSE_DTable, designed to always generate the same symbolValue */
|
|
||||||
|
|
||||||
size_t FSE_decompress_wksp(void *dst, size_t dstCapacity, const void *cSrc, size_t cSrcSize, unsigned maxLog, void *workspace, size_t workspaceSize);
|
|
||||||
/**< same as FSE_decompress(), using an externally allocated `workSpace` produced with `FSE_DTABLE_SIZE_U32(maxLog)` */
|
|
||||||
|
|
||||||
/* *****************************************
|
|
||||||
* FSE symbol compression API
|
|
||||||
*******************************************/
|
|
||||||
/*!
|
|
||||||
This API consists of small unitary functions, which highly benefit from being inlined.
|
|
||||||
Hence their body are included in next section.
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
ptrdiff_t value;
|
|
||||||
const void *stateTable;
|
|
||||||
const void *symbolTT;
|
|
||||||
unsigned stateLog;
|
|
||||||
} FSE_CState_t;
|
|
||||||
|
|
||||||
static void FSE_initCState(FSE_CState_t *CStatePtr, const FSE_CTable *ct);
|
|
||||||
|
|
||||||
static void FSE_encodeSymbol(BIT_CStream_t *bitC, FSE_CState_t *CStatePtr, unsigned symbol);
|
|
||||||
|
|
||||||
static void FSE_flushCState(BIT_CStream_t *bitC, const FSE_CState_t *CStatePtr);
|
|
||||||
|
|
||||||
/**<
|
|
||||||
These functions are inner components of FSE_compress_usingCTable().
|
|
||||||
They allow the creation of custom streams, mixing multiple tables and bit sources.
|
|
||||||
|
|
||||||
A key property to keep in mind is that encoding and decoding are done **in reverse direction**.
|
|
||||||
So the first symbol you will encode is the last you will decode, like a LIFO stack.
|
|
||||||
|
|
||||||
You will need a few variables to track your CStream. They are :
|
|
||||||
|
|
||||||
FSE_CTable ct; // Provided by FSE_buildCTable()
|
|
||||||
BIT_CStream_t bitStream; // bitStream tracking structure
|
|
||||||
FSE_CState_t state; // State tracking structure (can have several)
|
|
||||||
|
|
||||||
|
|
||||||
The first thing to do is to init bitStream and state.
|
|
||||||
size_t errorCode = BIT_initCStream(&bitStream, dstBuffer, maxDstSize);
|
|
||||||
FSE_initCState(&state, ct);
|
|
||||||
|
|
||||||
Note that BIT_initCStream() can produce an error code, so its result should be tested, using FSE_isError();
|
|
||||||
You can then encode your input data, byte after byte.
|
|
||||||
FSE_encodeSymbol() outputs a maximum of 'tableLog' bits at a time.
|
|
||||||
Remember decoding will be done in reverse direction.
|
|
||||||
FSE_encodeByte(&bitStream, &state, symbol);
|
|
||||||
|
|
||||||
At any time, you can also add any bit sequence.
|
|
||||||
Note : maximum allowed nbBits is 25, for compatibility with 32-bits decoders
|
|
||||||
BIT_addBits(&bitStream, bitField, nbBits);
|
|
||||||
|
|
||||||
The above methods don't commit data to memory, they just store it into local register, for speed.
|
|
||||||
Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
|
|
||||||
Writing data to memory is a manual operation, performed by the flushBits function.
|
|
||||||
BIT_flushBits(&bitStream);
|
|
||||||
|
|
||||||
Your last FSE encoding operation shall be to flush your last state value(s).
|
|
||||||
FSE_flushState(&bitStream, &state);
|
|
||||||
|
|
||||||
Finally, you must close the bitStream.
|
|
||||||
The function returns the size of CStream in bytes.
|
|
||||||
If data couldn't fit into dstBuffer, it will return a 0 ( == not compressible)
|
|
||||||
If there is an error, it returns an errorCode (which can be tested using FSE_isError()).
|
|
||||||
size_t size = BIT_closeCStream(&bitStream);
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* *****************************************
|
|
||||||
* FSE symbol decompression API
|
|
||||||
*******************************************/
|
|
||||||
typedef struct {
|
|
||||||
size_t state;
|
|
||||||
const void *table; /* precise table may vary, depending on U16 */
|
|
||||||
} FSE_DState_t;
|
|
||||||
|
|
||||||
static void FSE_initDState(FSE_DState_t *DStatePtr, BIT_DStream_t *bitD, const FSE_DTable *dt);
|
|
||||||
|
|
||||||
static unsigned char FSE_decodeSymbol(FSE_DState_t *DStatePtr, BIT_DStream_t *bitD);
|
|
||||||
|
|
||||||
static unsigned FSE_endOfDState(const FSE_DState_t *DStatePtr);
|
|
||||||
|
|
||||||
/**<
|
|
||||||
Let's now decompose FSE_decompress_usingDTable() into its unitary components.
|
|
||||||
You will decode FSE-encoded symbols from the bitStream,
|
|
||||||
and also any other bitFields you put in, **in reverse order**.
|
|
||||||
|
|
||||||
You will need a few variables to track your bitStream. They are :
|
|
||||||
|
|
||||||
BIT_DStream_t DStream; // Stream context
|
|
||||||
FSE_DState_t DState; // State context. Multiple ones are possible
|
|
||||||
FSE_DTable* DTablePtr; // Decoding table, provided by FSE_buildDTable()
|
|
||||||
|
|
||||||
The first thing to do is to init the bitStream.
|
|
||||||
errorCode = BIT_initDStream(&DStream, srcBuffer, srcSize);
|
|
||||||
|
|
||||||
You should then retrieve your initial state(s)
|
|
||||||
(in reverse flushing order if you have several ones) :
|
|
||||||
errorCode = FSE_initDState(&DState, &DStream, DTablePtr);
|
|
||||||
|
|
||||||
You can then decode your data, symbol after symbol.
|
|
||||||
For information the maximum number of bits read by FSE_decodeSymbol() is 'tableLog'.
|
|
||||||
Keep in mind that symbols are decoded in reverse order, like a LIFO stack (last in, first out).
|
|
||||||
unsigned char symbol = FSE_decodeSymbol(&DState, &DStream);
|
|
||||||
|
|
||||||
You can retrieve any bitfield you eventually stored into the bitStream (in reverse order)
|
|
||||||
Note : maximum allowed nbBits is 25, for 32-bits compatibility
|
|
||||||
size_t bitField = BIT_readBits(&DStream, nbBits);
|
|
||||||
|
|
||||||
All above operations only read from local register (which size depends on size_t).
|
|
||||||
Refueling the register from memory is manually performed by the reload method.
|
|
||||||
endSignal = FSE_reloadDStream(&DStream);
|
|
||||||
|
|
||||||
BIT_reloadDStream() result tells if there is still some more data to read from DStream.
|
|
||||||
BIT_DStream_unfinished : there is still some data left into the DStream.
|
|
||||||
BIT_DStream_endOfBuffer : Dstream reached end of buffer. Its container may no longer be completely filled.
|
|
||||||
BIT_DStream_completed : Dstream reached its exact end, corresponding in general to decompression completed.
|
|
||||||
BIT_DStream_tooFar : Dstream went too far. Decompression result is corrupted.
|
|
||||||
|
|
||||||
When reaching end of buffer (BIT_DStream_endOfBuffer), progress slowly, notably if you decode multiple symbols per loop,
|
|
||||||
to properly detect the exact end of stream.
|
|
||||||
After each decoded symbol, check if DStream is fully consumed using this simple test :
|
|
||||||
BIT_reloadDStream(&DStream) >= BIT_DStream_completed
|
|
||||||
|
|
||||||
When it's done, verify decompression is fully completed, by checking both DStream and the relevant states.
|
|
||||||
Checking if DStream has reached its end is performed by :
|
|
||||||
BIT_endOfDStream(&DStream);
|
|
||||||
Check also the states. There might be some symbols left there, if some high probability ones (>50%) are possible.
|
|
||||||
FSE_endOfDState(&DState);
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* *****************************************
|
|
||||||
* FSE unsafe API
|
|
||||||
*******************************************/
|
|
||||||
static unsigned char FSE_decodeSymbolFast(FSE_DState_t *DStatePtr, BIT_DStream_t *bitD);
|
|
||||||
/* faster, but works only if nbBits is always >= 1 (otherwise, result will be corrupted) */
|
|
||||||
|
|
||||||
/* *****************************************
|
|
||||||
* Implementation of inlined functions
|
|
||||||
*******************************************/
|
|
||||||
typedef struct {
|
|
||||||
int deltaFindState;
|
|
||||||
U32 deltaNbBits;
|
|
||||||
} FSE_symbolCompressionTransform; /* total 8 bytes */
|
|
||||||
|
|
||||||
ZSTD_STATIC void FSE_initCState(FSE_CState_t *statePtr, const FSE_CTable *ct)
|
|
||||||
{
|
|
||||||
const void *ptr = ct;
|
|
||||||
const U16 *u16ptr = (const U16 *)ptr;
|
|
||||||
const U32 tableLog = ZSTD_read16(ptr);
|
|
||||||
statePtr->value = (ptrdiff_t)1 << tableLog;
|
|
||||||
statePtr->stateTable = u16ptr + 2;
|
|
||||||
statePtr->symbolTT = ((const U32 *)ct + 1 + (tableLog ? (1 << (tableLog - 1)) : 1));
|
|
||||||
statePtr->stateLog = tableLog;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! FSE_initCState2() :
|
|
||||||
* Same as FSE_initCState(), but the first symbol to include (which will be the last to be read)
|
|
||||||
* uses the smallest state value possible, saving the cost of this symbol */
|
|
||||||
ZSTD_STATIC void FSE_initCState2(FSE_CState_t *statePtr, const FSE_CTable *ct, U32 symbol)
|
|
||||||
{
|
|
||||||
FSE_initCState(statePtr, ct);
|
|
||||||
{
|
|
||||||
const FSE_symbolCompressionTransform symbolTT = ((const FSE_symbolCompressionTransform *)(statePtr->symbolTT))[symbol];
|
|
||||||
const U16 *stateTable = (const U16 *)(statePtr->stateTable);
|
|
||||||
U32 nbBitsOut = (U32)((symbolTT.deltaNbBits + (1 << 15)) >> 16);
|
|
||||||
statePtr->value = (nbBitsOut << 16) - symbolTT.deltaNbBits;
|
|
||||||
statePtr->value = stateTable[(statePtr->value >> nbBitsOut) + symbolTT.deltaFindState];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ZSTD_STATIC void FSE_encodeSymbol(BIT_CStream_t *bitC, FSE_CState_t *statePtr, U32 symbol)
|
|
||||||
{
|
|
||||||
const FSE_symbolCompressionTransform symbolTT = ((const FSE_symbolCompressionTransform *)(statePtr->symbolTT))[symbol];
|
|
||||||
const U16 *const stateTable = (const U16 *)(statePtr->stateTable);
|
|
||||||
U32 nbBitsOut = (U32)((statePtr->value + symbolTT.deltaNbBits) >> 16);
|
|
||||||
BIT_addBits(bitC, statePtr->value, nbBitsOut);
|
|
||||||
statePtr->value = stateTable[(statePtr->value >> nbBitsOut) + symbolTT.deltaFindState];
|
|
||||||
}
|
|
||||||
|
|
||||||
ZSTD_STATIC void FSE_flushCState(BIT_CStream_t *bitC, const FSE_CState_t *statePtr)
|
|
||||||
{
|
|
||||||
BIT_addBits(bitC, statePtr->value, statePtr->stateLog);
|
|
||||||
BIT_flushBits(bitC);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ====== Decompression ====== */
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
U16 tableLog;
|
|
||||||
U16 fastMode;
|
|
||||||
} FSE_DTableHeader; /* sizeof U32 */
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
unsigned short newState;
|
|
||||||
unsigned char symbol;
|
|
||||||
unsigned char nbBits;
|
|
||||||
} FSE_decode_t; /* size == U32 */
|
|
||||||
|
|
||||||
ZSTD_STATIC void FSE_initDState(FSE_DState_t *DStatePtr, BIT_DStream_t *bitD, const FSE_DTable *dt)
|
|
||||||
{
|
|
||||||
const void *ptr = dt;
|
|
||||||
const FSE_DTableHeader *const DTableH = (const FSE_DTableHeader *)ptr;
|
|
||||||
DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog);
|
|
||||||
BIT_reloadDStream(bitD);
|
|
||||||
DStatePtr->table = dt + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ZSTD_STATIC BYTE FSE_peekSymbol(const FSE_DState_t *DStatePtr)
|
|
||||||
{
|
|
||||||
FSE_decode_t const DInfo = ((const FSE_decode_t *)(DStatePtr->table))[DStatePtr->state];
|
|
||||||
return DInfo.symbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
ZSTD_STATIC void FSE_updateState(FSE_DState_t *DStatePtr, BIT_DStream_t *bitD)
|
|
||||||
{
|
|
||||||
FSE_decode_t const DInfo = ((const FSE_decode_t *)(DStatePtr->table))[DStatePtr->state];
|
|
||||||
U32 const nbBits = DInfo.nbBits;
|
|
||||||
size_t const lowBits = BIT_readBits(bitD, nbBits);
|
|
||||||
DStatePtr->state = DInfo.newState + lowBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
ZSTD_STATIC BYTE FSE_decodeSymbol(FSE_DState_t *DStatePtr, BIT_DStream_t *bitD)
|
|
||||||
{
|
|
||||||
FSE_decode_t const DInfo = ((const FSE_decode_t *)(DStatePtr->table))[DStatePtr->state];
|
|
||||||
U32 const nbBits = DInfo.nbBits;
|
|
||||||
BYTE const symbol = DInfo.symbol;
|
|
||||||
size_t const lowBits = BIT_readBits(bitD, nbBits);
|
|
||||||
|
|
||||||
DStatePtr->state = DInfo.newState + lowBits;
|
|
||||||
return symbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! FSE_decodeSymbolFast() :
|
|
||||||
unsafe, only works if no symbol has a probability > 50% */
|
|
||||||
ZSTD_STATIC BYTE FSE_decodeSymbolFast(FSE_DState_t *DStatePtr, BIT_DStream_t *bitD)
|
|
||||||
{
|
|
||||||
FSE_decode_t const DInfo = ((const FSE_decode_t *)(DStatePtr->table))[DStatePtr->state];
|
|
||||||
U32 const nbBits = DInfo.nbBits;
|
|
||||||
BYTE const symbol = DInfo.symbol;
|
|
||||||
size_t const lowBits = BIT_readBitsFast(bitD, nbBits);
|
|
||||||
|
|
||||||
DStatePtr->state = DInfo.newState + lowBits;
|
|
||||||
return symbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
ZSTD_STATIC unsigned FSE_endOfDState(const FSE_DState_t *DStatePtr) { return DStatePtr->state == 0; }
|
|
||||||
|
|
||||||
/* **************************************************************
|
|
||||||
* 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 */
|
|
||||||
#ifndef FSE_MAX_MEMORY_USAGE
|
|
||||||
#define FSE_MAX_MEMORY_USAGE 14
|
|
||||||
#endif
|
|
||||||
#ifndef FSE_DEFAULT_MEMORY_USAGE
|
|
||||||
#define FSE_DEFAULT_MEMORY_USAGE 13
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*!FSE_MAX_SYMBOL_VALUE :
|
|
||||||
* Maximum symbol value authorized.
|
|
||||||
* Required for proper stack allocation */
|
|
||||||
#ifndef FSE_MAX_SYMBOL_VALUE
|
|
||||||
#define FSE_MAX_SYMBOL_VALUE 255
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* **************************************************************
|
|
||||||
* template functions type & suffix
|
|
||||||
****************************************************************/
|
|
||||||
#define FSE_FUNCTION_TYPE BYTE
|
|
||||||
#define FSE_FUNCTION_EXTENSION
|
|
||||||
#define FSE_DECODE_TYPE FSE_decode_t
|
|
||||||
|
|
||||||
/* ***************************************************************
|
|
||||||
* Constants
|
|
||||||
*****************************************************************/
|
|
||||||
#define FSE_MAX_TABLELOG (FSE_MAX_MEMORY_USAGE - 2)
|
|
||||||
#define FSE_MAX_TABLESIZE (1U << FSE_MAX_TABLELOG)
|
|
||||||
#define FSE_MAXTABLESIZE_MASK (FSE_MAX_TABLESIZE - 1)
|
|
||||||
#define FSE_DEFAULT_TABLELOG (FSE_DEFAULT_MEMORY_USAGE - 2)
|
|
||||||
#define FSE_MIN_TABLELOG 5
|
|
||||||
|
|
||||||
#define FSE_TABLELOG_ABSOLUTE_MAX 15
|
|
||||||
#if FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX
|
|
||||||
#error "FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX is not supported"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define FSE_TABLESTEP(tableSize) ((tableSize >> 1) + (tableSize >> 3) + 3)
|
|
||||||
|
|
||||||
#endif /* FSE_H */
|
|
|
@ -1,302 +0,0 @@
|
||||||
// SPDX-License-Identifier: (GPL-2.0 or BSD-2-Clause)
|
|
||||||
/*
|
|
||||||
* FSE : Finite State Entropy decoder
|
|
||||||
* Copyright (C) 2013-2015, Yann Collet.
|
|
||||||
*
|
|
||||||
* You can contact the author at :
|
|
||||||
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* **************************************************************
|
|
||||||
* Compiler specifics
|
|
||||||
****************************************************************/
|
|
||||||
#define FORCE_INLINE static __always_inline
|
|
||||||
|
|
||||||
/* **************************************************************
|
|
||||||
* Includes
|
|
||||||
****************************************************************/
|
|
||||||
#include "bitstream.h"
|
|
||||||
#include "fse.h"
|
|
||||||
#include <linux/compiler.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/string.h> /* memcpy, memset */
|
|
||||||
|
|
||||||
/* **************************************************************
|
|
||||||
* Error Management
|
|
||||||
****************************************************************/
|
|
||||||
#define FSE_isError ERR_isError
|
|
||||||
#define FSE_STATIC_ASSERT(c) \
|
|
||||||
{ \
|
|
||||||
enum { FSE_static_assert = 1 / (int)(!!(c)) }; \
|
|
||||||
} /* use only *after* variable declarations */
|
|
||||||
|
|
||||||
/* check and forward error code */
|
|
||||||
#define CHECK_F(f) \
|
|
||||||
{ \
|
|
||||||
size_t const e = f; \
|
|
||||||
if (FSE_isError(e)) \
|
|
||||||
return e; \
|
|
||||||
}
|
|
||||||
|
|
||||||
/* **************************************************************
|
|
||||||
* 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 FSE_FUNCTION_EXTENSION
|
|
||||||
#error "FSE_FUNCTION_EXTENSION must be defined"
|
|
||||||
#endif
|
|
||||||
#ifndef FSE_FUNCTION_TYPE
|
|
||||||
#error "FSE_FUNCTION_TYPE must be defined"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Function names */
|
|
||||||
#define FSE_CAT(X, Y) X##Y
|
|
||||||
#define FSE_FUNCTION_NAME(X, Y) FSE_CAT(X, Y)
|
|
||||||
#define FSE_TYPE_NAME(X, Y) FSE_CAT(X, Y)
|
|
||||||
|
|
||||||
/* Function templates */
|
|
||||||
|
|
||||||
size_t FSE_buildDTable_wksp(FSE_DTable *dt, const short *normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void *workspace, size_t workspaceSize)
|
|
||||||
{
|
|
||||||
void *const tdPtr = dt + 1; /* because *dt is unsigned, 32-bits aligned on 32-bits */
|
|
||||||
FSE_DECODE_TYPE *const tableDecode = (FSE_DECODE_TYPE *)(tdPtr);
|
|
||||||
U16 *symbolNext = (U16 *)workspace;
|
|
||||||
|
|
||||||
U32 const maxSV1 = maxSymbolValue + 1;
|
|
||||||
U32 const tableSize = 1 << tableLog;
|
|
||||||
U32 highThreshold = tableSize - 1;
|
|
||||||
|
|
||||||
/* Sanity Checks */
|
|
||||||
if (workspaceSize < sizeof(U16) * (FSE_MAX_SYMBOL_VALUE + 1))
|
|
||||||
return ERROR(tableLog_tooLarge);
|
|
||||||
if (maxSymbolValue > FSE_MAX_SYMBOL_VALUE)
|
|
||||||
return ERROR(maxSymbolValue_tooLarge);
|
|
||||||
if (tableLog > FSE_MAX_TABLELOG)
|
|
||||||
return ERROR(tableLog_tooLarge);
|
|
||||||
|
|
||||||
/* Init, lay down lowprob symbols */
|
|
||||||
{
|
|
||||||
FSE_DTableHeader DTableH;
|
|
||||||
DTableH.tableLog = (U16)tableLog;
|
|
||||||
DTableH.fastMode = 1;
|
|
||||||
{
|
|
||||||
S16 const largeLimit = (S16)(1 << (tableLog - 1));
|
|
||||||
U32 s;
|
|
||||||
for (s = 0; s < maxSV1; s++) {
|
|
||||||
if (normalizedCounter[s] == -1) {
|
|
||||||
tableDecode[highThreshold--].symbol = (FSE_FUNCTION_TYPE)s;
|
|
||||||
symbolNext[s] = 1;
|
|
||||||
} else {
|
|
||||||
if (normalizedCounter[s] >= largeLimit)
|
|
||||||
DTableH.fastMode = 0;
|
|
||||||
symbolNext[s] = normalizedCounter[s];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
memcpy(dt, &DTableH, sizeof(DTableH));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Spread symbols */
|
|
||||||
{
|
|
||||||
U32 const tableMask = tableSize - 1;
|
|
||||||
U32 const step = FSE_TABLESTEP(tableSize);
|
|
||||||
U32 s, position = 0;
|
|
||||||
for (s = 0; s < maxSV1; s++) {
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < normalizedCounter[s]; i++) {
|
|
||||||
tableDecode[position].symbol = (FSE_FUNCTION_TYPE)s;
|
|
||||||
position = (position + step) & tableMask;
|
|
||||||
while (position > 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; u < tableSize; u++) {
|
|
||||||
FSE_FUNCTION_TYPE const symbol = (FSE_FUNCTION_TYPE)(tableDecode[u].symbol);
|
|
||||||
U16 nextState = symbolNext[symbol]++;
|
|
||||||
tableDecode[u].nbBits = (BYTE)(tableLog - BIT_highbit32((U32)nextState));
|
|
||||||
tableDecode[u].newState = (U16)((nextState << tableDecode[u].nbBits) - tableSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-*******************************************************
|
|
||||||
* Decompression (Byte symbols)
|
|
||||||
*********************************************************/
|
|
||||||
size_t FSE_buildDTable_rle(FSE_DTable *dt, BYTE symbolValue)
|
|
||||||
{
|
|
||||||
void *ptr = dt;
|
|
||||||
FSE_DTableHeader *const DTableH = (FSE_DTableHeader *)ptr;
|
|
||||||
void *dPtr = dt + 1;
|
|
||||||
FSE_decode_t *const cell = (FSE_decode_t *)dPtr;
|
|
||||||
|
|
||||||
DTableH->tableLog = 0;
|
|
||||||
DTableH->fastMode = 0;
|
|
||||||
|
|
||||||
cell->newState = 0;
|
|
||||||
cell->symbol = symbolValue;
|
|
||||||
cell->nbBits = 0;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t FSE_buildDTable_raw(FSE_DTable *dt, unsigned nbBits)
|
|
||||||
{
|
|
||||||
void *ptr = dt;
|
|
||||||
FSE_DTableHeader *const DTableH = (FSE_DTableHeader *)ptr;
|
|
||||||
void *dPtr = dt + 1;
|
|
||||||
FSE_decode_t *const dinfo = (FSE_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 < maxSV1; s++) {
|
|
||||||
dinfo[s].newState = 0;
|
|
||||||
dinfo[s].symbol = (BYTE)s;
|
|
||||||
dinfo[s].nbBits = (BYTE)nbBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
FORCE_INLINE size_t FSE_decompress_usingDTable_generic(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const FSE_DTable *dt,
|
|
||||||
const unsigned fast)
|
|
||||||
{
|
|
||||||
BYTE *const ostart = (BYTE *)dst;
|
|
||||||
BYTE *op = ostart;
|
|
||||||
BYTE *const omax = op + maxDstSize;
|
|
||||||
BYTE *const olimit = omax - 3;
|
|
||||||
|
|
||||||
BIT_DStream_t bitD;
|
|
||||||
FSE_DState_t state1;
|
|
||||||
FSE_DState_t state2;
|
|
||||||
|
|
||||||
/* Init */
|
|
||||||
CHECK_F(BIT_initDStream(&bitD, cSrc, cSrcSize));
|
|
||||||
|
|
||||||
FSE_initDState(&state1, &bitD, dt);
|
|
||||||
FSE_initDState(&state2, &bitD, dt);
|
|
||||||
|
|
||||||
#define FSE_GETSYMBOL(statePtr) fast ? FSE_decodeSymbolFast(statePtr, &bitD) : FSE_decodeSymbol(statePtr, &bitD)
|
|
||||||
|
|
||||||
/* 4 symbols per loop */
|
|
||||||
for (; (BIT_reloadDStream(&bitD) == BIT_DStream_unfinished) & (op < olimit); op += 4) {
|
|
||||||
op[0] = FSE_GETSYMBOL(&state1);
|
|
||||||
|
|
||||||
if (FSE_MAX_TABLELOG * 2 + 7 > sizeof(bitD.bitContainer) * 8) /* This test must be static */
|
|
||||||
BIT_reloadDStream(&bitD);
|
|
||||||
|
|
||||||
op[1] = FSE_GETSYMBOL(&state2);
|
|
||||||
|
|
||||||
if (FSE_MAX_TABLELOG * 4 + 7 > sizeof(bitD.bitContainer) * 8) /* This test must be static */
|
|
||||||
{
|
|
||||||
if (BIT_reloadDStream(&bitD) > BIT_DStream_unfinished) {
|
|
||||||
op += 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
op[2] = FSE_GETSYMBOL(&state1);
|
|
||||||
|
|
||||||
if (FSE_MAX_TABLELOG * 2 + 7 > sizeof(bitD.bitContainer) * 8) /* This test must be static */
|
|
||||||
BIT_reloadDStream(&bitD);
|
|
||||||
|
|
||||||
op[3] = FSE_GETSYMBOL(&state2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* tail */
|
|
||||||
/* note : BIT_reloadDStream(&bitD) >= FSE_DStream_partiallyFilled; Ends at exactly BIT_DStream_completed */
|
|
||||||
while (1) {
|
|
||||||
if (op > (omax - 2))
|
|
||||||
return ERROR(dstSize_tooSmall);
|
|
||||||
*op++ = FSE_GETSYMBOL(&state1);
|
|
||||||
if (BIT_reloadDStream(&bitD) == BIT_DStream_overflow) {
|
|
||||||
*op++ = FSE_GETSYMBOL(&state2);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (op > (omax - 2))
|
|
||||||
return ERROR(dstSize_tooSmall);
|
|
||||||
*op++ = FSE_GETSYMBOL(&state2);
|
|
||||||
if (BIT_reloadDStream(&bitD) == BIT_DStream_overflow) {
|
|
||||||
*op++ = FSE_GETSYMBOL(&state1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return op - ostart;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t FSE_decompress_usingDTable(void *dst, size_t originalSize, const void *cSrc, size_t cSrcSize, const FSE_DTable *dt)
|
|
||||||
{
|
|
||||||
const void *ptr = dt;
|
|
||||||
const FSE_DTableHeader *DTableH = (const FSE_DTableHeader *)ptr;
|
|
||||||
const U32 fastMode = DTableH->fastMode;
|
|
||||||
|
|
||||||
/* select fast mode (static) */
|
|
||||||
if (fastMode)
|
|
||||||
return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 1);
|
|
||||||
return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t FSE_decompress_wksp(void *dst, size_t dstCapacity, const void *cSrc, size_t cSrcSize, unsigned maxLog, void *workspace, size_t workspaceSize)
|
|
||||||
{
|
|
||||||
const BYTE *const istart = (const BYTE *)cSrc;
|
|
||||||
const BYTE *ip = istart;
|
|
||||||
unsigned tableLog;
|
|
||||||
unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE;
|
|
||||||
size_t NCountLength;
|
|
||||||
|
|
||||||
FSE_DTable *dt;
|
|
||||||
short *counting;
|
|
||||||
size_t spaceUsed32 = 0;
|
|
||||||
|
|
||||||
FSE_STATIC_ASSERT(sizeof(FSE_DTable) == sizeof(U32));
|
|
||||||
|
|
||||||
dt = (FSE_DTable *)((U32 *)workspace + spaceUsed32);
|
|
||||||
spaceUsed32 += FSE_DTABLE_SIZE_U32(maxLog);
|
|
||||||
counting = (short *)((U32 *)workspace + spaceUsed32);
|
|
||||||
spaceUsed32 += ALIGN(sizeof(short) * (FSE_MAX_SYMBOL_VALUE + 1), sizeof(U32)) >> 2;
|
|
||||||
|
|
||||||
if ((spaceUsed32 << 2) > workspaceSize)
|
|
||||||
return ERROR(tableLog_tooLarge);
|
|
||||||
workspace = (U32 *)workspace + spaceUsed32;
|
|
||||||
workspaceSize -= (spaceUsed32 << 2);
|
|
||||||
|
|
||||||
/* normal FSE decoding mode */
|
|
||||||
NCountLength = FSE_readNCount(counting, &maxSymbolValue, &tableLog, istart, cSrcSize);
|
|
||||||
if (FSE_isError(NCountLength))
|
|
||||||
return NCountLength;
|
|
||||||
// if (NCountLength >= cSrcSize) return ERROR(srcSize_wrong); /* too small input size; supposed to be already checked in NCountLength, only remaining
|
|
||||||
// case : NCountLength==cSrcSize */
|
|
||||||
if (tableLog > maxLog)
|
|
||||||
return ERROR(tableLog_tooLarge);
|
|
||||||
ip += NCountLength;
|
|
||||||
cSrcSize -= NCountLength;
|
|
||||||
|
|
||||||
CHECK_F(FSE_buildDTable_wksp(dt, counting, maxSymbolValue, tableLog, workspace, workspaceSize));
|
|
||||||
|
|
||||||
return FSE_decompress_usingDTable(dst, dstCapacity, ip, cSrcSize, dt); /* always return, even if it is an error code */
|
|
||||||
}
|
|
182
lib/zstd/huf.h
182
lib/zstd/huf.h
|
@ -1,182 +0,0 @@
|
||||||
/* SPDX-License-Identifier: (GPL-2.0 or BSD-2-Clause) */
|
|
||||||
/*
|
|
||||||
* Huffman coder, part of New Generation Entropy library
|
|
||||||
* header file
|
|
||||||
* Copyright (C) 2013-2016, Yann Collet.
|
|
||||||
*
|
|
||||||
* You can contact the author at :
|
|
||||||
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
|
||||||
*/
|
|
||||||
#ifndef HUF_H_298734234
|
|
||||||
#define HUF_H_298734234
|
|
||||||
|
|
||||||
/* *** Dependencies *** */
|
|
||||||
#include <linux/types.h> /* size_t */
|
|
||||||
|
|
||||||
/* *** Tool functions *** */
|
|
||||||
#define HUF_BLOCKSIZE_MAX (128 * 1024) /**< maximum input size for a single block compressed with HUF_compress */
|
|
||||||
size_t HUF_compressBound(size_t size); /**< maximum compressed size (worst case) */
|
|
||||||
|
|
||||||
/* Error Management */
|
|
||||||
unsigned HUF_isError(size_t code); /**< tells if a return value is an error code */
|
|
||||||
|
|
||||||
/* *** Advanced function *** */
|
|
||||||
|
|
||||||
/** HUF_compress4X_wksp() :
|
|
||||||
* Same as HUF_compress2(), but uses externally allocated `workSpace`, which must be a table of >= 1024 unsigned */
|
|
||||||
size_t HUF_compress4X_wksp(void *dst, size_t dstSize, const void *src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void *workSpace,
|
|
||||||
size_t wkspSize); /**< `workSpace` must be a table of at least HUF_COMPRESS_WORKSPACE_SIZE_U32 unsigned */
|
|
||||||
|
|
||||||
/* *** Dependencies *** */
|
|
||||||
#include "mem.h" /* U32 */
|
|
||||||
|
|
||||||
/* *** Constants *** */
|
|
||||||
#define HUF_TABLELOG_MAX 12 /* max configured tableLog (for static allocation); can be modified up to HUF_ABSOLUTEMAX_TABLELOG */
|
|
||||||
#define HUF_TABLELOG_DEFAULT 11 /* tableLog by default, when not specified */
|
|
||||||
#define HUF_SYMBOLVALUE_MAX 255
|
|
||||||
|
|
||||||
#define HUF_TABLELOG_ABSOLUTEMAX 15 /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */
|
|
||||||
#if (HUF_TABLELOG_MAX > HUF_TABLELOG_ABSOLUTEMAX)
|
|
||||||
#error "HUF_TABLELOG_MAX is too large !"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* ****************************************
|
|
||||||
* Static allocation
|
|
||||||
******************************************/
|
|
||||||
/* HUF buffer bounds */
|
|
||||||
#define HUF_CTABLEBOUND 129
|
|
||||||
#define HUF_BLOCKBOUND(size) (size + (size >> 8) + 8) /* only true if incompressible pre-filtered with fast heuristic */
|
|
||||||
#define HUF_COMPRESSBOUND(size) (HUF_CTABLEBOUND + HUF_BLOCKBOUND(size)) /* Macro version, useful for static allocation */
|
|
||||||
|
|
||||||
/* static allocation of HUF's Compression Table */
|
|
||||||
#define HUF_CREATE_STATIC_CTABLE(name, maxSymbolValue) \
|
|
||||||
U32 name##hb[maxSymbolValue + 1]; \
|
|
||||||
void *name##hv = &(name##hb); \
|
|
||||||
HUF_CElt *name = (HUF_CElt *)(name##hv) /* no final ; */
|
|
||||||
|
|
||||||
/* static allocation of HUF's DTable */
|
|
||||||
typedef U32 HUF_DTable;
|
|
||||||
#define HUF_DTABLE_SIZE(maxTableLog) (1 + (1 << (maxTableLog)))
|
|
||||||
#define HUF_CREATE_STATIC_DTABLEX2(DTable, maxTableLog) HUF_DTable DTable[HUF_DTABLE_SIZE((maxTableLog)-1)] = {((U32)((maxTableLog)-1) * 0x01000001)}
|
|
||||||
#define HUF_CREATE_STATIC_DTABLEX4(DTable, maxTableLog) HUF_DTable DTable[HUF_DTABLE_SIZE(maxTableLog)] = {((U32)(maxTableLog)*0x01000001)}
|
|
||||||
|
|
||||||
/* The workspace must have alignment at least 4 and be at least this large */
|
|
||||||
#define HUF_COMPRESS_WORKSPACE_SIZE (6 << 10)
|
|
||||||
#define HUF_COMPRESS_WORKSPACE_SIZE_U32 (HUF_COMPRESS_WORKSPACE_SIZE / sizeof(U32))
|
|
||||||
|
|
||||||
/* The workspace must have alignment at least 4 and be at least this large */
|
|
||||||
#define HUF_DECOMPRESS_WORKSPACE_SIZE (3 << 10)
|
|
||||||
#define HUF_DECOMPRESS_WORKSPACE_SIZE_U32 (HUF_DECOMPRESS_WORKSPACE_SIZE / sizeof(U32))
|
|
||||||
|
|
||||||
/* ****************************************
|
|
||||||
* Advanced decompression functions
|
|
||||||
******************************************/
|
|
||||||
size_t HUF_decompress4X_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize); /**< decodes RLE and uncompressed */
|
|
||||||
size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace,
|
|
||||||
size_t workspaceSize); /**< considers RLE and uncompressed as errors */
|
|
||||||
size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace,
|
|
||||||
size_t workspaceSize); /**< single-symbol decoder */
|
|
||||||
size_t HUF_decompress4X4_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace,
|
|
||||||
size_t workspaceSize); /**< double-symbols decoder */
|
|
||||||
|
|
||||||
/* ****************************************
|
|
||||||
* HUF detailed API
|
|
||||||
******************************************/
|
|
||||||
/*!
|
|
||||||
HUF_compress() does the following:
|
|
||||||
1. count symbol occurrence from source[] into table count[] using FSE_count()
|
|
||||||
2. (optional) refine tableLog using HUF_optimalTableLog()
|
|
||||||
3. build Huffman table from count using HUF_buildCTable()
|
|
||||||
4. save Huffman table to memory buffer using HUF_writeCTable_wksp()
|
|
||||||
5. encode the data stream using HUF_compress4X_usingCTable()
|
|
||||||
|
|
||||||
The following API allows targeting specific sub-functions for advanced tasks.
|
|
||||||
For example, it's possible to compress several blocks using the same 'CTable',
|
|
||||||
or to save and regenerate 'CTable' using external methods.
|
|
||||||
*/
|
|
||||||
/* FSE_count() : find it within "fse.h" */
|
|
||||||
unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue);
|
|
||||||
typedef struct HUF_CElt_s HUF_CElt; /* incomplete type */
|
|
||||||
size_t HUF_writeCTable_wksp(void *dst, size_t maxDstSize, const HUF_CElt *CTable, unsigned maxSymbolValue, unsigned huffLog, void *workspace, size_t workspaceSize);
|
|
||||||
size_t HUF_compress4X_usingCTable(void *dst, size_t dstSize, const void *src, size_t srcSize, const HUF_CElt *CTable);
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
HUF_repeat_none, /**< Cannot use the previous table */
|
|
||||||
HUF_repeat_check, /**< Can use the previous table but it must be checked. Note : The previous table must have been constructed by HUF_compress{1,
|
|
||||||
4}X_repeat */
|
|
||||||
HUF_repeat_valid /**< Can use the previous table and it is asumed to be valid */
|
|
||||||
} HUF_repeat;
|
|
||||||
/** HUF_compress4X_repeat() :
|
|
||||||
* Same as HUF_compress4X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none.
|
|
||||||
* If it uses hufTable it does not modify hufTable or repeat.
|
|
||||||
* If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
|
|
||||||
* If preferRepeat then the old table will always be used if valid. */
|
|
||||||
size_t HUF_compress4X_repeat(void *dst, size_t dstSize, const void *src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void *workSpace,
|
|
||||||
size_t wkspSize, HUF_CElt *hufTable, HUF_repeat *repeat,
|
|
||||||
int preferRepeat); /**< `workSpace` must be a table of at least HUF_COMPRESS_WORKSPACE_SIZE_U32 unsigned */
|
|
||||||
|
|
||||||
/** HUF_buildCTable_wksp() :
|
|
||||||
* Same as HUF_buildCTable(), but using externally allocated scratch buffer.
|
|
||||||
* `workSpace` must be aligned on 4-bytes boundaries, and be at least as large as a table of 1024 unsigned.
|
|
||||||
*/
|
|
||||||
size_t HUF_buildCTable_wksp(HUF_CElt *tree, const U32 *count, U32 maxSymbolValue, U32 maxNbBits, void *workSpace, size_t wkspSize);
|
|
||||||
|
|
||||||
/*! HUF_readStats() :
|
|
||||||
Read compact Huffman tree, saved by HUF_writeCTable().
|
|
||||||
`huffWeight` is destination buffer.
|
|
||||||
@return : size read from `src` , or an error Code .
|
|
||||||
Note : Needed by HUF_readCTable() and HUF_readDTableXn() . */
|
|
||||||
size_t HUF_readStats_wksp(BYTE *huffWeight, size_t hwSize, U32 *rankStats, U32 *nbSymbolsPtr, U32 *tableLogPtr, const void *src, size_t srcSize,
|
|
||||||
void *workspace, size_t workspaceSize);
|
|
||||||
|
|
||||||
/** HUF_readCTable() :
|
|
||||||
* Loading a CTable saved with HUF_writeCTable() */
|
|
||||||
size_t HUF_readCTable_wksp(HUF_CElt *CTable, unsigned maxSymbolValue, const void *src, size_t srcSize, void *workspace, size_t workspaceSize);
|
|
||||||
|
|
||||||
/*
|
|
||||||
HUF_decompress() does the following:
|
|
||||||
1. select the decompression algorithm (X2, X4) based on pre-computed heuristics
|
|
||||||
2. build Huffman table from save, using HUF_readDTableXn()
|
|
||||||
3. decode 1 or 4 segments in parallel using HUF_decompressSXn_usingDTable
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** HUF_selectDecoder() :
|
|
||||||
* Tells which decoder is likely to decode faster,
|
|
||||||
* based on a set of pre-determined metrics.
|
|
||||||
* @return : 0==HUF_decompress4X2, 1==HUF_decompress4X4 .
|
|
||||||
* Assumption : 0 < cSrcSize < dstSize <= 128 KB */
|
|
||||||
U32 HUF_selectDecoder(size_t dstSize, size_t cSrcSize);
|
|
||||||
|
|
||||||
size_t HUF_readDTableX2_wksp(HUF_DTable *DTable, const void *src, size_t srcSize, void *workspace, size_t workspaceSize);
|
|
||||||
size_t HUF_readDTableX4_wksp(HUF_DTable *DTable, const void *src, size_t srcSize, void *workspace, size_t workspaceSize);
|
|
||||||
|
|
||||||
size_t HUF_decompress4X_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable);
|
|
||||||
size_t HUF_decompress4X2_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable);
|
|
||||||
size_t HUF_decompress4X4_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable);
|
|
||||||
|
|
||||||
/* single stream variants */
|
|
||||||
|
|
||||||
size_t HUF_compress1X_wksp(void *dst, size_t dstSize, const void *src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void *workSpace,
|
|
||||||
size_t wkspSize); /**< `workSpace` must be a table of at least HUF_COMPRESS_WORKSPACE_SIZE_U32 unsigned */
|
|
||||||
size_t HUF_compress1X_usingCTable(void *dst, size_t dstSize, const void *src, size_t srcSize, const HUF_CElt *CTable);
|
|
||||||
/** HUF_compress1X_repeat() :
|
|
||||||
* Same as HUF_compress1X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none.
|
|
||||||
* If it uses hufTable it does not modify hufTable or repeat.
|
|
||||||
* If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
|
|
||||||
* If preferRepeat then the old table will always be used if valid. */
|
|
||||||
size_t HUF_compress1X_repeat(void *dst, size_t dstSize, const void *src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void *workSpace,
|
|
||||||
size_t wkspSize, HUF_CElt *hufTable, HUF_repeat *repeat,
|
|
||||||
int preferRepeat); /**< `workSpace` must be a table of at least HUF_COMPRESS_WORKSPACE_SIZE_U32 unsigned */
|
|
||||||
|
|
||||||
size_t HUF_decompress1X_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize);
|
|
||||||
size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace,
|
|
||||||
size_t workspaceSize); /**< single-symbol decoder */
|
|
||||||
size_t HUF_decompress1X4_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace,
|
|
||||||
size_t workspaceSize); /**< double-symbols decoder */
|
|
||||||
|
|
||||||
size_t HUF_decompress1X_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize,
|
|
||||||
const HUF_DTable *DTable); /**< automatic selection of sing or double symbol decoder, based on DTable */
|
|
||||||
size_t HUF_decompress1X2_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable);
|
|
||||||
size_t HUF_decompress1X4_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable);
|
|
||||||
|
|
||||||
#endif /* HUF_H_298734234 */
|
|
|
@ -1,930 +0,0 @@
|
||||||
// SPDX-License-Identifier: (GPL-2.0 or BSD-2-Clause)
|
|
||||||
/*
|
|
||||||
* Huffman decoder, part of New Generation Entropy library
|
|
||||||
* Copyright (C) 2013-2016, Yann Collet.
|
|
||||||
*
|
|
||||||
* You can contact the author at :
|
|
||||||
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* **************************************************************
|
|
||||||
* Compiler specifics
|
|
||||||
****************************************************************/
|
|
||||||
#define FORCE_INLINE static __always_inline
|
|
||||||
|
|
||||||
/* **************************************************************
|
|
||||||
* Dependencies
|
|
||||||
****************************************************************/
|
|
||||||
#include "bitstream.h" /* BIT_* */
|
|
||||||
#include "fse.h" /* header compression */
|
|
||||||
#include "huf.h"
|
|
||||||
#include <linux/compiler.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/string.h> /* memcpy, memset */
|
|
||||||
|
|
||||||
/* **************************************************************
|
|
||||||
* Error Management
|
|
||||||
****************************************************************/
|
|
||||||
#define HUF_STATIC_ASSERT(c) \
|
|
||||||
{ \
|
|
||||||
enum { HUF_static_assert = 1 / (int)(!!(c)) }; \
|
|
||||||
} /* use only *after* variable declarations */
|
|
||||||
|
|
||||||
/*-***************************/
|
|
||||||
/* generic DTableDesc */
|
|
||||||
/*-***************************/
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
BYTE maxTableLog;
|
|
||||||
BYTE tableType;
|
|
||||||
BYTE tableLog;
|
|
||||||
BYTE reserved;
|
|
||||||
} DTableDesc;
|
|
||||||
|
|
||||||
static DTableDesc HUF_getDTableDesc(const HUF_DTable *table)
|
|
||||||
{
|
|
||||||
DTableDesc dtd;
|
|
||||||
memcpy(&dtd, table, sizeof(dtd));
|
|
||||||
return dtd;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-***************************/
|
|
||||||
/* single-symbol decoding */
|
|
||||||
/*-***************************/
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
BYTE byte;
|
|
||||||
BYTE nbBits;
|
|
||||||
} HUF_DEltX2; /* single-symbol decoding */
|
|
||||||
|
|
||||||
size_t HUF_readDTableX2_wksp(HUF_DTable *DTable, const void *src, size_t srcSize, void *workspace, size_t workspaceSize)
|
|
||||||
{
|
|
||||||
U32 tableLog = 0;
|
|
||||||
U32 nbSymbols = 0;
|
|
||||||
size_t iSize;
|
|
||||||
void *const dtPtr = DTable + 1;
|
|
||||||
HUF_DEltX2 *const dt = (HUF_DEltX2 *)dtPtr;
|
|
||||||
|
|
||||||
U32 *rankVal;
|
|
||||||
BYTE *huffWeight;
|
|
||||||
size_t spaceUsed32 = 0;
|
|
||||||
|
|
||||||
rankVal = (U32 *)workspace + spaceUsed32;
|
|
||||||
spaceUsed32 += HUF_TABLELOG_ABSOLUTEMAX + 1;
|
|
||||||
huffWeight = (BYTE *)((U32 *)workspace + spaceUsed32);
|
|
||||||
spaceUsed32 += ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2;
|
|
||||||
|
|
||||||
if ((spaceUsed32 << 2) > workspaceSize)
|
|
||||||
return ERROR(tableLog_tooLarge);
|
|
||||||
workspace = (U32 *)workspace + spaceUsed32;
|
|
||||||
workspaceSize -= (spaceUsed32 << 2);
|
|
||||||
|
|
||||||
HUF_STATIC_ASSERT(sizeof(DTableDesc) == sizeof(HUF_DTable));
|
|
||||||
/* memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */
|
|
||||||
|
|
||||||
iSize = HUF_readStats_wksp(huffWeight, HUF_SYMBOLVALUE_MAX + 1, rankVal, &nbSymbols, &tableLog, src, srcSize, workspace, workspaceSize);
|
|
||||||
if (HUF_isError(iSize))
|
|
||||||
return iSize;
|
|
||||||
|
|
||||||
/* Table header */
|
|
||||||
{
|
|
||||||
DTableDesc dtd = HUF_getDTableDesc(DTable);
|
|
||||||
if (tableLog > (U32)(dtd.maxTableLog + 1))
|
|
||||||
return ERROR(tableLog_tooLarge); /* DTable too small, Huffman tree cannot fit in */
|
|
||||||
dtd.tableType = 0;
|
|
||||||
dtd.tableLog = (BYTE)tableLog;
|
|
||||||
memcpy(DTable, &dtd, sizeof(dtd));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Calculate starting value for each rank */
|
|
||||||
{
|
|
||||||
U32 n, nextRankStart = 0;
|
|
||||||
for (n = 1; n < tableLog + 1; n++) {
|
|
||||||
U32 const curr = nextRankStart;
|
|
||||||
nextRankStart += (rankVal[n] << (n - 1));
|
|
||||||
rankVal[n] = curr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fill DTable */
|
|
||||||
{
|
|
||||||
U32 n;
|
|
||||||
for (n = 0; n < nbSymbols; n++) {
|
|
||||||
U32 const w = huffWeight[n];
|
|
||||||
U32 const length = (1 << w) >> 1;
|
|
||||||
U32 u;
|
|
||||||
HUF_DEltX2 D;
|
|
||||||
D.byte = (BYTE)n;
|
|
||||||
D.nbBits = (BYTE)(tableLog + 1 - w);
|
|
||||||
for (u = rankVal[w]; u < rankVal[w] + length; u++)
|
|
||||||
dt[u] = D;
|
|
||||||
rankVal[w] += length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return iSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BYTE HUF_decodeSymbolX2(BIT_DStream_t *Dstream, const HUF_DEltX2 *dt, const U32 dtLog)
|
|
||||||
{
|
|
||||||
size_t const val = BIT_lookBitsFast(Dstream, dtLog); /* note : dtLog >= 1 */
|
|
||||||
BYTE const c = dt[val].byte;
|
|
||||||
BIT_skipBits(Dstream, dt[val].nbBits);
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr) *ptr++ = HUF_decodeSymbolX2(DStreamPtr, dt, dtLog)
|
|
||||||
|
|
||||||
#define HUF_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \
|
|
||||||
if (ZSTD_64bits() || (HUF_TABLELOG_MAX <= 12)) \
|
|
||||||
HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr)
|
|
||||||
|
|
||||||
#define HUF_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \
|
|
||||||
if (ZSTD_64bits()) \
|
|
||||||
HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr)
|
|
||||||
|
|
||||||
FORCE_INLINE size_t HUF_decodeStreamX2(BYTE *p, BIT_DStream_t *const bitDPtr, BYTE *const pEnd, const HUF_DEltX2 *const dt, const U32 dtLog)
|
|
||||||
{
|
|
||||||
BYTE *const pStart = p;
|
|
||||||
|
|
||||||
/* up to 4 symbols at a time */
|
|
||||||
while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p <= pEnd - 4)) {
|
|
||||||
HUF_DECODE_SYMBOLX2_2(p, bitDPtr);
|
|
||||||
HUF_DECODE_SYMBOLX2_1(p, bitDPtr);
|
|
||||||
HUF_DECODE_SYMBOLX2_2(p, bitDPtr);
|
|
||||||
HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* closer to the end */
|
|
||||||
while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p < pEnd))
|
|
||||||
HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
|
|
||||||
|
|
||||||
/* no more data to retrieve from bitstream, hence no need to reload */
|
|
||||||
while (p < pEnd)
|
|
||||||
HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
|
|
||||||
|
|
||||||
return pEnd - pStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t HUF_decompress1X2_usingDTable_internal(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
|
|
||||||
{
|
|
||||||
BYTE *op = (BYTE *)dst;
|
|
||||||
BYTE *const oend = op + dstSize;
|
|
||||||
const void *dtPtr = DTable + 1;
|
|
||||||
const HUF_DEltX2 *const dt = (const HUF_DEltX2 *)dtPtr;
|
|
||||||
BIT_DStream_t bitD;
|
|
||||||
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
|
||||||
U32 const dtLog = dtd.tableLog;
|
|
||||||
|
|
||||||
{
|
|
||||||
size_t const errorCode = BIT_initDStream(&bitD, cSrc, cSrcSize);
|
|
||||||
if (HUF_isError(errorCode))
|
|
||||||
return errorCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
HUF_decodeStreamX2(op, &bitD, oend, dt, dtLog);
|
|
||||||
|
|
||||||
/* check */
|
|
||||||
if (!BIT_endOfDStream(&bitD))
|
|
||||||
return ERROR(corruption_detected);
|
|
||||||
|
|
||||||
return dstSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t HUF_decompress1X2_usingDTable(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
|
|
||||||
{
|
|
||||||
DTableDesc dtd = HUF_getDTableDesc(DTable);
|
|
||||||
if (dtd.tableType != 0)
|
|
||||||
return ERROR(GENERIC);
|
|
||||||
return HUF_decompress1X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable *DCtx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize)
|
|
||||||
{
|
|
||||||
const BYTE *ip = (const BYTE *)cSrc;
|
|
||||||
|
|
||||||
size_t const hSize = HUF_readDTableX2_wksp(DCtx, cSrc, cSrcSize, workspace, workspaceSize);
|
|
||||||
if (HUF_isError(hSize))
|
|
||||||
return hSize;
|
|
||||||
if (hSize >= cSrcSize)
|
|
||||||
return ERROR(srcSize_wrong);
|
|
||||||
ip += hSize;
|
|
||||||
cSrcSize -= hSize;
|
|
||||||
|
|
||||||
return HUF_decompress1X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t HUF_decompress4X2_usingDTable_internal(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *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 + 1;
|
|
||||||
const HUF_DEltX2 *const dt = (const HUF_DEltX2 *)dtPtr;
|
|
||||||
|
|
||||||
/* Init */
|
|
||||||
BIT_DStream_t bitD1;
|
|
||||||
BIT_DStream_t bitD2;
|
|
||||||
BIT_DStream_t bitD3;
|
|
||||||
BIT_DStream_t bitD4;
|
|
||||||
size_t const length1 = ZSTD_readLE16(istart);
|
|
||||||
size_t const length2 = ZSTD_readLE16(istart + 2);
|
|
||||||
size_t const length3 = ZSTD_readLE16(istart + 4);
|
|
||||||
size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6);
|
|
||||||
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;
|
|
||||||
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
|
||||||
U32 const dtLog = dtd.tableLog;
|
|
||||||
|
|
||||||
if (length4 > cSrcSize)
|
|
||||||
return ERROR(corruption_detected); /* overflow */
|
|
||||||
{
|
|
||||||
size_t const errorCode = BIT_initDStream(&bitD1, istart1, length1);
|
|
||||||
if (HUF_isError(errorCode))
|
|
||||||
return errorCode;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
size_t const errorCode = BIT_initDStream(&bitD2, istart2, length2);
|
|
||||||
if (HUF_isError(errorCode))
|
|
||||||
return errorCode;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
size_t const errorCode = BIT_initDStream(&bitD3, istart3, length3);
|
|
||||||
if (HUF_isError(errorCode))
|
|
||||||
return errorCode;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
size_t const errorCode = BIT_initDStream(&bitD4, istart4, length4);
|
|
||||||
if (HUF_isError(errorCode))
|
|
||||||
return errorCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 16-32 symbols per loop (4-8 symbols per stream) */
|
|
||||||
endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
|
|
||||||
for (; (endSignal == BIT_DStream_unfinished) && (op4 < (oend - 7));) {
|
|
||||||
HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
|
|
||||||
HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
|
|
||||||
HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
|
|
||||||
HUF_DECODE_SYMBOLX2_2(op4, &bitD4);
|
|
||||||
HUF_DECODE_SYMBOLX2_1(op1, &bitD1);
|
|
||||||
HUF_DECODE_SYMBOLX2_1(op2, &bitD2);
|
|
||||||
HUF_DECODE_SYMBOLX2_1(op3, &bitD3);
|
|
||||||
HUF_DECODE_SYMBOLX2_1(op4, &bitD4);
|
|
||||||
HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
|
|
||||||
HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
|
|
||||||
HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
|
|
||||||
HUF_DECODE_SYMBOLX2_2(op4, &bitD4);
|
|
||||||
HUF_DECODE_SYMBOLX2_0(op1, &bitD1);
|
|
||||||
HUF_DECODE_SYMBOLX2_0(op2, &bitD2);
|
|
||||||
HUF_DECODE_SYMBOLX2_0(op3, &bitD3);
|
|
||||||
HUF_DECODE_SYMBOLX2_0(op4, &bitD4);
|
|
||||||
endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_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 */
|
|
||||||
HUF_decodeStreamX2(op1, &bitD1, opStart2, dt, dtLog);
|
|
||||||
HUF_decodeStreamX2(op2, &bitD2, opStart3, dt, dtLog);
|
|
||||||
HUF_decodeStreamX2(op3, &bitD3, opStart4, dt, dtLog);
|
|
||||||
HUF_decodeStreamX2(op4, &bitD4, oend, dt, dtLog);
|
|
||||||
|
|
||||||
/* check */
|
|
||||||
endSignal = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4);
|
|
||||||
if (!endSignal)
|
|
||||||
return ERROR(corruption_detected);
|
|
||||||
|
|
||||||
/* decoded size */
|
|
||||||
return dstSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t HUF_decompress4X2_usingDTable(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
|
|
||||||
{
|
|
||||||
DTableDesc dtd = HUF_getDTableDesc(DTable);
|
|
||||||
if (dtd.tableType != 0)
|
|
||||||
return ERROR(GENERIC);
|
|
||||||
return HUF_decompress4X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize)
|
|
||||||
{
|
|
||||||
const BYTE *ip = (const BYTE *)cSrc;
|
|
||||||
|
|
||||||
size_t const hSize = HUF_readDTableX2_wksp(dctx, cSrc, cSrcSize, workspace, workspaceSize);
|
|
||||||
if (HUF_isError(hSize))
|
|
||||||
return hSize;
|
|
||||||
if (hSize >= cSrcSize)
|
|
||||||
return ERROR(srcSize_wrong);
|
|
||||||
ip += hSize;
|
|
||||||
cSrcSize -= hSize;
|
|
||||||
|
|
||||||
return HUF_decompress4X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *************************/
|
|
||||||
/* double-symbols decoding */
|
|
||||||
/* *************************/
|
|
||||||
typedef struct {
|
|
||||||
U16 sequence;
|
|
||||||
BYTE nbBits;
|
|
||||||
BYTE length;
|
|
||||||
} HUF_DEltX4; /* double-symbols decoding */
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
BYTE symbol;
|
|
||||||
BYTE weight;
|
|
||||||
} sortedSymbol_t;
|
|
||||||
|
|
||||||
/* HUF_fillDTableX4Level2() :
|
|
||||||
* `rankValOrigin` must be a table of at least (HUF_TABLELOG_MAX + 1) U32 */
|
|
||||||
static void HUF_fillDTableX4Level2(HUF_DEltX4 *DTable, U32 sizeLog, const U32 consumed, const U32 *rankValOrigin, const int minWeight,
|
|
||||||
const sortedSymbol_t *sortedSymbols, const U32 sortedListSize, U32 nbBitsBaseline, U16 baseSeq)
|
|
||||||
{
|
|
||||||
HUF_DEltX4 DElt;
|
|
||||||
U32 rankVal[HUF_TABLELOG_MAX + 1];
|
|
||||||
|
|
||||||
/* get pre-calculated rankVal */
|
|
||||||
memcpy(rankVal, rankValOrigin, sizeof(rankVal));
|
|
||||||
|
|
||||||
/* fill skipped values */
|
|
||||||
if (minWeight > 1) {
|
|
||||||
U32 i, skipSize = rankVal[minWeight];
|
|
||||||
ZSTD_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 < sortedListSize; s++) { /* note : sortedSymbols already skipped */
|
|
||||||
const U32 symbol = sortedSymbols[s].symbol;
|
|
||||||
const U32 weight = sortedSymbols[s].weight;
|
|
||||||
const U32 nbBits = nbBitsBaseline - weight;
|
|
||||||
const U32 length = 1 << (sizeLog - nbBits);
|
|
||||||
const U32 start = rankVal[weight];
|
|
||||||
U32 i = start;
|
|
||||||
const U32 end = start + length;
|
|
||||||
|
|
||||||
ZSTD_writeLE16(&(DElt.sequence), (U16)(baseSeq + (symbol << 8)));
|
|
||||||
DElt.nbBits = (BYTE)(nbBits + consumed);
|
|
||||||
DElt.length = 2;
|
|
||||||
do {
|
|
||||||
DTable[i++] = DElt;
|
|
||||||
} while (i < end); /* since length >= 1 */
|
|
||||||
|
|
||||||
rankVal[weight] += length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef U32 rankVal_t[HUF_TABLELOG_MAX][HUF_TABLELOG_MAX + 1];
|
|
||||||
typedef U32 rankValCol_t[HUF_TABLELOG_MAX + 1];
|
|
||||||
|
|
||||||
static void HUF_fillDTableX4(HUF_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[HUF_TABLELOG_MAX + 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 < sortedListSize; s++) {
|
|
||||||
const U16 symbol = sortedList[s].symbol;
|
|
||||||
const U32 weight = sortedList[s].weight;
|
|
||||||
const U32 nbBits = nbBitsBaseline - weight;
|
|
||||||
const U32 start = rankVal[weight];
|
|
||||||
const U32 length = 1 << (targetLog - nbBits);
|
|
||||||
|
|
||||||
if (targetLog - nbBits >= minBits) { /* enough room for a second symbol */
|
|
||||||
U32 sortedRank;
|
|
||||||
int minWeight = nbBits + scaleLog;
|
|
||||||
if (minWeight < 1)
|
|
||||||
minWeight = 1;
|
|
||||||
sortedRank = rankStart[minWeight];
|
|
||||||
HUF_fillDTableX4Level2(DTable + start, targetLog - nbBits, nbBits, rankValOrigin[nbBits], minWeight, sortedList + sortedRank,
|
|
||||||
sortedListSize - sortedRank, nbBitsBaseline, symbol);
|
|
||||||
} else {
|
|
||||||
HUF_DEltX4 DElt;
|
|
||||||
ZSTD_writeLE16(&(DElt.sequence), symbol);
|
|
||||||
DElt.nbBits = (BYTE)(nbBits);
|
|
||||||
DElt.length = 1;
|
|
||||||
{
|
|
||||||
U32 const end = start + length;
|
|
||||||
U32 u;
|
|
||||||
for (u = start; u < end; u++)
|
|
||||||
DTable[u] = DElt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rankVal[weight] += length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t HUF_readDTableX4_wksp(HUF_DTable *DTable, const void *src, size_t srcSize, void *workspace, size_t workspaceSize)
|
|
||||||
{
|
|
||||||
U32 tableLog, maxW, sizeOfSort, nbSymbols;
|
|
||||||
DTableDesc dtd = HUF_getDTableDesc(DTable);
|
|
||||||
U32 const maxTableLog = dtd.maxTableLog;
|
|
||||||
size_t iSize;
|
|
||||||
void *dtPtr = DTable + 1; /* force compiler to avoid strict-aliasing */
|
|
||||||
HUF_DEltX4 *const dt = (HUF_DEltX4 *)dtPtr;
|
|
||||||
U32 *rankStart;
|
|
||||||
|
|
||||||
rankValCol_t *rankVal;
|
|
||||||
U32 *rankStats;
|
|
||||||
U32 *rankStart0;
|
|
||||||
sortedSymbol_t *sortedSymbol;
|
|
||||||
BYTE *weightList;
|
|
||||||
size_t spaceUsed32 = 0;
|
|
||||||
|
|
||||||
HUF_STATIC_ASSERT((sizeof(rankValCol_t) & 3) == 0);
|
|
||||||
|
|
||||||
rankVal = (rankValCol_t *)((U32 *)workspace + spaceUsed32);
|
|
||||||
spaceUsed32 += (sizeof(rankValCol_t) * HUF_TABLELOG_MAX) >> 2;
|
|
||||||
rankStats = (U32 *)workspace + spaceUsed32;
|
|
||||||
spaceUsed32 += HUF_TABLELOG_MAX + 1;
|
|
||||||
rankStart0 = (U32 *)workspace + spaceUsed32;
|
|
||||||
spaceUsed32 += HUF_TABLELOG_MAX + 2;
|
|
||||||
sortedSymbol = (sortedSymbol_t *)((U32 *)workspace + spaceUsed32);
|
|
||||||
spaceUsed32 += ALIGN(sizeof(sortedSymbol_t) * (HUF_SYMBOLVALUE_MAX + 1), sizeof(U32)) >> 2;
|
|
||||||
weightList = (BYTE *)((U32 *)workspace + spaceUsed32);
|
|
||||||
spaceUsed32 += ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2;
|
|
||||||
|
|
||||||
if ((spaceUsed32 << 2) > workspaceSize)
|
|
||||||
return ERROR(tableLog_tooLarge);
|
|
||||||
workspace = (U32 *)workspace + spaceUsed32;
|
|
||||||
workspaceSize -= (spaceUsed32 << 2);
|
|
||||||
|
|
||||||
rankStart = rankStart0 + 1;
|
|
||||||
memset(rankStats, 0, sizeof(U32) * (2 * HUF_TABLELOG_MAX + 2 + 1));
|
|
||||||
|
|
||||||
HUF_STATIC_ASSERT(sizeof(HUF_DEltX4) == sizeof(HUF_DTable)); /* if compiler fails here, assertion is wrong */
|
|
||||||
if (maxTableLog > HUF_TABLELOG_MAX)
|
|
||||||
return ERROR(tableLog_tooLarge);
|
|
||||||
/* memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */
|
|
||||||
|
|
||||||
iSize = HUF_readStats_wksp(weightList, HUF_SYMBOLVALUE_MAX + 1, rankStats, &nbSymbols, &tableLog, src, srcSize, workspace, workspaceSize);
|
|
||||||
if (HUF_isError(iSize))
|
|
||||||
return iSize;
|
|
||||||
|
|
||||||
/* check result */
|
|
||||||
if (tableLog > maxTableLog)
|
|
||||||
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 + 1; w++) {
|
|
||||||
U32 curr = nextRankStart;
|
|
||||||
nextRankStart += rankStats[w];
|
|
||||||
rankStart[w] = curr;
|
|
||||||
}
|
|
||||||
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 < nbSymbols; s++) {
|
|
||||||
U32 const w = weightList[s];
|
|
||||||
U32 const r = rankStart[w]++;
|
|
||||||
sortedSymbol[r].symbol = (BYTE)s;
|
|
||||||
sortedSymbol[r].weight = (BYTE)w;
|
|
||||||
}
|
|
||||||
rankStart[0] = 0; /* forget 0w symbols; this is beginning of weight(1) */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Build rankVal */
|
|
||||||
{
|
|
||||||
U32 *const rankVal0 = rankVal[0];
|
|
||||||
{
|
|
||||||
int const rescale = (maxTableLog - tableLog) - 1; /* tableLog <= maxTableLog */
|
|
||||||
U32 nextRankVal = 0;
|
|
||||||
U32 w;
|
|
||||||
for (w = 1; w < maxW + 1; w++) {
|
|
||||||
U32 curr = nextRankVal;
|
|
||||||
nextRankVal += rankStats[w] << (w + rescale);
|
|
||||||
rankVal0[w] = curr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
U32 const minBits = tableLog + 1 - maxW;
|
|
||||||
U32 consumed;
|
|
||||||
for (consumed = minBits; consumed < maxTableLog - minBits + 1; consumed++) {
|
|
||||||
U32 *const rankValPtr = rankVal[consumed];
|
|
||||||
U32 w;
|
|
||||||
for (w = 1; w < maxW + 1; w++) {
|
|
||||||
rankValPtr[w] = rankVal0[w] >> consumed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HUF_fillDTableX4(dt, maxTableLog, sortedSymbol, sizeOfSort, rankStart0, rankVal, maxW, tableLog + 1);
|
|
||||||
|
|
||||||
dtd.tableLog = (BYTE)maxTableLog;
|
|
||||||
dtd.tableType = 1;
|
|
||||||
memcpy(DTable, &dtd, sizeof(dtd));
|
|
||||||
return iSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
static U32 HUF_decodeSymbolX4(void *op, BIT_DStream_t *DStream, const HUF_DEltX4 *dt, const U32 dtLog)
|
|
||||||
{
|
|
||||||
size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */
|
|
||||||
memcpy(op, dt + val, 2);
|
|
||||||
BIT_skipBits(DStream, dt[val].nbBits);
|
|
||||||
return dt[val].length;
|
|
||||||
}
|
|
||||||
|
|
||||||
static U32 HUF_decodeLastSymbolX4(void *op, BIT_DStream_t *DStream, const HUF_DEltX4 *dt, const U32 dtLog)
|
|
||||||
{
|
|
||||||
size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */
|
|
||||||
memcpy(op, dt + val, 1);
|
|
||||||
if (dt[val].length == 1)
|
|
||||||
BIT_skipBits(DStream, dt[val].nbBits);
|
|
||||||
else {
|
|
||||||
if (DStream->bitsConsumed < (sizeof(DStream->bitContainer) * 8)) {
|
|
||||||
BIT_skipBits(DStream, dt[val].nbBits);
|
|
||||||
if (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 */
|
|
||||||
DStream->bitsConsumed = (sizeof(DStream->bitContainer) * 8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define HUF_DECODE_SYMBOLX4_0(ptr, DStreamPtr) ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
|
|
||||||
|
|
||||||
#define HUF_DECODE_SYMBOLX4_1(ptr, DStreamPtr) \
|
|
||||||
if (ZSTD_64bits() || (HUF_TABLELOG_MAX <= 12)) \
|
|
||||||
ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
|
|
||||||
|
|
||||||
#define HUF_DECODE_SYMBOLX4_2(ptr, DStreamPtr) \
|
|
||||||
if (ZSTD_64bits()) \
|
|
||||||
ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
|
|
||||||
|
|
||||||
FORCE_INLINE size_t HUF_decodeStreamX4(BYTE *p, BIT_DStream_t *bitDPtr, BYTE *const pEnd, const HUF_DEltX4 *const dt, const U32 dtLog)
|
|
||||||
{
|
|
||||||
BYTE *const pStart = p;
|
|
||||||
|
|
||||||
/* up to 8 symbols at a time */
|
|
||||||
while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd - (sizeof(bitDPtr->bitContainer) - 1))) {
|
|
||||||
HUF_DECODE_SYMBOLX4_2(p, bitDPtr);
|
|
||||||
HUF_DECODE_SYMBOLX4_1(p, bitDPtr);
|
|
||||||
HUF_DECODE_SYMBOLX4_2(p, bitDPtr);
|
|
||||||
HUF_DECODE_SYMBOLX4_0(p, bitDPtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* closer to end : up to 2 symbols at a time */
|
|
||||||
while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p <= pEnd - 2))
|
|
||||||
HUF_DECODE_SYMBOLX4_0(p, bitDPtr);
|
|
||||||
|
|
||||||
while (p <= pEnd - 2)
|
|
||||||
HUF_DECODE_SYMBOLX4_0(p, bitDPtr); /* no need to reload : reached the end of DStream */
|
|
||||||
|
|
||||||
if (p < pEnd)
|
|
||||||
p += HUF_decodeLastSymbolX4(p, bitDPtr, dt, dtLog);
|
|
||||||
|
|
||||||
return p - pStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t HUF_decompress1X4_usingDTable_internal(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
|
|
||||||
{
|
|
||||||
BIT_DStream_t bitD;
|
|
||||||
|
|
||||||
/* Init */
|
|
||||||
{
|
|
||||||
size_t const errorCode = BIT_initDStream(&bitD, cSrc, cSrcSize);
|
|
||||||
if (HUF_isError(errorCode))
|
|
||||||
return errorCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* decode */
|
|
||||||
{
|
|
||||||
BYTE *const ostart = (BYTE *)dst;
|
|
||||||
BYTE *const oend = ostart + dstSize;
|
|
||||||
const void *const dtPtr = DTable + 1; /* force compiler to not use strict-aliasing */
|
|
||||||
const HUF_DEltX4 *const dt = (const HUF_DEltX4 *)dtPtr;
|
|
||||||
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
|
||||||
HUF_decodeStreamX4(ostart, &bitD, oend, dt, dtd.tableLog);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check */
|
|
||||||
if (!BIT_endOfDStream(&bitD))
|
|
||||||
return ERROR(corruption_detected);
|
|
||||||
|
|
||||||
/* decoded size */
|
|
||||||
return dstSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t HUF_decompress1X4_usingDTable(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
|
|
||||||
{
|
|
||||||
DTableDesc dtd = HUF_getDTableDesc(DTable);
|
|
||||||
if (dtd.tableType != 1)
|
|
||||||
return ERROR(GENERIC);
|
|
||||||
return HUF_decompress1X4_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t HUF_decompress1X4_DCtx_wksp(HUF_DTable *DCtx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize)
|
|
||||||
{
|
|
||||||
const BYTE *ip = (const BYTE *)cSrc;
|
|
||||||
|
|
||||||
size_t const hSize = HUF_readDTableX4_wksp(DCtx, cSrc, cSrcSize, workspace, workspaceSize);
|
|
||||||
if (HUF_isError(hSize))
|
|
||||||
return hSize;
|
|
||||||
if (hSize >= cSrcSize)
|
|
||||||
return ERROR(srcSize_wrong);
|
|
||||||
ip += hSize;
|
|
||||||
cSrcSize -= hSize;
|
|
||||||
|
|
||||||
return HUF_decompress1X4_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t HUF_decompress4X4_usingDTable_internal(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *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 + 1;
|
|
||||||
const HUF_DEltX4 *const dt = (const HUF_DEltX4 *)dtPtr;
|
|
||||||
|
|
||||||
/* Init */
|
|
||||||
BIT_DStream_t bitD1;
|
|
||||||
BIT_DStream_t bitD2;
|
|
||||||
BIT_DStream_t bitD3;
|
|
||||||
BIT_DStream_t bitD4;
|
|
||||||
size_t const length1 = ZSTD_readLE16(istart);
|
|
||||||
size_t const length2 = ZSTD_readLE16(istart + 2);
|
|
||||||
size_t const length3 = ZSTD_readLE16(istart + 4);
|
|
||||||
size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6);
|
|
||||||
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;
|
|
||||||
size_t const 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;
|
|
||||||
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
|
||||||
U32 const dtLog = dtd.tableLog;
|
|
||||||
|
|
||||||
if (length4 > cSrcSize)
|
|
||||||
return ERROR(corruption_detected); /* overflow */
|
|
||||||
{
|
|
||||||
size_t const errorCode = BIT_initDStream(&bitD1, istart1, length1);
|
|
||||||
if (HUF_isError(errorCode))
|
|
||||||
return errorCode;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
size_t const errorCode = BIT_initDStream(&bitD2, istart2, length2);
|
|
||||||
if (HUF_isError(errorCode))
|
|
||||||
return errorCode;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
size_t const errorCode = BIT_initDStream(&bitD3, istart3, length3);
|
|
||||||
if (HUF_isError(errorCode))
|
|
||||||
return errorCode;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
size_t const errorCode = BIT_initDStream(&bitD4, istart4, length4);
|
|
||||||
if (HUF_isError(errorCode))
|
|
||||||
return errorCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 16-32 symbols per loop (4-8 symbols per stream) */
|
|
||||||
endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
|
|
||||||
for (; (endSignal == BIT_DStream_unfinished) & (op4 < (oend - (sizeof(bitD4.bitContainer) - 1)));) {
|
|
||||||
HUF_DECODE_SYMBOLX4_2(op1, &bitD1);
|
|
||||||
HUF_DECODE_SYMBOLX4_2(op2, &bitD2);
|
|
||||||
HUF_DECODE_SYMBOLX4_2(op3, &bitD3);
|
|
||||||
HUF_DECODE_SYMBOLX4_2(op4, &bitD4);
|
|
||||||
HUF_DECODE_SYMBOLX4_1(op1, &bitD1);
|
|
||||||
HUF_DECODE_SYMBOLX4_1(op2, &bitD2);
|
|
||||||
HUF_DECODE_SYMBOLX4_1(op3, &bitD3);
|
|
||||||
HUF_DECODE_SYMBOLX4_1(op4, &bitD4);
|
|
||||||
HUF_DECODE_SYMBOLX4_2(op1, &bitD1);
|
|
||||||
HUF_DECODE_SYMBOLX4_2(op2, &bitD2);
|
|
||||||
HUF_DECODE_SYMBOLX4_2(op3, &bitD3);
|
|
||||||
HUF_DECODE_SYMBOLX4_2(op4, &bitD4);
|
|
||||||
HUF_DECODE_SYMBOLX4_0(op1, &bitD1);
|
|
||||||
HUF_DECODE_SYMBOLX4_0(op2, &bitD2);
|
|
||||||
HUF_DECODE_SYMBOLX4_0(op3, &bitD3);
|
|
||||||
HUF_DECODE_SYMBOLX4_0(op4, &bitD4);
|
|
||||||
|
|
||||||
endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_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 already verified within main loop */
|
|
||||||
|
|
||||||
/* finish bitStreams one by one */
|
|
||||||
HUF_decodeStreamX4(op1, &bitD1, opStart2, dt, dtLog);
|
|
||||||
HUF_decodeStreamX4(op2, &bitD2, opStart3, dt, dtLog);
|
|
||||||
HUF_decodeStreamX4(op3, &bitD3, opStart4, dt, dtLog);
|
|
||||||
HUF_decodeStreamX4(op4, &bitD4, oend, dt, dtLog);
|
|
||||||
|
|
||||||
/* check */
|
|
||||||
{
|
|
||||||
U32 const endCheck = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4);
|
|
||||||
if (!endCheck)
|
|
||||||
return ERROR(corruption_detected);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* decoded size */
|
|
||||||
return dstSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t HUF_decompress4X4_usingDTable(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
|
|
||||||
{
|
|
||||||
DTableDesc dtd = HUF_getDTableDesc(DTable);
|
|
||||||
if (dtd.tableType != 1)
|
|
||||||
return ERROR(GENERIC);
|
|
||||||
return HUF_decompress4X4_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t HUF_decompress4X4_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize)
|
|
||||||
{
|
|
||||||
const BYTE *ip = (const BYTE *)cSrc;
|
|
||||||
|
|
||||||
size_t hSize = HUF_readDTableX4_wksp(dctx, cSrc, cSrcSize, workspace, workspaceSize);
|
|
||||||
if (HUF_isError(hSize))
|
|
||||||
return hSize;
|
|
||||||
if (hSize >= cSrcSize)
|
|
||||||
return ERROR(srcSize_wrong);
|
|
||||||
ip += hSize;
|
|
||||||
cSrcSize -= hSize;
|
|
||||||
|
|
||||||
return HUF_decompress4X4_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ********************************/
|
|
||||||
/* Generic decompression selector */
|
|
||||||
/* ********************************/
|
|
||||||
|
|
||||||
size_t HUF_decompress1X_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
|
|
||||||
{
|
|
||||||
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
|
||||||
return dtd.tableType ? HUF_decompress1X4_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable)
|
|
||||||
: HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t HUF_decompress4X_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
|
|
||||||
{
|
|
||||||
DTableDesc const dtd = HUF_getDTableDesc(DTable);
|
|
||||||
return dtd.tableType ? HUF_decompress4X4_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable)
|
|
||||||
: HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable);
|
|
||||||
}
|
|
||||||
|
|
||||||
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% */
|
|
||||||
};
|
|
||||||
|
|
||||||
/** HUF_selectDecoder() :
|
|
||||||
* Tells which decoder is likely to decode faster,
|
|
||||||
* based on a set of pre-determined metrics.
|
|
||||||
* @return : 0==HUF_decompress4X2, 1==HUF_decompress4X4 .
|
|
||||||
* Assumption : 0 < cSrcSize < dstSize <= 128 KB */
|
|
||||||
U32 HUF_selectDecoder(size_t dstSize, size_t cSrcSize)
|
|
||||||
{
|
|
||||||
/* decoder timing evaluation */
|
|
||||||
U32 const Q = (U32)(cSrcSize * 16 / dstSize); /* Q < 16 since dstSize > cSrcSize */
|
|
||||||
U32 const D256 = (U32)(dstSize >> 8);
|
|
||||||
U32 const DTime0 = algoTime[Q][0].tableTime + (algoTime[Q][0].decode256Time * D256);
|
|
||||||
U32 DTime1 = algoTime[Q][1].tableTime + (algoTime[Q][1].decode256Time * D256);
|
|
||||||
DTime1 += DTime1 >> 3; /* advantage to algorithm using less memory, for cache eviction */
|
|
||||||
|
|
||||||
return DTime1 < DTime0;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef size_t (*decompressionAlgo)(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize);
|
|
||||||
|
|
||||||
size_t HUF_decompress4X_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize)
|
|
||||||
{
|
|
||||||
/* 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 */
|
|
||||||
|
|
||||||
{
|
|
||||||
U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
|
|
||||||
return algoNb ? HUF_decompress4X4_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workspace, workspaceSize)
|
|
||||||
: HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workspace, workspaceSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize)
|
|
||||||
{
|
|
||||||
/* validation checks */
|
|
||||||
if (dstSize == 0)
|
|
||||||
return ERROR(dstSize_tooSmall);
|
|
||||||
if ((cSrcSize >= dstSize) || (cSrcSize <= 1))
|
|
||||||
return ERROR(corruption_detected); /* invalid */
|
|
||||||
|
|
||||||
{
|
|
||||||
U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
|
|
||||||
return algoNb ? HUF_decompress4X4_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workspace, workspaceSize)
|
|
||||||
: HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workspace, workspaceSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t HUF_decompress1X_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize)
|
|
||||||
{
|
|
||||||
/* 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 */
|
|
||||||
|
|
||||||
{
|
|
||||||
U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
|
|
||||||
return algoNb ? HUF_decompress1X4_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workspace, workspaceSize)
|
|
||||||
: HUF_decompress1X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workspace, workspaceSize);
|
|
||||||
}
|
|
||||||
}
|
|
142
lib/zstd/mem.h
142
lib/zstd/mem.h
|
@ -1,142 +0,0 @@
|
||||||
/* SPDX-License-Identifier: (GPL-2.0 or BSD-3-Clause-Clear) */
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MEM_H_MODULE
|
|
||||||
#define MEM_H_MODULE
|
|
||||||
|
|
||||||
/*-****************************************
|
|
||||||
* Dependencies
|
|
||||||
******************************************/
|
|
||||||
#include <asm/unaligned.h>
|
|
||||||
#include <compiler.h>
|
|
||||||
#include <linux/string.h> /* memcpy */
|
|
||||||
#include <linux/types.h> /* size_t, ptrdiff_t */
|
|
||||||
|
|
||||||
/*-****************************************
|
|
||||||
* Compiler specifics
|
|
||||||
******************************************/
|
|
||||||
#define ZSTD_STATIC static __inline __attribute__((unused))
|
|
||||||
|
|
||||||
/*-**************************************************************
|
|
||||||
* Basic Types
|
|
||||||
*****************************************************************/
|
|
||||||
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;
|
|
||||||
typedef ptrdiff_t iPtrDiff;
|
|
||||||
typedef uintptr_t uPtrDiff;
|
|
||||||
|
|
||||||
/*-**************************************************************
|
|
||||||
* Memory I/O
|
|
||||||
*****************************************************************/
|
|
||||||
ZSTD_STATIC unsigned ZSTD_32bits(void) { return sizeof(size_t) == 4; }
|
|
||||||
ZSTD_STATIC unsigned ZSTD_64bits(void) { return sizeof(size_t) == 8; }
|
|
||||||
|
|
||||||
#if defined(__LITTLE_ENDIAN)
|
|
||||||
#define ZSTD_LITTLE_ENDIAN 1
|
|
||||||
#else
|
|
||||||
#define ZSTD_LITTLE_ENDIAN 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ZSTD_STATIC unsigned ZSTD_isLittleEndian(void) { return ZSTD_LITTLE_ENDIAN; }
|
|
||||||
|
|
||||||
ZSTD_STATIC U16 ZSTD_read16(const void *memPtr) { return get_unaligned((const U16 *)memPtr); }
|
|
||||||
|
|
||||||
ZSTD_STATIC U32 ZSTD_read32(const void *memPtr) { return get_unaligned((const U32 *)memPtr); }
|
|
||||||
|
|
||||||
ZSTD_STATIC U64 ZSTD_read64(const void *memPtr) { return get_unaligned((const U64 *)memPtr); }
|
|
||||||
|
|
||||||
ZSTD_STATIC size_t ZSTD_readST(const void *memPtr) { return get_unaligned((const size_t *)memPtr); }
|
|
||||||
|
|
||||||
ZSTD_STATIC void ZSTD_write16(void *memPtr, U16 value) { put_unaligned(value, (U16 *)memPtr); }
|
|
||||||
|
|
||||||
ZSTD_STATIC void ZSTD_write32(void *memPtr, U32 value) { put_unaligned(value, (U32 *)memPtr); }
|
|
||||||
|
|
||||||
ZSTD_STATIC void ZSTD_write64(void *memPtr, U64 value) { put_unaligned(value, (U64 *)memPtr); }
|
|
||||||
|
|
||||||
/*=== Little endian r/w ===*/
|
|
||||||
|
|
||||||
ZSTD_STATIC U16 ZSTD_readLE16(const void *memPtr) { return get_unaligned_le16(memPtr); }
|
|
||||||
|
|
||||||
ZSTD_STATIC void ZSTD_writeLE16(void *memPtr, U16 val) { put_unaligned_le16(val, memPtr); }
|
|
||||||
|
|
||||||
ZSTD_STATIC U32 ZSTD_readLE24(const void *memPtr) { return ZSTD_readLE16(memPtr) + (((const BYTE *)memPtr)[2] << 16); }
|
|
||||||
|
|
||||||
ZSTD_STATIC void ZSTD_writeLE24(void *memPtr, U32 val)
|
|
||||||
{
|
|
||||||
ZSTD_writeLE16(memPtr, (U16)val);
|
|
||||||
((BYTE *)memPtr)[2] = (BYTE)(val >> 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
ZSTD_STATIC U32 ZSTD_readLE32(const void *memPtr) { return get_unaligned_le32(memPtr); }
|
|
||||||
|
|
||||||
ZSTD_STATIC void ZSTD_writeLE32(void *memPtr, U32 val32) { put_unaligned_le32(val32, memPtr); }
|
|
||||||
|
|
||||||
ZSTD_STATIC U64 ZSTD_readLE64(const void *memPtr) { return get_unaligned_le64(memPtr); }
|
|
||||||
|
|
||||||
ZSTD_STATIC void ZSTD_writeLE64(void *memPtr, U64 val64) { put_unaligned_le64(val64, memPtr); }
|
|
||||||
|
|
||||||
ZSTD_STATIC size_t ZSTD_readLEST(const void *memPtr)
|
|
||||||
{
|
|
||||||
if (ZSTD_32bits())
|
|
||||||
return (size_t)ZSTD_readLE32(memPtr);
|
|
||||||
else
|
|
||||||
return (size_t)ZSTD_readLE64(memPtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
ZSTD_STATIC void ZSTD_writeLEST(void *memPtr, size_t val)
|
|
||||||
{
|
|
||||||
if (ZSTD_32bits())
|
|
||||||
ZSTD_writeLE32(memPtr, (U32)val);
|
|
||||||
else
|
|
||||||
ZSTD_writeLE64(memPtr, (U64)val);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*=== Big endian r/w ===*/
|
|
||||||
|
|
||||||
ZSTD_STATIC U32 ZSTD_readBE32(const void *memPtr) { return get_unaligned_be32(memPtr); }
|
|
||||||
|
|
||||||
ZSTD_STATIC void ZSTD_writeBE32(void *memPtr, U32 val32) { put_unaligned_be32(val32, memPtr); }
|
|
||||||
|
|
||||||
ZSTD_STATIC U64 ZSTD_readBE64(const void *memPtr) { return get_unaligned_be64(memPtr); }
|
|
||||||
|
|
||||||
ZSTD_STATIC void ZSTD_writeBE64(void *memPtr, U64 val64) { put_unaligned_be64(val64, memPtr); }
|
|
||||||
|
|
||||||
ZSTD_STATIC size_t ZSTD_readBEST(const void *memPtr)
|
|
||||||
{
|
|
||||||
if (ZSTD_32bits())
|
|
||||||
return (size_t)ZSTD_readBE32(memPtr);
|
|
||||||
else
|
|
||||||
return (size_t)ZSTD_readBE64(memPtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
ZSTD_STATIC void ZSTD_writeBEST(void *memPtr, size_t val)
|
|
||||||
{
|
|
||||||
if (ZSTD_32bits())
|
|
||||||
ZSTD_writeBE32(memPtr, (U32)val);
|
|
||||||
else
|
|
||||||
ZSTD_writeBE64(memPtr, (U64)val);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* function safe only for comparisons */
|
|
||||||
ZSTD_STATIC U32 ZSTD_readMINMATCH(const void *memPtr, U32 length)
|
|
||||||
{
|
|
||||||
switch (length) {
|
|
||||||
default:
|
|
||||||
case 4: return ZSTD_read32(memPtr);
|
|
||||||
case 3:
|
|
||||||
if (ZSTD_isLittleEndian())
|
|
||||||
return ZSTD_read32(memPtr) << 8;
|
|
||||||
else
|
|
||||||
return ZSTD_read32(memPtr) >> 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* MEM_H_MODULE */
|
|
|
@ -13,14 +13,12 @@
|
||||||
|
|
||||||
int zstd_decompress(struct abuf *in, struct abuf *out)
|
int zstd_decompress(struct abuf *in, struct abuf *out)
|
||||||
{
|
{
|
||||||
ZSTD_DStream *dstream;
|
zstd_dctx *ctx;
|
||||||
ZSTD_inBuffer in_buf;
|
size_t wsize, len;
|
||||||
ZSTD_outBuffer out_buf;
|
|
||||||
void *workspace;
|
void *workspace;
|
||||||
size_t wsize;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
wsize = ZSTD_DStreamWorkspaceBound(abuf_size(in));
|
wsize = zstd_dctx_workspace_bound();
|
||||||
workspace = malloc(wsize);
|
workspace = malloc(wsize);
|
||||||
if (!workspace) {
|
if (!workspace) {
|
||||||
debug("%s: cannot allocate workspace of size %zu\n", __func__,
|
debug("%s: cannot allocate workspace of size %zu\n", __func__,
|
||||||
|
@ -28,36 +26,35 @@ int zstd_decompress(struct abuf *in, struct abuf *out)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
dstream = ZSTD_initDStream(abuf_size(in), workspace, wsize);
|
ctx = zstd_init_dctx(workspace, wsize);
|
||||||
if (!dstream) {
|
if (!ctx) {
|
||||||
log_err("%s: ZSTD_initDStream failed\n", __func__);
|
log_err("%s: zstd_init_dctx() failed\n", __func__);
|
||||||
ret = -EPERM;
|
ret = -EPERM;
|
||||||
goto do_free;
|
goto do_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
in_buf.src = abuf_data(in);
|
/*
|
||||||
in_buf.pos = 0;
|
* Find out how large the frame actually is, there may be junk at
|
||||||
in_buf.size = abuf_size(in);
|
* the end of the frame that zstd_decompress_dctx() can't handle.
|
||||||
|
*/
|
||||||
out_buf.dst = abuf_data(out);
|
len = zstd_find_frame_compressed_size(abuf_data(in), abuf_size(in));
|
||||||
out_buf.pos = 0;
|
if (zstd_is_error(len)) {
|
||||||
out_buf.size = abuf_size(out);
|
log_err("%s: failed to detect compressed size: %d\n", __func__,
|
||||||
|
zstd_get_error_code(len));
|
||||||
while (1) {
|
ret = -EINVAL;
|
||||||
size_t res;
|
goto do_free;
|
||||||
|
|
||||||
res = ZSTD_decompressStream(dstream, &out_buf, &in_buf);
|
|
||||||
if (ZSTD_isError(res)) {
|
|
||||||
ret = ZSTD_getErrorCode(res);
|
|
||||||
log_err("ZSTD_decompressStream error %d\n", ret);
|
|
||||||
goto do_free;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (in_buf.pos >= abuf_size(in) || !res)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = out_buf.pos;
|
len = zstd_decompress_dctx(ctx, abuf_data(out), abuf_size(out),
|
||||||
|
abuf_data(in), len);
|
||||||
|
if (zstd_is_error(len)) {
|
||||||
|
log_err("%s: failed to decompress: %d\n", __func__,
|
||||||
|
zstd_get_error_code(len));
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto do_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = len;
|
||||||
do_free:
|
do_free:
|
||||||
free(workspace);
|
free(workspace);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -1,66 +0,0 @@
|
||||||
// SPDX-License-Identifier: (GPL-2.0 or BSD-3-Clause-Clear)
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*-*************************************
|
|
||||||
* Dependencies
|
|
||||||
***************************************/
|
|
||||||
#include "error_private.h"
|
|
||||||
#include "zstd_internal.h" /* declaration of ZSTD_isError, ZSTD_getErrorName, ZSTD_getErrorCode, ZSTD_getErrorString, ZSTD_versionNumber */
|
|
||||||
#include <malloc.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
|
|
||||||
/*=**************************************************************
|
|
||||||
* Custom allocator
|
|
||||||
****************************************************************/
|
|
||||||
|
|
||||||
#define stack_push(stack, size) \
|
|
||||||
({ \
|
|
||||||
void *const ptr = ZSTD_PTR_ALIGN((stack)->ptr); \
|
|
||||||
(stack)->ptr = (char *)ptr + (size); \
|
|
||||||
(stack)->ptr <= (stack)->end ? ptr : NULL; \
|
|
||||||
})
|
|
||||||
|
|
||||||
ZSTD_customMem ZSTD_initStack(void *workspace, size_t workspaceSize)
|
|
||||||
{
|
|
||||||
ZSTD_customMem stackMem = {ZSTD_stackAlloc, ZSTD_stackFree, workspace};
|
|
||||||
ZSTD_stack *stack = (ZSTD_stack *)workspace;
|
|
||||||
/* Verify preconditions */
|
|
||||||
if (!workspace || workspaceSize < sizeof(ZSTD_stack) || workspace != ZSTD_PTR_ALIGN(workspace)) {
|
|
||||||
ZSTD_customMem error = {NULL, NULL, NULL};
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
/* Initialize the stack */
|
|
||||||
stack->ptr = workspace;
|
|
||||||
stack->end = (char *)workspace + workspaceSize;
|
|
||||||
stack_push(stack, sizeof(ZSTD_stack));
|
|
||||||
return stackMem;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *ZSTD_stackAllocAll(void *opaque, size_t *size)
|
|
||||||
{
|
|
||||||
ZSTD_stack *stack = (ZSTD_stack *)opaque;
|
|
||||||
*size = (BYTE const *)stack->end - (BYTE *)ZSTD_PTR_ALIGN(stack->ptr);
|
|
||||||
return stack_push(stack, *size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *ZSTD_stackAlloc(void *opaque, size_t size)
|
|
||||||
{
|
|
||||||
ZSTD_stack *stack = (ZSTD_stack *)opaque;
|
|
||||||
return stack_push(stack, size);
|
|
||||||
}
|
|
||||||
void ZSTD_stackFree(void *opaque, void *address)
|
|
||||||
{
|
|
||||||
(void)opaque;
|
|
||||||
(void)address;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *ZSTD_malloc(size_t size, ZSTD_customMem customMem) { return customMem.customAlloc(customMem.opaque, size); }
|
|
||||||
|
|
||||||
void ZSTD_free(void *ptr, ZSTD_customMem customMem)
|
|
||||||
{
|
|
||||||
if (ptr != NULL)
|
|
||||||
customMem.customFree(customMem.opaque, ptr);
|
|
||||||
}
|
|
32
lib/zstd/zstd_common_module.c
Normal file
32
lib/zstd/zstd_common_module.c
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/compat.h>
|
||||||
|
|
||||||
|
#include "common/huf.h"
|
||||||
|
#include "common/fse.h"
|
||||||
|
#include "common/zstd_internal.h"
|
||||||
|
|
||||||
|
// Export symbols shared by compress and decompress into a common module
|
||||||
|
|
||||||
|
#undef ZSTD_isError /* defined within zstd_internal.h */
|
||||||
|
EXPORT_SYMBOL_GPL(FSE_readNCount);
|
||||||
|
EXPORT_SYMBOL_GPL(HUF_readStats);
|
||||||
|
EXPORT_SYMBOL_GPL(HUF_readStats_wksp);
|
||||||
|
EXPORT_SYMBOL_GPL(ZSTD_isError);
|
||||||
|
EXPORT_SYMBOL_GPL(ZSTD_getErrorName);
|
||||||
|
EXPORT_SYMBOL_GPL(ZSTD_getErrorCode);
|
||||||
|
EXPORT_SYMBOL_GPL(ZSTD_customMalloc);
|
||||||
|
EXPORT_SYMBOL_GPL(ZSTD_customCalloc);
|
||||||
|
EXPORT_SYMBOL_GPL(ZSTD_customFree);
|
||||||
|
|
||||||
|
MODULE_LICENSE("Dual BSD/GPL");
|
||||||
|
MODULE_DESCRIPTION("Zstd Common");
|
105
lib/zstd/zstd_decompress_module.c
Normal file
105
lib/zstd/zstd_decompress_module.c
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/compat.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
#include <linux/zstd.h>
|
||||||
|
|
||||||
|
#include "common/zstd_deps.h"
|
||||||
|
|
||||||
|
/* Common symbols. zstd_compress must depend on zstd_decompress. */
|
||||||
|
|
||||||
|
unsigned int zstd_is_error(size_t code)
|
||||||
|
{
|
||||||
|
return ZSTD_isError(code);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(zstd_is_error);
|
||||||
|
|
||||||
|
zstd_error_code zstd_get_error_code(size_t code)
|
||||||
|
{
|
||||||
|
return ZSTD_getErrorCode(code);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(zstd_get_error_code);
|
||||||
|
|
||||||
|
const char *zstd_get_error_name(size_t code)
|
||||||
|
{
|
||||||
|
return ZSTD_getErrorName(code);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(zstd_get_error_name);
|
||||||
|
|
||||||
|
/* Decompression symbols. */
|
||||||
|
|
||||||
|
size_t zstd_dctx_workspace_bound(void)
|
||||||
|
{
|
||||||
|
return ZSTD_estimateDCtxSize();
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(zstd_dctx_workspace_bound);
|
||||||
|
|
||||||
|
zstd_dctx *zstd_init_dctx(void *workspace, size_t workspace_size)
|
||||||
|
{
|
||||||
|
if (workspace == NULL)
|
||||||
|
return NULL;
|
||||||
|
return ZSTD_initStaticDCtx(workspace, workspace_size);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(zstd_init_dctx);
|
||||||
|
|
||||||
|
size_t zstd_decompress_dctx(zstd_dctx *dctx, void *dst, size_t dst_capacity,
|
||||||
|
const void *src, size_t src_size)
|
||||||
|
{
|
||||||
|
return ZSTD_decompressDCtx(dctx, dst, dst_capacity, src, src_size);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(zstd_decompress_dctx);
|
||||||
|
|
||||||
|
size_t zstd_dstream_workspace_bound(size_t max_window_size)
|
||||||
|
{
|
||||||
|
return ZSTD_estimateDStreamSize(max_window_size);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(zstd_dstream_workspace_bound);
|
||||||
|
|
||||||
|
zstd_dstream *zstd_init_dstream(size_t max_window_size, void *workspace,
|
||||||
|
size_t workspace_size)
|
||||||
|
{
|
||||||
|
if (workspace == NULL)
|
||||||
|
return NULL;
|
||||||
|
(void)max_window_size;
|
||||||
|
return ZSTD_initStaticDStream(workspace, workspace_size);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(zstd_init_dstream);
|
||||||
|
|
||||||
|
size_t zstd_reset_dstream(zstd_dstream *dstream)
|
||||||
|
{
|
||||||
|
return ZSTD_resetDStream(dstream);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(zstd_reset_dstream);
|
||||||
|
|
||||||
|
size_t zstd_decompress_stream(zstd_dstream *dstream, zstd_out_buffer *output,
|
||||||
|
zstd_in_buffer *input)
|
||||||
|
{
|
||||||
|
return ZSTD_decompressStream(dstream, output, input);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(zstd_decompress_stream);
|
||||||
|
|
||||||
|
size_t zstd_find_frame_compressed_size(const void *src, size_t src_size)
|
||||||
|
{
|
||||||
|
return ZSTD_findFrameCompressedSize(src, src_size);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(zstd_find_frame_compressed_size);
|
||||||
|
|
||||||
|
size_t zstd_get_frame_header(zstd_frame_header *header, const void *src,
|
||||||
|
size_t src_size)
|
||||||
|
{
|
||||||
|
return ZSTD_getFrameHeader(header, src, src_size);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(zstd_get_frame_header);
|
||||||
|
|
||||||
|
MODULE_LICENSE("Dual BSD/GPL");
|
||||||
|
MODULE_DESCRIPTION("Zstd Decompressor");
|
|
@ -1,253 +0,0 @@
|
||||||
/* SPDX-License-Identifier: (GPL-2.0 or BSD-3-Clause-Clear) */
|
|
||||||
/**
|
|
||||||
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef ZSTD_CCOMMON_H_MODULE
|
|
||||||
#define ZSTD_CCOMMON_H_MODULE
|
|
||||||
|
|
||||||
/*-*******************************************************
|
|
||||||
* Compiler specifics
|
|
||||||
*********************************************************/
|
|
||||||
#define FORCE_INLINE static __always_inline
|
|
||||||
#define FORCE_NOINLINE static noinline
|
|
||||||
|
|
||||||
/*-*************************************
|
|
||||||
* Dependencies
|
|
||||||
***************************************/
|
|
||||||
#include "error_private.h"
|
|
||||||
#include "mem.h"
|
|
||||||
#include <linux/compiler.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/xxhash.h>
|
|
||||||
#include <linux/zstd.h>
|
|
||||||
|
|
||||||
/*-*************************************
|
|
||||||
* shared macros
|
|
||||||
***************************************/
|
|
||||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
|
||||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
|
||||||
#define CHECK_F(f) \
|
|
||||||
{ \
|
|
||||||
size_t const errcod = f; \
|
|
||||||
if (ERR_isError(errcod)) \
|
|
||||||
return errcod; \
|
|
||||||
} /* check and Forward error code */
|
|
||||||
#define CHECK_E(f, e) \
|
|
||||||
{ \
|
|
||||||
size_t const errcod = f; \
|
|
||||||
if (ERR_isError(errcod)) \
|
|
||||||
return ERROR(e); \
|
|
||||||
} /* check and send Error code */
|
|
||||||
#define ZSTD_STATIC_ASSERT(c) \
|
|
||||||
{ \
|
|
||||||
enum { ZSTD_static_assert = 1 / (int)(!!(c)) }; \
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-*************************************
|
|
||||||
* Common constants
|
|
||||||
***************************************/
|
|
||||||
#define ZSTD_OPT_NUM (1 << 12)
|
|
||||||
#define ZSTD_DICT_MAGIC 0xEC30A437 /* v0.7+ */
|
|
||||||
|
|
||||||
#define ZSTD_REP_NUM 3 /* number of repcodes */
|
|
||||||
#define ZSTD_REP_CHECK (ZSTD_REP_NUM) /* number of repcodes to check by the optimal parser */
|
|
||||||
#define ZSTD_REP_MOVE (ZSTD_REP_NUM - 1)
|
|
||||||
#define ZSTD_REP_MOVE_OPT (ZSTD_REP_NUM)
|
|
||||||
static const U32 repStartValue[ZSTD_REP_NUM] = {1, 4, 8};
|
|
||||||
|
|
||||||
#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 ZSTD_WINDOWLOG_ABSOLUTEMIN 10
|
|
||||||
static const size_t ZSTD_fcs_fieldSize[4] = {0, 2, 4, 8};
|
|
||||||
static const size_t ZSTD_did_fieldSize[4] = {0, 1, 2, 4};
|
|
||||||
|
|
||||||
#define ZSTD_BLOCKHEADERSIZE 3 /* C standard doesn't allow `static const` variable to be init using another `static const` variable */
|
|
||||||
static const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE;
|
|
||||||
typedef enum { bt_raw, bt_rle, bt_compressed, bt_reserved } blockType_e;
|
|
||||||
|
|
||||||
#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 HufLog 12
|
|
||||||
typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingType_e;
|
|
||||||
|
|
||||||
#define LONGNBSEQ 0x7F00
|
|
||||||
|
|
||||||
#define MINMATCH 3
|
|
||||||
#define EQUAL_READ32 4
|
|
||||||
|
|
||||||
#define Litbits 8
|
|
||||||
#define MaxLit ((1 << Litbits) - 1)
|
|
||||||
#define MaxML 52
|
|
||||||
#define MaxLL 35
|
|
||||||
#define MaxOff 28
|
|
||||||
#define MaxSeq MAX(MaxLL, MaxML) /* Assumption : MaxOff < MaxLL,MaxML */
|
|
||||||
#define MLFSELog 9
|
|
||||||
#define LLFSELog 9
|
|
||||||
#define OffFSELog 8
|
|
||||||
|
|
||||||
static const U32 LL_bits[MaxLL + 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};
|
|
||||||
static const S16 LL_defaultNorm[MaxLL + 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};
|
|
||||||
#define LL_DEFAULTNORMLOG 6 /* for static allocation */
|
|
||||||
static const U32 LL_defaultNormLog = LL_DEFAULTNORMLOG;
|
|
||||||
|
|
||||||
static const U32 ML_bits[MaxML + 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};
|
|
||||||
static const S16 ML_defaultNorm[MaxML + 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};
|
|
||||||
#define ML_DEFAULTNORMLOG 6 /* for static allocation */
|
|
||||||
static const U32 ML_defaultNormLog = ML_DEFAULTNORMLOG;
|
|
||||||
|
|
||||||
static const S16 OF_defaultNorm[MaxOff + 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};
|
|
||||||
#define OF_DEFAULTNORMLOG 5 /* for static allocation */
|
|
||||||
static const U32 OF_defaultNormLog = OF_DEFAULTNORMLOG;
|
|
||||||
|
|
||||||
/*-*******************************************
|
|
||||||
* Shared functions to include for inlining
|
|
||||||
*********************************************/
|
|
||||||
ZSTD_STATIC void ZSTD_copy8(void *dst, const void *src) {
|
|
||||||
memcpy(dst, src, 8);
|
|
||||||
}
|
|
||||||
/*! ZSTD_wildcopy() :
|
|
||||||
* custom version of memcpy(), can copy up to 7 bytes too many (8 bytes if length==0) */
|
|
||||||
#define WILDCOPY_OVERLENGTH 8
|
|
||||||
ZSTD_STATIC void ZSTD_wildcopy(void *dst, const void *src, ptrdiff_t length)
|
|
||||||
{
|
|
||||||
const BYTE* ip = (const BYTE*)src;
|
|
||||||
BYTE* op = (BYTE*)dst;
|
|
||||||
BYTE* const oend = op + length;
|
|
||||||
/* Work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81388.
|
|
||||||
* Avoid the bad case where the loop only runs once by handling the
|
|
||||||
* special case separately. This doesn't trigger the bug because it
|
|
||||||
* doesn't involve pointer/integer overflow.
|
|
||||||
*/
|
|
||||||
if (length <= 8)
|
|
||||||
return ZSTD_copy8(dst, src);
|
|
||||||
do {
|
|
||||||
ZSTD_copy8(op, ip);
|
|
||||||
op += 8;
|
|
||||||
ip += 8;
|
|
||||||
} while (op < oend);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-*******************************************
|
|
||||||
* Private interfaces
|
|
||||||
*********************************************/
|
|
||||||
typedef struct ZSTD_stats_s ZSTD_stats_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
U32 off;
|
|
||||||
U32 len;
|
|
||||||
} ZSTD_match_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
U32 price;
|
|
||||||
U32 off;
|
|
||||||
U32 mlen;
|
|
||||||
U32 litlen;
|
|
||||||
U32 rep[ZSTD_REP_NUM];
|
|
||||||
} ZSTD_optimal_t;
|
|
||||||
|
|
||||||
typedef struct seqDef_s {
|
|
||||||
U32 offset;
|
|
||||||
U16 litLength;
|
|
||||||
U16 matchLength;
|
|
||||||
} seqDef;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
seqDef *sequencesStart;
|
|
||||||
seqDef *sequences;
|
|
||||||
BYTE *litStart;
|
|
||||||
BYTE *lit;
|
|
||||||
BYTE *llCode;
|
|
||||||
BYTE *mlCode;
|
|
||||||
BYTE *ofCode;
|
|
||||||
U32 longLengthID; /* 0 == no longLength; 1 == Lit.longLength; 2 == Match.longLength; */
|
|
||||||
U32 longLengthPos;
|
|
||||||
/* opt */
|
|
||||||
ZSTD_optimal_t *priceTable;
|
|
||||||
ZSTD_match_t *matchTable;
|
|
||||||
U32 *matchLengthFreq;
|
|
||||||
U32 *litLengthFreq;
|
|
||||||
U32 *litFreq;
|
|
||||||
U32 *offCodeFreq;
|
|
||||||
U32 matchLengthSum;
|
|
||||||
U32 matchSum;
|
|
||||||
U32 litLengthSum;
|
|
||||||
U32 litSum;
|
|
||||||
U32 offCodeSum;
|
|
||||||
U32 log2matchLengthSum;
|
|
||||||
U32 log2matchSum;
|
|
||||||
U32 log2litLengthSum;
|
|
||||||
U32 log2litSum;
|
|
||||||
U32 log2offCodeSum;
|
|
||||||
U32 factor;
|
|
||||||
U32 staticPrices;
|
|
||||||
U32 cachedPrice;
|
|
||||||
U32 cachedLitLength;
|
|
||||||
const BYTE *cachedLiterals;
|
|
||||||
} seqStore_t;
|
|
||||||
|
|
||||||
const seqStore_t *ZSTD_getSeqStore(const ZSTD_CCtx *ctx);
|
|
||||||
void ZSTD_seqToCodes(const seqStore_t *seqStorePtr);
|
|
||||||
int ZSTD_isSkipFrame(ZSTD_DCtx *dctx);
|
|
||||||
|
|
||||||
/*= Custom memory allocation functions */
|
|
||||||
typedef void *(*ZSTD_allocFunction)(void *opaque, size_t size);
|
|
||||||
typedef void (*ZSTD_freeFunction)(void *opaque, void *address);
|
|
||||||
typedef struct {
|
|
||||||
ZSTD_allocFunction customAlloc;
|
|
||||||
ZSTD_freeFunction customFree;
|
|
||||||
void *opaque;
|
|
||||||
} ZSTD_customMem;
|
|
||||||
|
|
||||||
void *ZSTD_malloc(size_t size, ZSTD_customMem customMem);
|
|
||||||
void ZSTD_free(void *ptr, ZSTD_customMem customMem);
|
|
||||||
|
|
||||||
/*====== stack allocation ======*/
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
void *ptr;
|
|
||||||
const void *end;
|
|
||||||
} ZSTD_stack;
|
|
||||||
|
|
||||||
#define ZSTD_ALIGN(x) ALIGN(x, sizeof(size_t))
|
|
||||||
#define ZSTD_PTR_ALIGN(p) PTR_ALIGN(p, sizeof(size_t))
|
|
||||||
|
|
||||||
ZSTD_customMem ZSTD_initStack(void *workspace, size_t workspaceSize);
|
|
||||||
|
|
||||||
void *ZSTD_stackAllocAll(void *opaque, size_t *size);
|
|
||||||
void *ZSTD_stackAlloc(void *opaque, size_t size);
|
|
||||||
void ZSTD_stackFree(void *opaque, void *address);
|
|
||||||
|
|
||||||
/*====== common function ======*/
|
|
||||||
|
|
||||||
ZSTD_STATIC U32 ZSTD_highbit32(U32 val) { return 31 - __builtin_clz(val); }
|
|
||||||
|
|
||||||
/* hidden functions */
|
|
||||||
|
|
||||||
/* ZSTD_invalidateRepCodes() :
|
|
||||||
* ensures next compression will not use repcodes from previous block.
|
|
||||||
* Note : only works with regular variant;
|
|
||||||
* do not use with extDict variant ! */
|
|
||||||
void ZSTD_invalidateRepCodes(ZSTD_CCtx *cctx);
|
|
||||||
|
|
||||||
size_t ZSTD_freeCCtx(ZSTD_CCtx *cctx);
|
|
||||||
size_t ZSTD_freeDCtx(ZSTD_DCtx *dctx);
|
|
||||||
size_t ZSTD_freeCDict(ZSTD_CDict *cdict);
|
|
||||||
size_t ZSTD_freeDDict(ZSTD_DDict *cdict);
|
|
||||||
size_t ZSTD_freeCStream(ZSTD_CStream *zcs);
|
|
||||||
size_t ZSTD_freeDStream(ZSTD_DStream *zds);
|
|
||||||
|
|
||||||
#endif /* ZSTD_CCOMMON_H_MODULE */
|
|
1004
lib/zstd/zstd_opt.h
1004
lib/zstd/zstd_opt.h
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue