Compare commits
142
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4340f46b2 | ||
|
|
d29bf941b9 | ||
|
|
969e6ef44f | ||
|
|
7f6a783862 | ||
|
|
2b2f3c6f64 | ||
|
|
4252621e26 | ||
|
|
ba55dc8b5e | ||
|
|
6dd958eea2 | ||
|
|
c85141caed | ||
|
|
a86a7097ec | ||
|
|
67478f4cb0 | ||
|
|
9b166d2291 | ||
|
|
3b27ed41fd | ||
|
|
7e00df4a49 | ||
|
|
004fd34fd9 | ||
|
|
7304a63c12 | ||
|
|
86e83e926f | ||
|
|
4946993f87 | ||
|
|
7f580f9ee8 | ||
|
|
0d58aaf6f0 | ||
|
|
fe5444bc66 | ||
|
|
51d82d5516 | ||
|
|
ed7ae4c9bd | ||
|
|
6e7ba3df2f | ||
|
|
82bc200f82 | ||
|
|
5e4ad557bc | ||
|
|
bd18095edc | ||
|
|
b600b5bafd | ||
|
|
00fc1ba8dd | ||
|
|
5db19b8685 | ||
|
|
6e930c13d1 | ||
|
|
76ac0b2d99 | ||
|
|
dc404119e5 | ||
|
|
96bb29aa14 | ||
|
|
c5d6dde502 | ||
|
|
ee1ed78fcb | ||
|
|
5b10345b26 | ||
|
|
e580dc6a4a | ||
|
|
8afb151c9b | ||
|
|
657946a913 | ||
|
|
fbd5ab7027 | ||
|
|
db1668a43b | ||
|
|
7c9669f272 | ||
|
|
1416bc0f07 | ||
|
|
8afcc80e07 | ||
|
|
e963800e27 | ||
|
|
754ae5cc0b | ||
|
|
e0065cf660 | ||
|
|
47c6a95d07 | ||
|
|
86b4fe5b45 | ||
|
|
dc27c36495 | ||
|
|
d0519d4b0c | ||
|
|
5705d9f25a | ||
|
|
b93598d6a4 | ||
|
|
e4ec427720 | ||
|
|
bbef058ae6 | ||
|
|
8074261d00 | ||
|
|
2cd15dd9a4 | ||
|
|
377abcc02c | ||
|
|
d6770f80af | ||
|
|
9fe50ed623 | ||
|
|
9b5b47ac93 | ||
|
|
824f75ea7c | ||
|
|
fac8c70859 | ||
|
|
d9c1e9125f | ||
|
|
aa800c4793 | ||
|
|
bc32b40b98 | ||
|
|
54a827fff0 | ||
|
|
e45a2aea9b | ||
|
|
3182ea2e64 | ||
|
|
e57b4114e9 | ||
|
|
02502191e5 | ||
|
|
f9de54acfb | ||
|
|
b555b7ef41 | ||
|
|
bdd0f6f046 | ||
|
|
60059df051 | ||
|
|
495b5269ea | ||
|
|
ea1f50bf73 | ||
|
|
60ca44b545 | ||
|
|
c994932788 | ||
|
|
763f8b5e45 | ||
|
|
6c41adfb28 | ||
|
|
ecf1778e23 | ||
|
|
9416195221 | ||
|
|
d56a350402 | ||
|
|
bfabd1d4dc | ||
|
|
ca306c1c84 | ||
|
|
b0a3ad96d3 | ||
|
|
cd53ac831b | ||
|
|
4791561c4a | ||
|
|
91ffe71ec8 | ||
|
|
c0dd960363 | ||
|
|
319c699991 | ||
|
|
8d1e97ea9c | ||
|
|
bfbec3c1ae | ||
|
|
df4e9bba25 | ||
|
|
9f0b8dfbe9 | ||
|
|
471aa385b3 | ||
|
|
c233bdbaee | ||
|
|
3095ca8c56 | ||
|
|
56f1f0e3dd | ||
|
|
8a4d0abc1c | ||
|
|
586df82a78 | ||
|
|
52a1d1c6dc | ||
|
|
5d8fdd1641 | ||
|
|
76cb38d085 | ||
|
|
f2a913862c | ||
|
|
6ee05a02b8 | ||
|
|
917a213254 | ||
|
|
77d5bc2d62 | ||
|
|
11e21f23cb | ||
|
|
6bb781e0f1 | ||
|
|
b8d4a3887f | ||
|
|
044fb4c057 | ||
|
|
62568c9a42 | ||
|
|
bbe77212ef | ||
|
|
bfad5568b5 | ||
|
|
23199b6daf | ||
|
|
1c23b64049 | ||
|
|
96f0cde31a | ||
|
|
7c3dea42ce | ||
|
|
e60f48c549 | ||
|
|
360238733a | ||
|
|
645563583e | ||
|
|
f97c2dbd39 | ||
|
|
aecf3b479c | ||
|
|
b72808a49b | ||
|
|
fe007ba8bd | ||
|
|
7d30795931 | ||
|
|
da0c157fc4 | ||
|
|
39d0c6cde7 | ||
|
|
02c44a7257 | ||
|
|
585bb51413 | ||
|
|
bb8a7601bc | ||
|
|
ebf275912a | ||
|
|
f2ea8932fc | ||
|
|
2c2ee2b4b0 | ||
|
|
c4f2490050 | ||
|
|
cbc5225d38 | ||
|
|
817995bb7a | ||
|
|
99b6d9f1a3 | ||
|
|
b9edd2f9fb |
@@ -19,3 +19,6 @@
|
||||
# Windows
|
||||
*.bat text eol=crlf
|
||||
*.cmd text eol=crlf
|
||||
|
||||
# .travis.yml merging
|
||||
.travis.yml merge=ours
|
||||
|
||||
+33
-13
@@ -1,4 +1,4 @@
|
||||
# Medium Tests: Run on all commits/PRs to dev branch
|
||||
# Long tests: run on commits to master branch/cron builds
|
||||
|
||||
language: c
|
||||
sudo: required
|
||||
@@ -6,21 +6,37 @@ dist: trusty
|
||||
matrix:
|
||||
include:
|
||||
# Ubuntu 14.04
|
||||
- env: Cmd='make gcc6install && CC=gcc-6 make clean uasan-test-zstd'
|
||||
- env: Cmd='make gcc6install libc6install && CC=gcc-6 make clean uasan-test-zstd32'
|
||||
- env: Cmd='make clang38install && CC=clang-3.8 make clean msan-test-zstd'
|
||||
- env: Cmd="make cxxtest && make clean && make gnu90build && make clean && make cmakebuild && make clean && make travis-install"
|
||||
|
||||
- env: Cmd='make gcc6install && CC=gcc-6 make clean uasan-fuzztest'
|
||||
- env: Cmd='make gcc6install libc6install && CC=gcc-6 CFLAGS=-m32 make clean uasan-fuzztest'
|
||||
- env: Cmd='make clang38install && CC=clang-3.8 make clean msan-fuzztest'
|
||||
- env: Cmd='make gcc6install && CC=gcc-6 make clean uasan-test'
|
||||
- env: Cmd='make gcc6install libc6install && CC=gcc-6 make clean uasan-test32'
|
||||
- env: Cmd='make clang38install && CC=clang-3.8 make clean msan-test'
|
||||
- env: Cmd='make clang38install && CC=clang-3.8 make clean tsan-test-zstream'
|
||||
|
||||
- env: Cmd='make valgrindinstall && make -C tests clean valgrindTest'
|
||||
|
||||
- env: Cmd='make arminstall && make armfuzz'
|
||||
- env: Cmd='make arminstall && make aarch64fuzz'
|
||||
- env: Cmd='make ppcinstall && make ppcfuzz'
|
||||
- env: Cmd='make ppcinstall && make ppc64fuzz'
|
||||
- env: Cmd='make arminstall && make armtest'
|
||||
- env: Cmd='make arminstall && make aarch64test'
|
||||
- env: Cmd='make ppcinstall && make ppctest'
|
||||
- env: Cmd='make ppcinstall && make ppc64test'
|
||||
|
||||
- env: Cmd='make gpp6install valgrindinstall && make -C zlibWrapper test && make -C zlibWrapper valgrindTest'
|
||||
- env: Cmd='make gcc6install && CC=gcc-6 make uasan-test-zstd-nolegacy'
|
||||
- env: Cmd='make gcc6install && CC=gcc-6 make uasan-test-zbuff'
|
||||
|
||||
- env: Cmd='make -j uasanregressiontest'
|
||||
- env: Cmd='make -j msanregressiontest'
|
||||
|
||||
- env: Cmd='make -C tests versionsTest && make lz4install && make clean && make -C tests test-lz4'
|
||||
|
||||
# OS X Mavericks
|
||||
- env: Cmd="make test"
|
||||
os: osx
|
||||
|
||||
before_install:
|
||||
- if [ `uname` = "Darwin" ]; then brew update; fi
|
||||
|
||||
install:
|
||||
- if [ `uname` = "Darwin" ]; then brew install xz; fi
|
||||
|
||||
git:
|
||||
depth: 1
|
||||
@@ -33,7 +49,11 @@ branches:
|
||||
script:
|
||||
- JOB_NUMBER=$(echo $TRAVIS_JOB_NUMBER | sed -e 's:[0-9][0-9]*\.\(.*\):\1:')
|
||||
- echo JOB_NUMBER=$JOB_NUMBER TRAVIS_BRANCH=$TRAVIS_BRANCH TRAVIS_EVENT_TYPE=$TRAVIS_EVENT_TYPE TRAVIS_PULL_REQUEST=$TRAVIS_PULL_REQUEST
|
||||
- export FUZZERTEST=-T2mn;
|
||||
- export FUZZERTEST=-T5mn;
|
||||
export ZSTREAM_TESTTIME=-T2mn;
|
||||
export DECODECORPUS_TESTTIME=-T1mn;
|
||||
if [ "$TRAVIS_EVENT_TYPE" = "cron" ]; then
|
||||
git fetch origin dev;
|
||||
git checkout -f FETCH_HEAD;
|
||||
fi;
|
||||
sh -c "$Cmd" || travis_terminate 1;
|
||||
|
||||
@@ -12,6 +12,7 @@ ZSTDDIR = lib
|
||||
BUILDIR = build
|
||||
ZWRAPDIR = zlibWrapper
|
||||
TESTDIR = tests
|
||||
FUZZDIR = $(TESTDIR)/fuzz
|
||||
|
||||
# Define nul output
|
||||
VOID = /dev/null
|
||||
@@ -97,6 +98,7 @@ clean:
|
||||
@$(MAKE) -C examples/ $@ > $(VOID)
|
||||
@$(MAKE) -C contrib/gen_html $@ > $(VOID)
|
||||
@$(RM) zstd$(EXT) zstdmt$(EXT) tmp*
|
||||
@$(RM) -r lz4
|
||||
@echo Cleaning completed
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
@@ -111,7 +113,7 @@ CMAKE_PARAMS = -DZSTD_BUILD_CONTRIB:BOOL=ON -DZSTD_BUILD_STATIC:BOOL=ON -DZSTD_B
|
||||
list:
|
||||
@$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' | xargs
|
||||
|
||||
.PHONY: install clangtest gpptest armtest usan asan uasan
|
||||
.PHONY: install clangtest armtest usan asan uasan
|
||||
install:
|
||||
@$(MAKE) -C $(ZSTDDIR) $@
|
||||
@$(MAKE) -C $(PRGDIR) $@
|
||||
@@ -178,8 +180,10 @@ ppcfuzz: clean
|
||||
ppc64fuzz: clean
|
||||
CC=powerpc-linux-gnu-gcc QEMU_SYS=qemu-ppc64-static MOREFLAGS="-m64 -static" FUZZER_FLAGS=--no-big-tests $(MAKE) -C $(TESTDIR) fuzztest
|
||||
|
||||
gpptest: clean
|
||||
CC=$(CXX) $(MAKE) -C $(PRGDIR) all CFLAGS="-O3 -Wall -Wextra -Wundef -Wshadow -Wcast-align -Werror"
|
||||
.PHONY: cxxtest
|
||||
cxxtest: CXXFLAGS += -Wall -Wextra -Wundef -Wshadow -Wcast-align -Werror
|
||||
cxxtest: clean
|
||||
$(MAKE) -C $(PRGDIR) all CC="$(CXX) -Wno-deprecated" CFLAGS="$(CXXFLAGS)" # adding -Wno-deprecated to avoid clang++ warning on dealing with C files directly
|
||||
|
||||
gcc5test: clean
|
||||
gcc-5 -v
|
||||
@@ -215,6 +219,15 @@ arm-ppc-compilation:
|
||||
$(MAKE) -C $(PRGDIR) clean zstd CC=powerpc-linux-gnu-gcc QEMU_SYS=qemu-ppc-static ZSTDRTTEST= MOREFLAGS="-Werror -Wno-attributes -static"
|
||||
$(MAKE) -C $(PRGDIR) clean zstd CC=powerpc-linux-gnu-gcc QEMU_SYS=qemu-ppc64-static ZSTDRTTEST= MOREFLAGS="-m64 -static"
|
||||
|
||||
regressiontest:
|
||||
$(MAKE) -C $(FUZZDIR) regressiontest
|
||||
|
||||
uasanregressiontest:
|
||||
$(MAKE) -C $(FUZZDIR) regressiontest CC=clang CXX=clang++ CFLAGS="-O3 -fsanitize=address,undefined" CXXFLAGS="-O3 -fsanitize=address,undefined"
|
||||
|
||||
msanregressiontest:
|
||||
$(MAKE) -C $(FUZZDIR) regressiontest CC=clang CXX=clang++ CFLAGS="-O3 -fsanitize=memory" CXXFLAGS="-O3 -fsanitize=memory"
|
||||
|
||||
# run UBsan with -fsanitize-recover=signed-integer-overflow
|
||||
# due to a bug in UBsan when doing pointer subtraction
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63303
|
||||
@@ -274,6 +287,10 @@ gpp6install: apt-add-repo
|
||||
clang38install:
|
||||
APT_PACKAGES="clang-3.8" $(MAKE) apt-install
|
||||
|
||||
# Ubuntu 14.04 ships a too-old lz4
|
||||
lz4install:
|
||||
[ -e lz4 ] || git clone https://github.com/lz4/lz4 && sudo $(MAKE) -C lz4 install
|
||||
|
||||
endif
|
||||
|
||||
|
||||
@@ -284,7 +301,7 @@ endif
|
||||
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#make tests validated only for MSYS, Linux, OSX, kFreeBSD and Hurd targets
|
||||
# target specific tests
|
||||
#------------------------------------------------------------------------
|
||||
ifneq (,$(filter $(HOST_OS),MSYS POSIX))
|
||||
cmakebuild:
|
||||
@@ -294,38 +311,38 @@ cmakebuild:
|
||||
cd $(BUILDIR)/cmake/build ; cmake -DCMAKE_INSTALL_PREFIX:PATH=~/install_test_dir $(CMAKE_PARAMS) .. ; $(MAKE) install ; $(MAKE) uninstall
|
||||
|
||||
c90build: clean
|
||||
gcc -v
|
||||
$(CC) -v
|
||||
CFLAGS="-std=c90" $(MAKE) allmost # will fail, due to missing support for `long long`
|
||||
|
||||
gnu90build: clean
|
||||
gcc -v
|
||||
$(CC) -v
|
||||
CFLAGS="-std=gnu90" $(MAKE) allmost
|
||||
|
||||
c99build: clean
|
||||
gcc -v
|
||||
$(CC) -v
|
||||
CFLAGS="-std=c99" $(MAKE) allmost
|
||||
|
||||
gnu99build: clean
|
||||
gcc -v
|
||||
$(CC) -v
|
||||
CFLAGS="-std=gnu99" $(MAKE) allmost
|
||||
|
||||
c11build: clean
|
||||
gcc -v
|
||||
$(CC) -v
|
||||
CFLAGS="-std=c11" $(MAKE) allmost
|
||||
|
||||
bmix64build: clean
|
||||
gcc -v
|
||||
$(CC) -v
|
||||
CFLAGS="-O3 -mbmi -Werror" $(MAKE) -C $(TESTDIR) test
|
||||
|
||||
bmix32build: clean
|
||||
gcc -v
|
||||
$(CC) -v
|
||||
CFLAGS="-O3 -mbmi -mx32 -Werror" $(MAKE) -C $(TESTDIR) test
|
||||
|
||||
bmi32build: clean
|
||||
gcc -v
|
||||
$(CC) -v
|
||||
CFLAGS="-O3 -mbmi -m32 -Werror" $(MAKE) -C $(TESTDIR) test
|
||||
|
||||
staticAnalyze: clean
|
||||
gcc -v
|
||||
$(CC) -v
|
||||
CPPFLAGS=-g scan-build --status-bugs -v $(MAKE) all
|
||||
endif
|
||||
|
||||
@@ -1,14 +1,25 @@
|
||||
v1.3.2
|
||||
new : long range mode, using --long command, by Stella Lau (@stellamplau)
|
||||
license : changed /examples license to BSD + GPLv2
|
||||
license : fix a few header files to reflect new license (#825)
|
||||
new : ability to generate and decode magicless frames (#591)
|
||||
changed : maximum nb of threads reduced to 200, to avoid address space exhaustion in 32-bits mode
|
||||
fix : multi-threading compression works with custom allocators
|
||||
fix : a rare compression bug when compression generates very large distances (only possible at --ultra -22)
|
||||
fix : ZSTD_sizeof_CStream() was over-evaluating memory usage
|
||||
fix : a rare compression bug when compression generates very large distances and bunch of other conditions (only possible at --ultra -22)
|
||||
fix : 32-bits build can now decode large offsets (levels 21+)
|
||||
cli : added LZ4 frame support by default, by Felix Handte (@felixhandte)
|
||||
cli : improved --list output
|
||||
cli : new : can split input file for dictionary training, using command -B#
|
||||
cli : new : clean operation artefact on Ctrl-C interruption
|
||||
cli : fix : do not change /dev/null permissions when using command -t with root access, reported by @mike155 (#851)
|
||||
cli : fix : write file size in header in multiple-files mode
|
||||
api : added macro ZSTD_COMPRESSBOUND() for static allocation
|
||||
api : experimental : new advanced decompression API
|
||||
api : fix : sizeof_CCtx() used to over-estimate
|
||||
build: fix : no-multithread variant compiles without pool.c dependency, reported by Mitchell Blank Jr (@mitchblank) (#819)
|
||||
build: better compatibility with reproducible builds, by Bernhard M. Wiedemann (@bmwiedemann) (#818)
|
||||
example : added streaming_memory_usage
|
||||
license : changed /examples license to BSD + GPLv2
|
||||
license : fix a few header files to reflect new license (#825)
|
||||
|
||||
v1.3.1
|
||||
New license : BSD + GPLv2
|
||||
|
||||
+6
-1
@@ -45,7 +45,7 @@ test:
|
||||
parallel: true
|
||||
- ? |
|
||||
if [[ "$CIRCLE_NODE_INDEX" == "0" ]] ; then make ppc64build && make clean; fi &&
|
||||
if [[ "$CIRCLE_NODE_TOTAL" < "2" ]] || [[ "$CIRCLE_NODE_INDEX" == "1" ]]; then make gcc7build && make clean; fi #could add another test here
|
||||
if [[ "$CIRCLE_NODE_TOTAL" < "2" ]] || [[ "$CIRCLE_NODE_INDEX" == "1" ]]; then make gcc7build && make clean; fi
|
||||
:
|
||||
parallel: true
|
||||
- ? |
|
||||
@@ -53,6 +53,11 @@ test:
|
||||
if [[ "$CIRCLE_NODE_TOTAL" < "2" ]] || [[ "$CIRCLE_NODE_INDEX" == "1" ]]; then make -C tests test-legacy test-longmatch test-symbols && make clean; fi
|
||||
:
|
||||
parallel: true
|
||||
- ? |
|
||||
if [[ "$CIRCLE_NODE_INDEX" == "0" ]] ; then make -j regressiontest && make clean; fi &&
|
||||
if [[ "$CIRCLE_NODE_TOTAL" < "2" ]] || [[ "$CIRCLE_NODE_INDEX" == "1" ]]; then true; fi # Could add another test here
|
||||
:
|
||||
parallel: true
|
||||
|
||||
post:
|
||||
- echo Circle CI tests finished
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* *********************************************************
|
||||
|
||||
+178
-55
@@ -1,10 +1,10 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>zstd 1.3.1 Manual</title>
|
||||
<title>zstd 1.3.2 Manual</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>zstd 1.3.1 Manual</h1>
|
||||
<h1>zstd 1.3.2 Manual</h1>
|
||||
<hr>
|
||||
<a name="Contents"></a><h2>Contents</h2>
|
||||
<ol>
|
||||
@@ -27,8 +27,8 @@
|
||||
<li><a href="#Chapter17">Buffer-less and synchronous inner streaming functions</a></li>
|
||||
<li><a href="#Chapter18">Buffer-less streaming compression (synchronous mode)</a></li>
|
||||
<li><a href="#Chapter19">Buffer-less streaming decompression (synchronous mode)</a></li>
|
||||
<li><a href="#Chapter20">ZSTD_CCtx_params</a></li>
|
||||
<li><a href="#Chapter21">Block functions</a></li>
|
||||
<li><a href="#Chapter20">New advanced API (experimental)</a></li>
|
||||
<li><a href="#Chapter21">Block level API</a></li>
|
||||
</ol>
|
||||
<hr>
|
||||
<a name="Chapter1"></a><h2>Introduction</h2><pre>
|
||||
@@ -111,10 +111,11 @@ unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize);
|
||||
@return : content size to be decompressed, as a 64-bits value _if known and not empty_, 0 otherwise.
|
||||
</p></pre><BR>
|
||||
|
||||
<h3>Helper functions</h3><pre></pre><b><pre>int ZSTD_maxCLevel(void); </b>/*!< maximum compression level available */<b>
|
||||
<h3>Helper functions</h3><pre></pre><b><pre>#define ZSTD_COMPRESSBOUND(srcSize) ((srcSize) + ((srcSize)>>8) + (((srcSize) < 128 KB) ? ((128 KB - (srcSize)) >> 11) </b>/* margin, from 64 to 0 */ : 0)) /* this formula ensures that bound(A) + bound(B) <= bound(A+B) as long as A and B >= 128 KB */<b>
|
||||
size_t ZSTD_compressBound(size_t srcSize); </b>/*!< maximum compressed size in worst case scenario */<b>
|
||||
unsigned ZSTD_isError(size_t code); </b>/*!< tells if a `size_t` function result is an error code */<b>
|
||||
const char* ZSTD_getErrorName(size_t code); </b>/*!< provides readable string from an error code */<b>
|
||||
int ZSTD_maxCLevel(void); </b>/*!< maximum compression level available */<b>
|
||||
</pre></b><BR>
|
||||
<a name="Chapter4"></a><h2>Explicit memory management</h2><pre></pre>
|
||||
|
||||
@@ -399,33 +400,33 @@ size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds);
|
||||
size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict);
|
||||
size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict);
|
||||
</b><p> These functions give the current memory usage of selected object.
|
||||
Object memory usage can evolve if it's re-used multiple times.
|
||||
Object memory usage can evolve when re-used multiple times.
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>size_t ZSTD_estimateCCtxSize(int compressionLevel);
|
||||
size_t ZSTD_estimateCCtxSize_advanced_usingCParams(ZSTD_compressionParameters cParams);
|
||||
size_t ZSTD_estimateCCtxSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* params);
|
||||
size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams);
|
||||
size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params);
|
||||
size_t ZSTD_estimateDCtxSize(void);
|
||||
</b><p> These functions make it possible to estimate memory usage
|
||||
of a future {D,C}Ctx, before its creation.
|
||||
ZSTD_estimateCCtxSize() will provide a budget large enough for any compression level up to selected one.
|
||||
It will also consider src size to be arbitrarily "large", which is worst case.
|
||||
If srcSize is known to always be small, ZSTD_estimateCCtxSize_advanced_usingCParams() can provide a tighter estimation.
|
||||
ZSTD_estimateCCtxSize_advanced_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
|
||||
ZSTD_estimateCCtxSize_advanced_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is > 1.
|
||||
If srcSize is known to always be small, ZSTD_estimateCCtxSize_usingCParams() can provide a tighter estimation.
|
||||
ZSTD_estimateCCtxSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
|
||||
ZSTD_estimateCCtxSize_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is > 1.
|
||||
Note : CCtx estimation is only correct for single-threaded compression
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>size_t ZSTD_estimateCStreamSize(int compressionLevel);
|
||||
size_t ZSTD_estimateCStreamSize_advanced_usingCParams(ZSTD_compressionParameters cParams);
|
||||
size_t ZSTD_estimateCStreamSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* params);
|
||||
size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams);
|
||||
size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params);
|
||||
size_t ZSTD_estimateDStreamSize(size_t windowSize);
|
||||
size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize);
|
||||
</b><p> ZSTD_estimateCStreamSize() will provide a budget large enough for any compression level up to selected one.
|
||||
It will also consider src size to be arbitrarily "large", which is worst case.
|
||||
If srcSize is known to always be small, ZSTD_estimateCStreamSize_advanced_usingCParams() can provide a tighter estimation.
|
||||
ZSTD_estimateCStreamSize_advanced_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
|
||||
ZSTD_estimateCStreamSize_advanced_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is set to a value > 1.
|
||||
If srcSize is known to always be small, ZSTD_estimateCStreamSize_usingCParams() can provide a tighter estimation.
|
||||
ZSTD_estimateCStreamSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
|
||||
ZSTD_estimateCStreamSize_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is set to a value > 1.
|
||||
Note : CStream estimation is only correct for single-threaded compression.
|
||||
ZSTD_DStream memory budget depends on window Size.
|
||||
This information can be passed manually, using ZSTD_estimateDStreamSize,
|
||||
@@ -436,8 +437,8 @@ size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize);
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>typedef enum {
|
||||
ZSTD_dlm_byCopy = 0, </b>/* Copy dictionary content internally. */<b>
|
||||
ZSTD_dlm_byRef, </b>/* Reference dictionary content -- the dictionary buffer must outlives its users. */<b>
|
||||
ZSTD_dlm_byCopy = 0, </b>/**< Copy dictionary content internally */<b>
|
||||
ZSTD_dlm_byRef, </b>/**< Reference dictionary content -- the dictionary buffer must outlive its users. */<b>
|
||||
} ZSTD_dictLoadMethod_e;
|
||||
</b></pre><BR>
|
||||
<pre><b>size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel);
|
||||
@@ -646,18 +647,18 @@ size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, const ZSTD_CDict*
|
||||
@return : 0, or an error code (which can be tested using ZSTD_isError())
|
||||
</p></pre><BR>
|
||||
|
||||
<h3>Advanced Streaming decompression functions</h3><pre></pre><b><pre>typedef enum { DStream_p_maxWindowSize } ZSTD_DStreamParameter_e;
|
||||
ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem);
|
||||
<h3>Advanced Streaming decompression functions</h3><pre></pre><b><pre>ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem);
|
||||
ZSTD_DStream* ZSTD_initStaticDStream(void* workspace, size_t workspaceSize); </b>/**< same as ZSTD_initStaticDCtx() */<b>
|
||||
size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, ZSTD_DStreamParameter_e paramType, unsigned paramValue);
|
||||
size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); </b>/**< note: a dict will not be used if dict == NULL or dictSize < 8 */<b>
|
||||
size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict); </b>/**< note : ddict will just be referenced, and must outlive decompression session */<b>
|
||||
typedef enum { DStream_p_maxWindowSize } ZSTD_DStreamParameter_e;
|
||||
size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, ZSTD_DStreamParameter_e paramType, unsigned paramValue); </b>/* obsolete : this API will be removed in a future version */<b>
|
||||
size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); </b>/**< note: no dictionary will be used if dict == NULL or dictSize < 8 */<b>
|
||||
size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict); </b>/**< note : ddict is referenced, it must outlive decompression session */<b>
|
||||
size_t ZSTD_resetDStream(ZSTD_DStream* zds); </b>/**< re-use decompression parameters from previous init; saves dictionary loading */<b>
|
||||
</pre></b><BR>
|
||||
<a name="Chapter17"></a><h2>Buffer-less and synchronous inner streaming functions</h2><pre>
|
||||
This is an advanced API, giving full control over buffer management, for users which need direct control over memory.
|
||||
But it's also a complex one, with many restrictions (documented below).
|
||||
Prefer using normal streaming API for an easier experience
|
||||
But it's also a complex one, with several restrictions, documented below.
|
||||
Prefer normal streaming API for an easier experience.
|
||||
|
||||
<BR></pre>
|
||||
|
||||
@@ -673,8 +674,8 @@ size_t ZSTD_resetDStream(ZSTD_DStream* zds); </b>/**< re-use decompression para
|
||||
|
||||
Then, consume your input using ZSTD_compressContinue().
|
||||
There are some important considerations to keep in mind when using this advanced function :
|
||||
- ZSTD_compressContinue() has no internal buffer. It uses externally provided buffer only.
|
||||
- Interface is synchronous : input is consumed entirely and produce 1+ (or more) compressed blocks.
|
||||
- ZSTD_compressContinue() has no internal buffer. It uses externally provided buffers only.
|
||||
- Interface is synchronous : input is consumed entirely and produces 1+ compressed blocks.
|
||||
- Caller must ensure there is enough space in `dst` to store compressed data under worst case scenario.
|
||||
Worst case evaluation is provided by ZSTD_compressBound().
|
||||
ZSTD_compressContinue() doesn't guarantee recover after a failed compression.
|
||||
@@ -685,9 +686,9 @@ size_t ZSTD_resetDStream(ZSTD_DStream* zds); </b>/**< re-use decompression para
|
||||
|
||||
Finish a frame with ZSTD_compressEnd(), which will write the last block(s) and optional checksum.
|
||||
It's possible to use srcSize==0, in which case, it will write a final empty block to end the frame.
|
||||
Without last block mark, frames will be considered unfinished (corrupted) by decoders.
|
||||
Without last block mark, frames are considered unfinished (hence corrupted) by compliant decoders.
|
||||
|
||||
`ZSTD_CCtx` object can be re-used (ZSTD_compressBegin()) to compress some new frame.
|
||||
`ZSTD_CCtx` object can be re-used (ZSTD_compressBegin()) to compress again.
|
||||
<BR></pre>
|
||||
|
||||
<h3>Buffer-less streaming compression functions</h3><pre></pre><b><pre>size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel);
|
||||
@@ -783,15 +784,38 @@ size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long
|
||||
</pre></b><BR>
|
||||
<pre><b>typedef enum { ZSTDnit_frameHeader, ZSTDnit_blockHeader, ZSTDnit_block, ZSTDnit_lastBlock, ZSTDnit_checksum, ZSTDnit_skippableFrame } ZSTD_nextInputType_e;
|
||||
</b></pre><BR>
|
||||
<h3>New advanced API (experimental, and compression only)</h3><pre></pre><b><pre></pre></b><BR>
|
||||
<a name="Chapter20"></a><h2>New advanced API (experimental)</h2><pre></pre>
|
||||
|
||||
<pre><b>typedef enum {
|
||||
</b>/* Question : should we have a format ZSTD_f_auto ?<b>
|
||||
* For the time being, it would mean exactly the same as ZSTD_f_zstd1.
|
||||
* But, in the future, should several formats be supported,
|
||||
* on the compression side, it would mean "default format".
|
||||
* On the decompression side, it would mean "multi format",
|
||||
* and ZSTD_f_zstd1 could be reserved to mean "accept *only* zstd frames".
|
||||
* Since meaning is a little different, another option could be to define different enums for compression and decompression.
|
||||
* This question could be kept for later, when there are actually multiple formats to support,
|
||||
* but there is also the question of pinning enum values, and pinning value `0` is especially important */
|
||||
ZSTD_f_zstd1 = 0, </b>/* zstd frame format, specified in zstd_compression_format.md (default) */<b>
|
||||
ZSTD_f_zstd1_magicless, </b>/* Variant of zstd frame format, without initial 4-bytes magic number.<b>
|
||||
* Useful to save 4 bytes per generated frame.
|
||||
* Decoder cannot recognise automatically this format, requiring instructions. */
|
||||
} ZSTD_format_e;
|
||||
</b></pre><BR>
|
||||
<pre><b>typedef enum {
|
||||
</b>/* compression format */<b>
|
||||
ZSTD_p_format = 10, </b>/* See ZSTD_format_e enum definition.<b>
|
||||
* Cast selected format as unsigned for ZSTD_CCtx_setParameter() compatibility. */
|
||||
|
||||
</b>/* compression parameters */<b>
|
||||
ZSTD_p_compressionLevel=100, </b>/* Update all compression parameters according to pre-defined cLevel table<b>
|
||||
* Default level is ZSTD_CLEVEL_DEFAULT==3.
|
||||
* Special: value 0 means "do not change cLevel". */
|
||||
ZSTD_p_windowLog, </b>/* Maximum allowed back-reference distance, expressed as power of 2.<b>
|
||||
* Must be clamped between ZSTD_WINDOWLOG_MIN and ZSTD_WINDOWLOG_MAX.
|
||||
* Special: value 0 means "do not change windowLog". */
|
||||
* Special: value 0 means "do not change windowLog".
|
||||
* Note: Using a window size greater than ZSTD_MAXWINDOWSIZE_DEFAULT (default: 2^27)
|
||||
* requires setting the maximum window size at least as large during decompression. */
|
||||
ZSTD_p_hashLog, </b>/* Size of the probe table, as a power of 2.<b>
|
||||
* Resulting table size is (1 << (hashLog+2)).
|
||||
* Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX.
|
||||
@@ -859,7 +883,7 @@ size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long
|
||||
* Larger values increase memory usage and compression ratio, but decrease
|
||||
* compression speed.
|
||||
* Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX
|
||||
* (default: 20). */
|
||||
* (default: windowlog - 7). */
|
||||
ZSTD_p_ldmMinMatch, </b>/* Minimum size of searched matches for long distance matcher.<b>
|
||||
* Larger/too small values usually decrease compression ratio.
|
||||
* Must be clamped between ZSTD_LDM_MINMATCH_MIN
|
||||
@@ -949,7 +973,7 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t
|
||||
<pre><b>typedef enum {
|
||||
ZSTD_e_continue=0, </b>/* collect more data, encoder transparently decides when to output result, for optimal conditions */<b>
|
||||
ZSTD_e_flush, </b>/* flush any data provided so far - frame will continue, future data can still reference previous data for better compression */<b>
|
||||
ZSTD_e_end </b>/* flush any remaining data and ends current frame. Any future compression starts a new frame. */<b>
|
||||
ZSTD_e_end </b>/* flush any remaining data and close current frame. Any additional data starts a new frame. */<b>
|
||||
} ZSTD_EndDirective;
|
||||
</b></pre><BR>
|
||||
<pre><b>size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
|
||||
@@ -959,8 +983,8 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t
|
||||
</b><p> Behave about the same as ZSTD_compressStream. To note :
|
||||
- Compression parameters are pushed into CCtx before starting compression, using ZSTD_CCtx_setParameter()
|
||||
- Compression parameters cannot be changed once compression is started.
|
||||
- *dstPos must be <= dstCapacity, *srcPos must be <= srcSize
|
||||
- *dspPos and *srcPos will be updated. They are guaranteed to remain below their respective limit.
|
||||
- outpot->pos must be <= dstCapacity, input->pos must be <= srcSize
|
||||
- outpot->pos and input->pos will be updated. They are guaranteed to remain below their respective limit.
|
||||
- @return provides the minimum amount of data still to flush from internal buffers
|
||||
or an error code, which can be tested using ZSTD_isError().
|
||||
if @return != 0, flush is not fully completed, there is some data left within internal buffers.
|
||||
@@ -976,6 +1000,7 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t
|
||||
Useful after an error, or to interrupt an ongoing compression job and start a new one.
|
||||
Any internal data not yet flushed is cancelled.
|
||||
Dictionary (if any) is dropped.
|
||||
All parameters are back to default values.
|
||||
It's possible to modify compression parameters after a reset.
|
||||
|
||||
</p></pre><BR>
|
||||
@@ -987,26 +1012,30 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t
|
||||
ZSTD_EndDirective endOp);
|
||||
</b><p> Same as ZSTD_compress_generic(),
|
||||
but using only integral types as arguments.
|
||||
Argument list is larger and less expressive than ZSTD_{in,out}Buffer,
|
||||
Argument list is larger than ZSTD_{in,out}Buffer,
|
||||
but can be helpful for binders from dynamic languages
|
||||
which have troubles handling structures containing memory pointers.
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<a name="Chapter20"></a><h2>ZSTD_CCtx_params</h2><pre>
|
||||
<pre><b>ZSTD_CCtx_params* ZSTD_createCCtxParams(void);
|
||||
</b><p> Quick howto :
|
||||
- ZSTD_createCCtxParams() : Create a ZSTD_CCtx_params structure
|
||||
- ZSTD_CCtxParam_setParameter() : Push parameters one by one into an
|
||||
existing ZSTD_CCtx_params structure. This is similar to
|
||||
ZSTD_CCtx_setParameter().
|
||||
- ZSTD_CCtx_setParametersUsingCCtxParams() : Apply parameters to an existing CCtx. These
|
||||
parameters will be applied to all subsequent compression jobs.
|
||||
- ZSTD_CCtxParam_setParameter() : Push parameters one by one into
|
||||
an existing ZSTD_CCtx_params structure.
|
||||
This is similar to
|
||||
ZSTD_CCtx_setParameter().
|
||||
- ZSTD_CCtx_setParametersUsingCCtxParams() : Apply parameters to
|
||||
an existing CCtx.
|
||||
These parameters will be applied to
|
||||
all subsequent compression jobs.
|
||||
- ZSTD_compress_generic() : Do compression using the CCtx.
|
||||
- ZSTD_freeCCtxParams() : Free the memory.
|
||||
|
||||
This can be used with ZSTD_estimateCCtxSize_opaque() for static allocation
|
||||
for single-threaded compression.
|
||||
This can be used with ZSTD_estimateCCtxSize_advanced_usingCCtxParams()
|
||||
for static allocation for single-threaded compression.
|
||||
|
||||
<BR></pre>
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>size_t ZSTD_resetCCtxParams(ZSTD_CCtx_params* params);
|
||||
</b><p> Reset params to default, with the default compression level.
|
||||
@@ -1030,22 +1059,116 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t
|
||||
Set one compression parameter, selected by enum ZSTD_cParameter.
|
||||
Parameters must be applied to a ZSTD_CCtx using ZSTD_CCtx_setParametersUsingCCtxParams().
|
||||
Note : when `value` is an enum, cast it to unsigned for proper type checking.
|
||||
@result : 0, or an error code (which can be tested with ZSTD_isError()).
|
||||
@result : 0, or an error code (which can be tested with ZSTD_isError()).
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>size_t ZSTD_CCtx_setParametersUsingCCtxParams(
|
||||
ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params);
|
||||
</b><p> Apply a set of ZSTD_CCtx_params to the compression context.
|
||||
This must be done before the dictionary is loaded.
|
||||
The pledgedSrcSize is treated as unknown.
|
||||
Multithreading parameters are applied only if nbThreads > 1.
|
||||
</b><p> Apply a set of ZSTD_CCtx_params to the compression context.
|
||||
This must be done before the dictionary is loaded.
|
||||
The pledgedSrcSize is treated as unknown.
|
||||
Multithreading parameters are applied only if nbThreads > 1.
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<a name="Chapter21"></a><h2>Block functions</h2><pre>
|
||||
Block functions produce and decode raw zstd blocks, without frame metadata.
|
||||
Frame metadata cost is typically ~18 bytes, which can be non-negligible for very small blocks (< 100 bytes).
|
||||
<h3>Advanced parameters for decompression API</h3><pre></pre><b><pre></pre></b><BR>
|
||||
<pre><b>size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); </b>/* not implemented */<b>
|
||||
size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); </b>/* not implemented */<b>
|
||||
size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictMode_e dictMode); </b>/* not implemented */<b>
|
||||
</b><p> Create an internal DDict from dict buffer,
|
||||
to be used to decompress next frames.
|
||||
@result : 0, or an error code (which can be tested with ZSTD_isError()).
|
||||
Special : Adding a NULL (or 0-size) dictionary invalidates any previous dictionary,
|
||||
meaning "return to no-dictionary mode".
|
||||
Note 1 : `dict` content will be copied internally.
|
||||
Use ZSTD_DCtx_loadDictionary_byReference()
|
||||
to reference dictionary content instead.
|
||||
In which case, the dictionary buffer must outlive its users.
|
||||
Note 2 : Loading a dictionary involves building tables,
|
||||
which has a non-negligible impact on CPU usage and latency.
|
||||
Note 3 : Use ZSTD_DCtx_loadDictionary_advanced() to select
|
||||
how dictionary content will be interpreted and loaded.
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); </b>/* not implemented */<b>
|
||||
</b><p> Reference a prepared dictionary, to be used to decompress next frames.
|
||||
The dictionary remains active for decompression of future frames using same DCtx.
|
||||
@result : 0, or an error code (which can be tested with ZSTD_isError()).
|
||||
Note 1 : Currently, only one dictionary can be managed.
|
||||
Referencing a new dictionary effectively "discards" any previous one.
|
||||
Special : adding a NULL DDict means "return to no-dictionary mode".
|
||||
Note 2 : DDict is just referenced, its lifetime must outlive its usage from DCtx.
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize); </b>/* not implemented */<b>
|
||||
size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictMode_e dictMode); </b>/* not implemented */<b>
|
||||
</b><p> Reference a prefix (single-usage dictionary) for next compression job.
|
||||
Prefix is **only used once**. It must be explicitly referenced before each frame.
|
||||
If there is a need to use same prefix multiple times, consider embedding it into a ZSTD_DDict instead.
|
||||
@result : 0, or an error code (which can be tested with ZSTD_isError()).
|
||||
Note 1 : Adding any prefix (including NULL) invalidates any previously set prefix or dictionary
|
||||
Note 2 : Prefix buffer is referenced. It must outlive compression job.
|
||||
Note 3 : By default, the prefix is treated as raw content (ZSTD_dm_rawContent).
|
||||
Use ZSTD_CCtx_refPrefix_advanced() to alter dictMode.
|
||||
Note 4 : Referencing a raw content prefix has almost no cpu nor memory cost.
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize);
|
||||
</b><p> Refuses allocating internal buffers for frames requiring a window size larger than provided limit.
|
||||
This is useful to prevent a decoder context from reserving too much memory for itself (potential attack scenario).
|
||||
This parameter is only useful in streaming mode, since no internal buffer is allocated in direct mode.
|
||||
By default, a decompression context accepts all window sizes <= (1 << ZSTD_WINDOWLOG_MAX)
|
||||
@return : 0, or an error code (which can be tested using ZSTD_isError()).
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format);
|
||||
</b><p> Instruct the decoder context about what kind of data to decode next.
|
||||
This instruction is mandatory to decode data without a fully-formed header,
|
||||
such ZSTD_f_zstd1_magicless for example.
|
||||
@return : 0, or an error code (which can be tested using ZSTD_isError()).
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>size_t ZSTD_decompress_generic(ZSTD_DCtx* dctx,
|
||||
ZSTD_outBuffer* output,
|
||||
ZSTD_inBuffer* input);
|
||||
</b><p> Behave the same as ZSTD_decompressStream.
|
||||
Decompression parameters cannot be changed once decompression is started.
|
||||
@return : an error code, which can be tested using ZSTD_isError()
|
||||
if >0, a hint, nb of expected input bytes for next invocation.
|
||||
`0` means : a frame has just been fully decoded and flushed.
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>size_t ZSTD_decompress_generic_simpleArgs (
|
||||
ZSTD_DCtx* dctx,
|
||||
void* dst, size_t dstCapacity, size_t* dstPos,
|
||||
const void* src, size_t srcSize, size_t* srcPos);
|
||||
</b><p> Same as ZSTD_decompress_generic(),
|
||||
but using only integral types as arguments.
|
||||
Argument list is larger than ZSTD_{in,out}Buffer,
|
||||
but can be helpful for binders from dynamic languages
|
||||
which have troubles handling structures containing memory pointers.
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>void ZSTD_DCtx_reset(ZSTD_DCtx* dctx);
|
||||
</b><p> Return a DCtx to clean state.
|
||||
If a decompression was ongoing, any internal data not yet flushed is cancelled.
|
||||
All parameters are back to default values, including sticky ones.
|
||||
Dictionary (if any) is dropped.
|
||||
Parameters can be modified again after a reset.
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<a name="Chapter21"></a><h2>Block level API</h2><pre></pre>
|
||||
|
||||
<pre><b></b><p> Frame metadata cost is typically ~18 bytes, which can be non-negligible for very small blocks (< 100 bytes).
|
||||
User will have to take in charge required information to regenerate data, such as compressed and content sizes.
|
||||
|
||||
A few rules to respect :
|
||||
@@ -1055,7 +1178,7 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t
|
||||
+ compression : any ZSTD_compressBegin*() variant, including with dictionary
|
||||
+ decompression : any ZSTD_decompressBegin*() variant, including with dictionary
|
||||
+ copyCCtx() and copyDCtx() can be used too
|
||||
- Block size is limited, it must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX
|
||||
- Block size is limited, it must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX == 128 KB
|
||||
+ If input is larger than a block size, it's necessary to split input data into multiple blocks
|
||||
+ For inputs larger than a single block size, consider using the regular ZSTD_compress() instead.
|
||||
Frame metadata is not that costly, and quickly becomes negligible as source size grows larger.
|
||||
@@ -1066,7 +1189,7 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t
|
||||
+ In case of multiple successive blocks, should some of them be uncompressed,
|
||||
decoder must be informed of their existence in order to follow proper history.
|
||||
Use ZSTD_insertBlock() for such a case.
|
||||
<BR></pre>
|
||||
</p></pre><BR>
|
||||
|
||||
<h3>Raw zstd block functions</h3><pre></pre><b><pre>size_t ZSTD_getBlockSize (const ZSTD_CCtx* cctx);
|
||||
size_t ZSTD_compressBlock (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
|
||||
|
||||
@@ -85,7 +85,7 @@ int main(int argc, char const *argv[]) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
size_t compressedSize;
|
||||
{ ZSTD_inBuffer inBuff = { dataToCompress, sizeof(dataToCompress), 0 };
|
||||
ZSTD_outBuffer outBuff = { compressedData, sizeof(compressedData), 0 };
|
||||
@@ -133,7 +133,7 @@ int main(int argc, char const *argv[]) {
|
||||
|
||||
size_t const cstreamSize = ZSTD_sizeof_CStream(cstream);
|
||||
size_t const cstreamEstimatedSize = wLog ?
|
||||
ZSTD_estimateCStreamSize_advanced_usingCParams(params.cParams) :
|
||||
ZSTD_estimateCStreamSize_usingCParams(params.cParams) :
|
||||
ZSTD_estimateCStreamSize(compressionLevel);
|
||||
size_t const dstreamSize = ZSTD_sizeof_DStream(dstream);
|
||||
|
||||
|
||||
@@ -30,14 +30,15 @@ const char* ERR_getErrorString(ERR_enum code)
|
||||
case PREFIX(init_missing): return "Context should be init first";
|
||||
case PREFIX(memory_allocation): return "Allocation error : not enough memory";
|
||||
case PREFIX(stage_wrong): return "Operation not authorized at current processing stage";
|
||||
case PREFIX(dstSize_tooSmall): return "Destination buffer is too small";
|
||||
case PREFIX(srcSize_wrong): return "Src size is incorrect";
|
||||
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";
|
||||
/* 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(maxCode):
|
||||
|
||||
+1
-1
@@ -184,7 +184,7 @@ FSE_PUBLIC_API size_t FSE_writeNCount (void* buffer, size_t bufferSize, const sh
|
||||
/*! 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 tableLog, unsigned maxSymbolValue);
|
||||
FSE_PUBLIC_API FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog);
|
||||
FSE_PUBLIC_API void FSE_freeCTable (FSE_CTable* ct);
|
||||
|
||||
/*! FSE_buildCTable():
|
||||
|
||||
+1
-1
@@ -242,7 +242,7 @@ size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats,
|
||||
|
||||
/** HUF_readCTable() :
|
||||
* Loading a CTable saved with HUF_writeCTable() */
|
||||
size_t HUF_readCTable (HUF_CElt* CTable, unsigned maxSymbolValue, const void* src, size_t srcSize);
|
||||
size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize);
|
||||
|
||||
|
||||
/*
|
||||
|
||||
+35
-35
@@ -33,7 +33,7 @@ typedef struct POOL_job_s {
|
||||
struct POOL_ctx_s {
|
||||
ZSTD_customMem customMem;
|
||||
/* Keep track of the threads */
|
||||
pthread_t *threads;
|
||||
ZSTD_pthread_t *threads;
|
||||
size_t numThreads;
|
||||
|
||||
/* The queue is a circular buffer */
|
||||
@@ -48,11 +48,11 @@ struct POOL_ctx_s {
|
||||
int queueEmpty;
|
||||
|
||||
/* The mutex protects the queue */
|
||||
pthread_mutex_t queueMutex;
|
||||
ZSTD_pthread_mutex_t queueMutex;
|
||||
/* Condition variable for pushers to wait on when the queue is full */
|
||||
pthread_cond_t queuePushCond;
|
||||
ZSTD_pthread_cond_t queuePushCond;
|
||||
/* Condition variables for poppers to wait on when the queue is empty */
|
||||
pthread_cond_t queuePopCond;
|
||||
ZSTD_pthread_cond_t queuePopCond;
|
||||
/* Indicates if the queue is shutting down */
|
||||
int shutdown;
|
||||
};
|
||||
@@ -67,14 +67,14 @@ static void* POOL_thread(void* opaque) {
|
||||
if (!ctx) { return NULL; }
|
||||
for (;;) {
|
||||
/* Lock the mutex and wait for a non-empty queue or until shutdown */
|
||||
pthread_mutex_lock(&ctx->queueMutex);
|
||||
ZSTD_pthread_mutex_lock(&ctx->queueMutex);
|
||||
|
||||
while (ctx->queueEmpty && !ctx->shutdown) {
|
||||
pthread_cond_wait(&ctx->queuePopCond, &ctx->queueMutex);
|
||||
ZSTD_pthread_cond_wait(&ctx->queuePopCond, &ctx->queueMutex);
|
||||
}
|
||||
/* empty => shutting down: so stop */
|
||||
if (ctx->queueEmpty) {
|
||||
pthread_mutex_unlock(&ctx->queueMutex);
|
||||
ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
|
||||
return opaque;
|
||||
}
|
||||
/* Pop a job off the queue */
|
||||
@@ -83,32 +83,32 @@ static void* POOL_thread(void* opaque) {
|
||||
ctx->numThreadsBusy++;
|
||||
ctx->queueEmpty = ctx->queueHead == ctx->queueTail;
|
||||
/* Unlock the mutex, signal a pusher, and run the job */
|
||||
pthread_mutex_unlock(&ctx->queueMutex);
|
||||
pthread_cond_signal(&ctx->queuePushCond);
|
||||
ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
|
||||
ZSTD_pthread_cond_signal(&ctx->queuePushCond);
|
||||
|
||||
job.function(job.opaque);
|
||||
|
||||
/* If the intended queue size was 0, signal after finishing job */
|
||||
if (ctx->queueSize == 1) {
|
||||
pthread_mutex_lock(&ctx->queueMutex);
|
||||
ZSTD_pthread_mutex_lock(&ctx->queueMutex);
|
||||
ctx->numThreadsBusy--;
|
||||
pthread_mutex_unlock(&ctx->queueMutex);
|
||||
pthread_cond_signal(&ctx->queuePushCond);
|
||||
ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
|
||||
ZSTD_pthread_cond_signal(&ctx->queuePushCond);
|
||||
} }
|
||||
} /* for (;;) */
|
||||
/* Unreachable */
|
||||
}
|
||||
|
||||
POOL_ctx *POOL_create(size_t numThreads, size_t queueSize) {
|
||||
POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) {
|
||||
return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem);
|
||||
}
|
||||
|
||||
POOL_ctx *POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customMem customMem) {
|
||||
POOL_ctx *ctx;
|
||||
POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customMem customMem) {
|
||||
POOL_ctx* ctx;
|
||||
/* Check the parameters */
|
||||
if (!numThreads) { return NULL; }
|
||||
/* Allocate the context and zero initialize */
|
||||
ctx = (POOL_ctx *)ZSTD_calloc(sizeof(POOL_ctx), customMem);
|
||||
ctx = (POOL_ctx*)ZSTD_calloc(sizeof(POOL_ctx), customMem);
|
||||
if (!ctx) { return NULL; }
|
||||
/* Initialize the job queue.
|
||||
* It needs one extra space since one space is wasted to differentiate empty
|
||||
@@ -120,12 +120,12 @@ POOL_ctx *POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customM
|
||||
ctx->queueTail = 0;
|
||||
ctx->numThreadsBusy = 0;
|
||||
ctx->queueEmpty = 1;
|
||||
(void)pthread_mutex_init(&ctx->queueMutex, NULL);
|
||||
(void)pthread_cond_init(&ctx->queuePushCond, NULL);
|
||||
(void)pthread_cond_init(&ctx->queuePopCond, NULL);
|
||||
(void)ZSTD_pthread_mutex_init(&ctx->queueMutex, NULL);
|
||||
(void)ZSTD_pthread_cond_init(&ctx->queuePushCond, NULL);
|
||||
(void)ZSTD_pthread_cond_init(&ctx->queuePopCond, NULL);
|
||||
ctx->shutdown = 0;
|
||||
/* Allocate space for the thread handles */
|
||||
ctx->threads = (pthread_t*)ZSTD_malloc(numThreads * sizeof(pthread_t), customMem);
|
||||
ctx->threads = (ZSTD_pthread_t*)ZSTD_malloc(numThreads * sizeof(ZSTD_pthread_t), customMem);
|
||||
ctx->numThreads = 0;
|
||||
ctx->customMem = customMem;
|
||||
/* Check for errors */
|
||||
@@ -133,7 +133,7 @@ POOL_ctx *POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customM
|
||||
/* Initialize the threads */
|
||||
{ size_t i;
|
||||
for (i = 0; i < numThreads; ++i) {
|
||||
if (pthread_create(&ctx->threads[i], NULL, &POOL_thread, ctx)) {
|
||||
if (ZSTD_pthread_create(&ctx->threads[i], NULL, &POOL_thread, ctx)) {
|
||||
ctx->numThreads = i;
|
||||
POOL_free(ctx);
|
||||
return NULL;
|
||||
@@ -146,27 +146,27 @@ POOL_ctx *POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customM
|
||||
/*! POOL_join() :
|
||||
Shutdown the queue, wake any sleeping threads, and join all of the threads.
|
||||
*/
|
||||
static void POOL_join(POOL_ctx *ctx) {
|
||||
static void POOL_join(POOL_ctx* ctx) {
|
||||
/* Shut down the queue */
|
||||
pthread_mutex_lock(&ctx->queueMutex);
|
||||
ZSTD_pthread_mutex_lock(&ctx->queueMutex);
|
||||
ctx->shutdown = 1;
|
||||
pthread_mutex_unlock(&ctx->queueMutex);
|
||||
ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
|
||||
/* Wake up sleeping threads */
|
||||
pthread_cond_broadcast(&ctx->queuePushCond);
|
||||
pthread_cond_broadcast(&ctx->queuePopCond);
|
||||
ZSTD_pthread_cond_broadcast(&ctx->queuePushCond);
|
||||
ZSTD_pthread_cond_broadcast(&ctx->queuePopCond);
|
||||
/* Join all of the threads */
|
||||
{ size_t i;
|
||||
for (i = 0; i < ctx->numThreads; ++i) {
|
||||
pthread_join(ctx->threads[i], NULL);
|
||||
ZSTD_pthread_join(ctx->threads[i], NULL);
|
||||
} }
|
||||
}
|
||||
|
||||
void POOL_free(POOL_ctx *ctx) {
|
||||
if (!ctx) { return; }
|
||||
POOL_join(ctx);
|
||||
pthread_mutex_destroy(&ctx->queueMutex);
|
||||
pthread_cond_destroy(&ctx->queuePushCond);
|
||||
pthread_cond_destroy(&ctx->queuePopCond);
|
||||
ZSTD_pthread_mutex_destroy(&ctx->queueMutex);
|
||||
ZSTD_pthread_cond_destroy(&ctx->queuePushCond);
|
||||
ZSTD_pthread_cond_destroy(&ctx->queuePopCond);
|
||||
ZSTD_free(ctx->queue, ctx->customMem);
|
||||
ZSTD_free(ctx->threads, ctx->customMem);
|
||||
ZSTD_free(ctx, ctx->customMem);
|
||||
@@ -176,7 +176,7 @@ size_t POOL_sizeof(POOL_ctx *ctx) {
|
||||
if (ctx==NULL) return 0; /* supports sizeof NULL */
|
||||
return sizeof(*ctx)
|
||||
+ ctx->queueSize * sizeof(POOL_job)
|
||||
+ ctx->numThreads * sizeof(pthread_t);
|
||||
+ ctx->numThreads * sizeof(ZSTD_pthread_t);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -198,12 +198,12 @@ void POOL_add(void* ctxVoid, POOL_function function, void *opaque) {
|
||||
POOL_ctx* const ctx = (POOL_ctx*)ctxVoid;
|
||||
if (!ctx) { return; }
|
||||
|
||||
pthread_mutex_lock(&ctx->queueMutex);
|
||||
ZSTD_pthread_mutex_lock(&ctx->queueMutex);
|
||||
{ POOL_job const job = {function, opaque};
|
||||
|
||||
/* Wait until there is space in the queue for the new job */
|
||||
while (isQueueFull(ctx) && !ctx->shutdown) {
|
||||
pthread_cond_wait(&ctx->queuePushCond, &ctx->queueMutex);
|
||||
ZSTD_pthread_cond_wait(&ctx->queuePushCond, &ctx->queueMutex);
|
||||
}
|
||||
/* The queue is still going => there is space */
|
||||
if (!ctx->shutdown) {
|
||||
@@ -212,8 +212,8 @@ void POOL_add(void* ctxVoid, POOL_function function, void *opaque) {
|
||||
ctx->queueTail = (ctx->queueTail + 1) % ctx->queueSize;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&ctx->queueMutex);
|
||||
pthread_cond_signal(&ctx->queuePopCond);
|
||||
ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
|
||||
ZSTD_pthread_cond_signal(&ctx->queuePopCond);
|
||||
}
|
||||
|
||||
#else /* ZSTD_MULTITHREAD not defined */
|
||||
|
||||
@@ -35,12 +35,12 @@ int g_ZSTD_threading_useles_symbol;
|
||||
|
||||
static unsigned __stdcall worker(void *arg)
|
||||
{
|
||||
pthread_t* const thread = (pthread_t*) arg;
|
||||
ZSTD_pthread_t* const thread = (ZSTD_pthread_t*) arg;
|
||||
thread->arg = thread->start_routine(thread->arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_create(pthread_t* thread, const void* unused,
|
||||
int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused,
|
||||
void* (*start_routine) (void*), void* arg)
|
||||
{
|
||||
(void)unused;
|
||||
@@ -54,16 +54,16 @@ int pthread_create(pthread_t* thread, const void* unused,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _pthread_join(pthread_t * thread, void **value_ptr)
|
||||
int ZSTD_pthread_join(ZSTD_pthread_t thread, void **value_ptr)
|
||||
{
|
||||
DWORD result;
|
||||
|
||||
if (!thread->handle) return 0;
|
||||
if (!thread.handle) return 0;
|
||||
|
||||
result = WaitForSingleObject(thread->handle, INFINITE);
|
||||
result = WaitForSingleObject(thread.handle, INFINITE);
|
||||
switch (result) {
|
||||
case WAIT_OBJECT_0:
|
||||
if (value_ptr) *value_ptr = thread->arg;
|
||||
if (value_ptr) *value_ptr = thread.arg;
|
||||
return 0;
|
||||
case WAIT_ABANDONED:
|
||||
return EINVAL;
|
||||
|
||||
+44
-28
@@ -44,32 +44,31 @@ extern "C" {
|
||||
|
||||
|
||||
/* mutex */
|
||||
#define pthread_mutex_t CRITICAL_SECTION
|
||||
#define pthread_mutex_init(a,b) (InitializeCriticalSection((a)), 0)
|
||||
#define pthread_mutex_destroy(a) DeleteCriticalSection((a))
|
||||
#define pthread_mutex_lock(a) EnterCriticalSection((a))
|
||||
#define pthread_mutex_unlock(a) LeaveCriticalSection((a))
|
||||
#define ZSTD_pthread_mutex_t CRITICAL_SECTION
|
||||
#define ZSTD_pthread_mutex_init(a, b) (InitializeCriticalSection((a)), 0)
|
||||
#define ZSTD_pthread_mutex_destroy(a) DeleteCriticalSection((a))
|
||||
#define ZSTD_pthread_mutex_lock(a) EnterCriticalSection((a))
|
||||
#define ZSTD_pthread_mutex_unlock(a) LeaveCriticalSection((a))
|
||||
|
||||
/* condition variable */
|
||||
#define pthread_cond_t CONDITION_VARIABLE
|
||||
#define pthread_cond_init(a, b) (InitializeConditionVariable((a)), 0)
|
||||
#define pthread_cond_destroy(a) /* No delete */
|
||||
#define pthread_cond_wait(a, b) SleepConditionVariableCS((a), (b), INFINITE)
|
||||
#define pthread_cond_signal(a) WakeConditionVariable((a))
|
||||
#define pthread_cond_broadcast(a) WakeAllConditionVariable((a))
|
||||
#define ZSTD_pthread_cond_t CONDITION_VARIABLE
|
||||
#define ZSTD_pthread_cond_init(a, b) (InitializeConditionVariable((a)), 0)
|
||||
#define ZSTD_pthread_cond_destroy(a) /* No delete */
|
||||
#define ZSTD_pthread_cond_wait(a, b) SleepConditionVariableCS((a), (b), INFINITE)
|
||||
#define ZSTD_pthread_cond_signal(a) WakeConditionVariable((a))
|
||||
#define ZSTD_pthread_cond_broadcast(a) WakeAllConditionVariable((a))
|
||||
|
||||
/* pthread_create() and pthread_join() */
|
||||
/* ZSTD_pthread_create() and ZSTD_pthread_join() */
|
||||
typedef struct {
|
||||
HANDLE handle;
|
||||
void* (*start_routine)(void*);
|
||||
void* arg;
|
||||
} pthread_t;
|
||||
} ZSTD_pthread_t;
|
||||
|
||||
int pthread_create(pthread_t* thread, const void* unused,
|
||||
int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused,
|
||||
void* (*start_routine) (void*), void* arg);
|
||||
|
||||
#define pthread_join(a, b) _pthread_join(&(a), (b))
|
||||
int _pthread_join(pthread_t* thread, void** value_ptr);
|
||||
int ZSTD_pthread_join(ZSTD_pthread_t thread, void** value_ptr);
|
||||
|
||||
/**
|
||||
* add here more wrappers as required
|
||||
@@ -80,23 +79,40 @@ int _pthread_join(pthread_t* thread, void** value_ptr);
|
||||
/* === POSIX Systems === */
|
||||
# include <pthread.h>
|
||||
|
||||
#define ZSTD_pthread_mutex_t pthread_mutex_t
|
||||
#define ZSTD_pthread_mutex_init(a, b) pthread_mutex_init((a), (b))
|
||||
#define ZSTD_pthread_mutex_destroy(a) pthread_mutex_destroy((a))
|
||||
#define ZSTD_pthread_mutex_lock(a) pthread_mutex_lock((a))
|
||||
#define ZSTD_pthread_mutex_unlock(a) pthread_mutex_unlock((a))
|
||||
|
||||
#define ZSTD_pthread_cond_t pthread_cond_t
|
||||
#define ZSTD_pthread_cond_init(a, b) pthread_cond_init((a), (b))
|
||||
#define ZSTD_pthread_cond_destroy(a) pthread_cond_destroy((a))
|
||||
#define ZSTD_pthread_cond_wait(a, b) pthread_cond_wait((a), (b))
|
||||
#define ZSTD_pthread_cond_signal(a) pthread_cond_signal((a))
|
||||
#define ZSTD_pthread_cond_broadcast(a) pthread_cond_broadcast((a))
|
||||
|
||||
#define ZSTD_pthread_t pthread_t
|
||||
#define ZSTD_pthread_create(a, b, c, d) pthread_create((a), (b), (c), (d))
|
||||
#define ZSTD_pthread_join(a, b) pthread_join((a),(b))
|
||||
|
||||
#else /* ZSTD_MULTITHREAD not defined */
|
||||
/* No multithreading support */
|
||||
|
||||
#define pthread_mutex_t int /* #define rather than typedef, because sometimes pthread support is implicit, resulting in duplicated symbols */
|
||||
#define pthread_mutex_init(a,b) ((void)a, 0)
|
||||
#define pthread_mutex_destroy(a)
|
||||
#define pthread_mutex_lock(a)
|
||||
#define pthread_mutex_unlock(a)
|
||||
typedef int ZSTD_pthread_mutex_t;
|
||||
#define ZSTD_pthread_mutex_init(a, b) ((void)a, 0)
|
||||
#define ZSTD_pthread_mutex_destroy(a)
|
||||
#define ZSTD_pthread_mutex_lock(a)
|
||||
#define ZSTD_pthread_mutex_unlock(a)
|
||||
|
||||
#define pthread_cond_t int
|
||||
#define pthread_cond_init(a,b) ((void)a, 0)
|
||||
#define pthread_cond_destroy(a)
|
||||
#define pthread_cond_wait(a,b)
|
||||
#define pthread_cond_signal(a)
|
||||
#define pthread_cond_broadcast(a)
|
||||
typedef int ZSTD_pthread_cond_t;
|
||||
#define ZSTD_pthread_cond_init(a, b) ((void)a, 0)
|
||||
#define ZSTD_pthread_cond_destroy(a)
|
||||
#define ZSTD_pthread_cond_wait(a, b)
|
||||
#define ZSTD_pthread_cond_signal(a)
|
||||
#define ZSTD_pthread_cond_broadcast(a)
|
||||
|
||||
/* do not use pthread_t */
|
||||
/* do not use ZSTD_pthread_t */
|
||||
|
||||
#endif /* ZSTD_MULTITHREAD */
|
||||
|
||||
|
||||
@@ -63,9 +63,10 @@ typedef enum {
|
||||
ZSTD_error_memory_allocation = 64,
|
||||
ZSTD_error_dstSize_tooSmall = 70,
|
||||
ZSTD_error_srcSize_wrong = 72,
|
||||
/* following error codes are not stable and may be removed or changed in a future version */
|
||||
ZSTD_error_frameIndex_tooLarge = 100,
|
||||
ZSTD_error_seekableIO = 102,
|
||||
ZSTD_error_maxCode = 120 /* never EVER use this value directly, it may change in future versions! Use ZSTD_isError() instead */
|
||||
ZSTD_error_maxCode = 120 /* never EVER use this value directly, it can change in future versions! Use ZSTD_isError() instead */
|
||||
} ZSTD_ErrorCode;
|
||||
|
||||
/*! ZSTD_getErrorCode() :
|
||||
|
||||
@@ -102,9 +102,13 @@ static const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 };
|
||||
#define BIT0 1
|
||||
|
||||
#define ZSTD_WINDOWLOG_ABSOLUTEMIN 10
|
||||
#define ZSTD_WINDOWLOG_DEFAULTMAX 27 /* Default maximum allowed window log */
|
||||
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_FRAMEIDSIZE 4
|
||||
static const size_t ZSTD_frameIdSize = ZSTD_FRAMEIDSIZE; /* magic number size */
|
||||
|
||||
#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;
|
||||
@@ -123,7 +127,8 @@ typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingTy
|
||||
#define MaxLit ((1<<Litbits) - 1)
|
||||
#define MaxML 52
|
||||
#define MaxLL 35
|
||||
#define MaxOff 28
|
||||
#define DefaultMaxOff 28
|
||||
#define MaxOff 31
|
||||
#define MaxSeq MAX(MaxLL, MaxML) /* Assumption : MaxOff < MaxLL,MaxML */
|
||||
#define MLFSELog 9
|
||||
#define LLFSELog 9
|
||||
@@ -149,8 +154,8 @@ static const S16 ML_defaultNorm[MaxML+1] = { 1, 4, 3, 2, 2, 2, 2, 2, 2, 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 };
|
||||
static 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 const U32 OF_defaultNormLog = OF_DEFAULTNORMLOG;
|
||||
|
||||
@@ -282,6 +287,7 @@ typedef struct {
|
||||
} ZSTD_entropyCTables_t;
|
||||
|
||||
struct ZSTD_CCtx_params_s {
|
||||
ZSTD_format_e format;
|
||||
ZSTD_compressionParameters cParams;
|
||||
ZSTD_frameParameters fParams;
|
||||
|
||||
|
||||
@@ -582,7 +582,7 @@ size_t FSE_normalizeCount (short* normalizedCounter, unsigned tableLog,
|
||||
if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); /* Unsupported size */
|
||||
if (tableLog < FSE_minTableLog(total, maxSymbolValue)) return ERROR(GENERIC); /* Too small tableLog, compression potentially impossible */
|
||||
|
||||
{ U32 const rtbTable[] = { 0, 473195, 504333, 520860, 550000, 700000, 750000, 830000 };
|
||||
{ static U32 const rtbTable[] = { 0, 473195, 504333, 520860, 550000, 700000, 750000, 830000 };
|
||||
U64 const scale = 62 - tableLog;
|
||||
U64 const step = ((U64)1<<62) / total; /* <== here, one division ! */
|
||||
U64 const vStep = 1ULL<<(scale-20);
|
||||
|
||||
@@ -167,7 +167,7 @@ size_t HUF_writeCTable (void* dst, size_t maxDstSize,
|
||||
}
|
||||
|
||||
|
||||
size_t HUF_readCTable (HUF_CElt* CTable, U32 maxSymbolValue, const void* src, size_t srcSize)
|
||||
size_t HUF_readCTable (HUF_CElt* CTable, U32* maxSymbolValuePtr, const void* src, size_t srcSize)
|
||||
{
|
||||
BYTE huffWeight[HUF_SYMBOLVALUE_MAX + 1]; /* init not required, even though some static analyzer may complain */
|
||||
U32 rankVal[HUF_TABLELOG_ABSOLUTEMAX + 1]; /* large enough for values from 0 to 16 */
|
||||
@@ -179,7 +179,7 @@ size_t HUF_readCTable (HUF_CElt* CTable, U32 maxSymbolValue, const void* src, si
|
||||
|
||||
/* check result */
|
||||
if (tableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
|
||||
if (nbSymbols > maxSymbolValue+1) return ERROR(maxSymbolValue_tooSmall);
|
||||
if (nbSymbols > *maxSymbolValuePtr+1) return ERROR(maxSymbolValue_tooSmall);
|
||||
|
||||
/* Prepare base value per rank */
|
||||
{ U32 n, nextRankStart = 0;
|
||||
@@ -208,9 +208,10 @@ size_t HUF_readCTable (HUF_CElt* CTable, U32 maxSymbolValue, const void* src, si
|
||||
min >>= 1;
|
||||
} }
|
||||
/* assign value within rank, symbol order */
|
||||
{ U32 n; for (n=0; n<=maxSymbolValue; n++) CTable[n].val = valPerRank[CTable[n].nbBits]++; }
|
||||
{ U32 n; for (n=0; n<nbSymbols; n++) CTable[n].val = valPerRank[CTable[n].nbBits]++; }
|
||||
}
|
||||
|
||||
*maxSymbolValuePtr = nbSymbols - 1;
|
||||
return readSize;
|
||||
}
|
||||
|
||||
|
||||
+102
-63
@@ -38,9 +38,7 @@
|
||||
* Helper functions
|
||||
***************************************/
|
||||
size_t ZSTD_compressBound(size_t srcSize) {
|
||||
size_t const lowLimit = 256 KB;
|
||||
size_t const margin = (srcSize < lowLimit) ? (lowLimit-srcSize) >> 12 : 0; /* from 64 to 0 */
|
||||
return srcSize + (srcSize >> 8) + margin;
|
||||
return ZSTD_COMPRESSBOUND(srcSize);
|
||||
}
|
||||
|
||||
|
||||
@@ -242,6 +240,7 @@ static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams(
|
||||
ZSTD_CCtx_params ret = cctxParams;
|
||||
ret.cParams = params.cParams;
|
||||
ret.fParams = params.fParams;
|
||||
ret.compressionLevel = ZSTD_CLEVEL_CUSTOM;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -256,6 +255,9 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v
|
||||
|
||||
switch(param)
|
||||
{
|
||||
case ZSTD_p_format :
|
||||
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
|
||||
|
||||
case ZSTD_p_compressionLevel:
|
||||
if (value == 0) return 0; /* special value : 0 means "don't change anything" */
|
||||
if (cctx->cdict) return ERROR(stage_wrong);
|
||||
@@ -326,6 +328,12 @@ size_t ZSTD_CCtxParam_setParameter(
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case ZSTD_p_format :
|
||||
if (value > (unsigned)ZSTD_f_zstd1_magicless)
|
||||
return ERROR(parameter_unsupported);
|
||||
params->format = (ZSTD_format_e)value;
|
||||
return 0;
|
||||
|
||||
case ZSTD_p_compressionLevel :
|
||||
if ((int)value > ZSTD_maxCLevel()) value = ZSTD_maxCLevel();
|
||||
if (value == 0) return 0;
|
||||
@@ -429,7 +437,7 @@ size_t ZSTD_CCtxParam_setParameter(
|
||||
case ZSTD_p_enableLongDistanceMatching :
|
||||
if (value != 0) {
|
||||
ZSTD_cLevelToCCtxParams(params);
|
||||
params->cParams.windowLog = ZSTD_LDM_WINDOW_LOG;
|
||||
params->cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG;
|
||||
}
|
||||
return ZSTD_ldm_initializeParameters(¶ms->ldmParams, value);
|
||||
|
||||
@@ -503,7 +511,7 @@ size_t ZSTD_CCtx_setParametersUsingCCtxParams(
|
||||
|
||||
ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize)
|
||||
{
|
||||
DEBUGLOG(5, " setting pledgedSrcSize to %u", (U32)pledgedSrcSize);
|
||||
DEBUGLOG(4, " setting pledgedSrcSize to %u", (U32)pledgedSrcSize);
|
||||
if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
|
||||
cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1;
|
||||
return 0;
|
||||
@@ -515,7 +523,7 @@ size_t ZSTD_CCtx_loadDictionary_advanced(
|
||||
{
|
||||
if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
|
||||
if (cctx->staticSize) return ERROR(memory_allocation); /* no malloc for static CCtx */
|
||||
DEBUGLOG(5, "load dictionary of size %u", (U32)dictSize);
|
||||
DEBUGLOG(4, "load dictionary of size %u", (U32)dictSize);
|
||||
ZSTD_freeCDict(cctx->cdictLocal); /* in case one already exists */
|
||||
if (dict==NULL || dictSize==0) { /* no dictionary mode */
|
||||
cctx->cdictLocal = NULL;
|
||||
@@ -631,29 +639,37 @@ static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
|
||||
|
||||
/** ZSTD_adjustCParams_internal() :
|
||||
optimize `cPar` for a given input (`srcSize` and `dictSize`).
|
||||
mostly downsizing to reduce memory consumption and initialization.
|
||||
Both `srcSize` and `dictSize` are optional (use 0 if unknown),
|
||||
but if both are 0, no optimization can be done.
|
||||
Note : cPar is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */
|
||||
mostly downsizing to reduce memory consumption and initialization latency.
|
||||
Both `srcSize` and `dictSize` are optional (use 0 if unknown).
|
||||
Note : cPar is considered validated at this stage. Use ZSTD_checkCParams() to ensure that condition. */
|
||||
ZSTD_compressionParameters ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize)
|
||||
{
|
||||
static const U64 minSrcSize = 513; /* (1<<9) + 1 */
|
||||
static const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1);
|
||||
assert(ZSTD_checkCParams(cPar)==0);
|
||||
if (srcSize+dictSize == 0) return cPar; /* no size information available : no adjustment */
|
||||
|
||||
/* resize params, to use less memory when necessary */
|
||||
{ U32 const minSrcSize = (srcSize==0) ? 500 : 0;
|
||||
U64 const rSize = srcSize + dictSize + minSrcSize;
|
||||
if (rSize < ((U64)1<<ZSTD_WINDOWLOG_MAX)) {
|
||||
U32 const srcLog =
|
||||
MAX(ZSTD_HASHLOG_MIN, (rSize==1) ? 1 : ZSTD_highbit32((U32)(rSize)-1) + 1);
|
||||
if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
|
||||
} }
|
||||
if (dictSize && (srcSize+1<2) /* srcSize unknown */ )
|
||||
srcSize = minSrcSize; /* presumed small when there is a dictionary */
|
||||
else if (srcSize == 0)
|
||||
srcSize = ZSTD_CONTENTSIZE_UNKNOWN; /* 0 == unknown : presumed large */
|
||||
|
||||
/* resize windowLog if input is small enough, to use less memory */
|
||||
if ( (srcSize < maxWindowResize)
|
||||
&& (dictSize < maxWindowResize) ) {
|
||||
U32 const tSize = (U32)(srcSize + dictSize);
|
||||
static U32 const hashSizeMin = 1 << ZSTD_HASHLOG_MIN;
|
||||
U32 const srcLog = (tSize < hashSizeMin) ? ZSTD_HASHLOG_MIN :
|
||||
ZSTD_highbit32(tSize-1) + 1;
|
||||
if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
|
||||
}
|
||||
if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog;
|
||||
{ U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
|
||||
if (cycleLog > cPar.windowLog) cPar.chainLog -= (cycleLog - cPar.windowLog);
|
||||
if (cycleLog > cPar.windowLog)
|
||||
cPar.chainLog -= (cycleLog - cPar.windowLog);
|
||||
}
|
||||
|
||||
if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
|
||||
if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN)
|
||||
cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
|
||||
|
||||
return cPar;
|
||||
}
|
||||
@@ -664,7 +680,7 @@ ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, u
|
||||
return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize);
|
||||
}
|
||||
|
||||
size_t ZSTD_estimateCCtxSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* params)
|
||||
size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params)
|
||||
{
|
||||
/* Estimate CCtx size is supported for single-threaded compression only. */
|
||||
if (params->nbThreads > 1) { return ERROR(GENERIC); }
|
||||
@@ -701,22 +717,22 @@ size_t ZSTD_estimateCCtxSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* pa
|
||||
}
|
||||
}
|
||||
|
||||
size_t ZSTD_estimateCCtxSize_advanced_usingCParams(ZSTD_compressionParameters cParams)
|
||||
size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams)
|
||||
{
|
||||
ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
|
||||
return ZSTD_estimateCCtxSize_advanced_usingCCtxParams(¶ms);
|
||||
return ZSTD_estimateCCtxSize_usingCCtxParams(¶ms);
|
||||
}
|
||||
|
||||
size_t ZSTD_estimateCCtxSize(int compressionLevel)
|
||||
{
|
||||
ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0);
|
||||
return ZSTD_estimateCCtxSize_advanced_usingCParams(cParams);
|
||||
return ZSTD_estimateCCtxSize_usingCParams(cParams);
|
||||
}
|
||||
|
||||
size_t ZSTD_estimateCStreamSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* params)
|
||||
size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params)
|
||||
{
|
||||
if (params->nbThreads > 1) { return ERROR(GENERIC); }
|
||||
{ size_t const CCtxSize = ZSTD_estimateCCtxSize_advanced_usingCCtxParams(params);
|
||||
{ size_t const CCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params);
|
||||
size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params->cParams.windowLog);
|
||||
size_t const inBuffSize = ((size_t)1 << params->cParams.windowLog) + blockSize;
|
||||
size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1;
|
||||
@@ -726,15 +742,15 @@ size_t ZSTD_estimateCStreamSize_advanced_usingCCtxParams(const ZSTD_CCtx_params*
|
||||
}
|
||||
}
|
||||
|
||||
size_t ZSTD_estimateCStreamSize_advanced_usingCParams(ZSTD_compressionParameters cParams)
|
||||
size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams)
|
||||
{
|
||||
ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
|
||||
return ZSTD_estimateCStreamSize_advanced_usingCCtxParams(¶ms);
|
||||
return ZSTD_estimateCStreamSize_usingCCtxParams(¶ms);
|
||||
}
|
||||
|
||||
size_t ZSTD_estimateCStreamSize(int compressionLevel) {
|
||||
ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0);
|
||||
return ZSTD_estimateCStreamSize_advanced_usingCParams(cParams);
|
||||
return ZSTD_estimateCStreamSize_usingCParams(cParams);
|
||||
}
|
||||
|
||||
static U32 ZSTD_equivalentCParams(ZSTD_compressionParameters cParams1,
|
||||
@@ -775,13 +791,13 @@ static U32 ZSTD_equivalentParams(ZSTD_CCtx_params params1,
|
||||
static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pledgedSrcSize)
|
||||
{
|
||||
U32 const end = (U32)(cctx->nextSrc - cctx->base);
|
||||
DEBUGLOG(5, "continue mode");
|
||||
DEBUGLOG(4, "continue mode");
|
||||
cctx->appliedParams = params;
|
||||
cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1;
|
||||
cctx->consumedSrcSize = 0;
|
||||
if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)
|
||||
cctx->appliedParams.fParams.contentSizeFlag = 0;
|
||||
DEBUGLOG(5, "pledged content size : %u ; flag : %u",
|
||||
DEBUGLOG(4, "pledged content size : %u ; flag : %u",
|
||||
(U32)pledgedSrcSize, cctx->appliedParams.fParams.contentSizeFlag);
|
||||
cctx->lowLimit = end;
|
||||
cctx->dictLimit = end;
|
||||
@@ -805,11 +821,13 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
||||
ZSTD_compResetPolicy_e const crp,
|
||||
ZSTD_buffered_policy_e const zbuff)
|
||||
{
|
||||
DEBUGLOG(4, "ZSTD_resetCCtx_internal");
|
||||
assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
|
||||
DEBUGLOG(4, "pledgedSrcSize: %u", (U32)pledgedSrcSize);
|
||||
|
||||
if (crp == ZSTDcrp_continue) {
|
||||
if (ZSTD_equivalentParams(params, zc->appliedParams)) {
|
||||
DEBUGLOG(5, "ZSTD_equivalentParams()==1");
|
||||
DEBUGLOG(4, "ZSTD_equivalentParams()==1");
|
||||
assert(!(params.ldmParams.enableLdm &&
|
||||
params.ldmParams.hashEveryLog == ZSTD_LDM_HASHEVERYLOG_NOTSET));
|
||||
zc->entropy->hufCTable_repeatMode = HUF_repeat_none;
|
||||
@@ -1250,20 +1268,30 @@ void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
|
||||
mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
|
||||
}
|
||||
|
||||
MEM_STATIC symbolEncodingType_e ZSTD_selectEncodingType(FSE_repeat* repeatMode,
|
||||
size_t const mostFrequent, size_t nbSeq, U32 defaultNormLog)
|
||||
typedef enum {
|
||||
ZSTD_defaultDisallowed = 0,
|
||||
ZSTD_defaultAllowed = 1
|
||||
} ZSTD_defaultPolicy_e;
|
||||
|
||||
MEM_STATIC symbolEncodingType_e ZSTD_selectEncodingType(
|
||||
FSE_repeat* repeatMode, size_t const mostFrequent, size_t nbSeq,
|
||||
U32 defaultNormLog, ZSTD_defaultPolicy_e const isDefaultAllowed)
|
||||
{
|
||||
#define MIN_SEQ_FOR_DYNAMIC_FSE 64
|
||||
#define MAX_SEQ_FOR_STATIC_FSE 1000
|
||||
|
||||
if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
|
||||
ZSTD_STATIC_ASSERT(ZSTD_defaultDisallowed == 0 && ZSTD_defaultAllowed != 0);
|
||||
if ((mostFrequent == nbSeq) && (!isDefaultAllowed || nbSeq > 2)) {
|
||||
/* Prefer set_basic over set_rle when there are 2 or less symbols,
|
||||
* since RLE uses 1 byte, but set_basic uses 5-6 bits per symbol.
|
||||
* If basic encoding isn't possible, always choose RLE.
|
||||
*/
|
||||
*repeatMode = FSE_repeat_check;
|
||||
return set_rle;
|
||||
}
|
||||
if ((*repeatMode == FSE_repeat_valid) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
|
||||
if (isDefaultAllowed && (*repeatMode == FSE_repeat_valid) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
|
||||
return set_repeat;
|
||||
}
|
||||
if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (defaultNormLog-1)))) {
|
||||
if (isDefaultAllowed && ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (defaultNormLog-1))))) {
|
||||
*repeatMode = FSE_repeat_valid;
|
||||
return set_basic;
|
||||
}
|
||||
@@ -1299,6 +1327,7 @@ MEM_STATIC size_t ZSTD_buildCTable(void* dst, size_t dstCapacity,
|
||||
count[codeTable[nbSeq-1]]--;
|
||||
nbSeq_1--;
|
||||
}
|
||||
assert(nbSeq_1 > 1);
|
||||
CHECK_F(FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max));
|
||||
{ size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog); /* overflow protected */
|
||||
if (FSE_isError(NCountSize)) return NCountSize;
|
||||
@@ -1436,7 +1465,7 @@ MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
|
||||
/* CTable for Literal Lengths */
|
||||
{ U32 max = MaxLL;
|
||||
size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, entropy->workspace);
|
||||
LLtype = ZSTD_selectEncodingType(&entropy->litlength_repeatMode, mostFrequent, nbSeq, LL_defaultNormLog);
|
||||
LLtype = ZSTD_selectEncodingType(&entropy->litlength_repeatMode, mostFrequent, nbSeq, LL_defaultNormLog, ZSTD_defaultAllowed);
|
||||
{ size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype,
|
||||
count, max, llCodeTable, nbSeq, LL_defaultNorm, LL_defaultNormLog, MaxLL,
|
||||
entropy->workspace, sizeof(entropy->workspace));
|
||||
@@ -1446,9 +1475,11 @@ MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
|
||||
/* CTable for Offsets */
|
||||
{ U32 max = MaxOff;
|
||||
size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, entropy->workspace);
|
||||
Offtype = ZSTD_selectEncodingType(&entropy->offcode_repeatMode, mostFrequent, nbSeq, OF_defaultNormLog);
|
||||
/* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */
|
||||
ZSTD_defaultPolicy_e const defaultPolicy = max <= DefaultMaxOff ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed;
|
||||
Offtype = ZSTD_selectEncodingType(&entropy->offcode_repeatMode, mostFrequent, nbSeq, OF_defaultNormLog, defaultPolicy);
|
||||
{ size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype,
|
||||
count, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, MaxOff,
|
||||
count, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
|
||||
entropy->workspace, sizeof(entropy->workspace));
|
||||
if (ZSTD_isError(countSize)) return countSize;
|
||||
op += countSize;
|
||||
@@ -1456,7 +1487,7 @@ MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
|
||||
/* CTable for MatchLengths */
|
||||
{ U32 max = MaxML;
|
||||
size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, entropy->workspace);
|
||||
MLtype = ZSTD_selectEncodingType(&entropy->matchlength_repeatMode, mostFrequent, nbSeq, ML_defaultNormLog);
|
||||
MLtype = ZSTD_selectEncodingType(&entropy->matchlength_repeatMode, mostFrequent, nbSeq, ML_defaultNormLog, ZSTD_defaultAllowed);
|
||||
{ size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype,
|
||||
count, max, mlCodeTable, nbSeq, ML_defaultNorm, ML_defaultNormLog, MaxML,
|
||||
entropy->workspace, sizeof(entropy->workspace));
|
||||
@@ -1586,7 +1617,7 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
|
||||
const BYTE* ip = (const BYTE*)src;
|
||||
BYTE* const ostart = (BYTE*)dst;
|
||||
BYTE* op = ostart;
|
||||
U32 const maxDist = 1 << cctx->appliedParams.cParams.windowLog;
|
||||
U32 const maxDist = (U32)1 << cctx->appliedParams.cParams.windowLog;
|
||||
|
||||
if (cctx->appliedParams.fParams.checksumFlag && srcSize)
|
||||
XXH64_update(&cctx->xxhState, src, srcSize);
|
||||
@@ -1617,9 +1648,9 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
|
||||
* windowLog <= 31 ==> 3<<29 + 1<<windowLog < 7<<29 < 1<<32.
|
||||
*/
|
||||
if (cctx->lowLimit > (3U<<29)) {
|
||||
U32 const cycleMask = (1 << ZSTD_cycleLog(cctx->appliedParams.cParams.chainLog, cctx->appliedParams.cParams.strategy)) - 1;
|
||||
U32 const cycleMask = ((U32)1 << ZSTD_cycleLog(cctx->appliedParams.cParams.chainLog, cctx->appliedParams.cParams.strategy)) - 1;
|
||||
U32 const current = (U32)(ip - cctx->base);
|
||||
U32 const newCurrent = (current & cycleMask) + (1 << cctx->appliedParams.cParams.windowLog);
|
||||
U32 const newCurrent = (current & cycleMask) + ((U32)1 << cctx->appliedParams.cParams.windowLog);
|
||||
U32 const correction = current - newCurrent;
|
||||
ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30);
|
||||
ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30);
|
||||
@@ -1675,20 +1706,24 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
|
||||
U32 const dictIDSizeCodeLength = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */
|
||||
U32 const dictIDSizeCode = params.fParams.noDictIDFlag ? 0 : dictIDSizeCodeLength; /* 0-3 */
|
||||
U32 const checksumFlag = params.fParams.checksumFlag>0;
|
||||
U32 const windowSize = 1U << params.cParams.windowLog;
|
||||
U32 const windowSize = (U32)1 << params.cParams.windowLog;
|
||||
U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize >= pledgedSrcSize);
|
||||
BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
|
||||
U32 const fcsCode = params.fParams.contentSizeFlag ?
|
||||
(pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : 0; /* 0-3 */
|
||||
BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
|
||||
size_t pos;
|
||||
size_t pos=0;
|
||||
|
||||
if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall);
|
||||
DEBUGLOG(5, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u",
|
||||
DEBUGLOG(4, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u",
|
||||
!params.fParams.noDictIDFlag, dictID, dictIDSizeCode);
|
||||
|
||||
MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
|
||||
op[4] = frameHeaderDecriptionByte; pos=5;
|
||||
if (params.format == ZSTD_f_zstd1) {
|
||||
DEBUGLOG(4, "writing zstd magic number");
|
||||
MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
|
||||
pos = 4;
|
||||
}
|
||||
op[pos++] = frameHeaderDecriptionByte;
|
||||
if (!singleSegment) op[pos++] = windowLogByte;
|
||||
switch(dictIDSizeCode)
|
||||
{
|
||||
@@ -1775,7 +1810,7 @@ size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx)
|
||||
{
|
||||
ZSTD_compressionParameters const cParams =
|
||||
ZSTD_getCParamsFromCCtxParams(cctx->appliedParams, 0, 0);
|
||||
return MIN (ZSTD_BLOCKSIZE_MAX, 1 << cParams.windowLog);
|
||||
return MIN (ZSTD_BLOCKSIZE_MAX, (U32)1 << cParams.windowLog);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
|
||||
@@ -1824,7 +1859,7 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t
|
||||
case ZSTD_btopt:
|
||||
case ZSTD_btultra:
|
||||
if (srcSize >= HASH_READ_SIZE)
|
||||
ZSTD_updateTree(zc, iend-HASH_READ_SIZE, iend, 1 << zc->appliedParams.cParams.searchLog, zc->appliedParams.cParams.searchLength);
|
||||
ZSTD_updateTree(zc, iend-HASH_READ_SIZE, iend, (U32)1 << zc->appliedParams.cParams.searchLog, zc->appliedParams.cParams.searchLength);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1872,8 +1907,10 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t
|
||||
cctx->dictID = cctx->appliedParams.fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr);
|
||||
dictPtr += 4;
|
||||
|
||||
{ size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)cctx->entropy->hufCTable, 255, dictPtr, dictEnd-dictPtr);
|
||||
{ unsigned maxSymbolValue = 255;
|
||||
size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)cctx->entropy->hufCTable, &maxSymbolValue, dictPtr, dictEnd-dictPtr);
|
||||
if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
|
||||
if (maxSymbolValue < 255) return ERROR(dictionary_corrupted);
|
||||
dictPtr += hufHeaderSize;
|
||||
}
|
||||
|
||||
@@ -1977,8 +2014,6 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
|
||||
ZSTD_buffered_policy_e zbuff)
|
||||
{
|
||||
DEBUGLOG(4, "ZSTD_compressBegin_internal");
|
||||
DEBUGLOG(4, "dict ? %s", dict ? "dict" : (cdict ? "cdict" : "none"));
|
||||
DEBUGLOG(4, "dictMode : %u", (U32)dictMode);
|
||||
/* params are supposed to be fully validated at this point */
|
||||
assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
|
||||
assert(!((dict) && (cdict))); /* either dict or cdict, not both */
|
||||
@@ -2090,9 +2125,9 @@ size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
|
||||
endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize);
|
||||
if (ZSTD_isError(endResult)) return endResult;
|
||||
if (cctx->appliedParams.fParams.contentSizeFlag) { /* control src size */
|
||||
DEBUGLOG(5, "end of frame : controlling src size");
|
||||
DEBUGLOG(4, "end of frame : controlling src size");
|
||||
if (cctx->pledgedSrcSizePlusOne != cctx->consumedSrcSize+1) {
|
||||
DEBUGLOG(5, "error : pledgedSrcSize = %u, while realSrcSize = %u",
|
||||
DEBUGLOG(4, "error : pledgedSrcSize = %u, while realSrcSize = %u",
|
||||
(U32)cctx->pledgedSrcSizePlusOne-1, (U32)cctx->consumedSrcSize);
|
||||
return ERROR(srcSize_wrong);
|
||||
} }
|
||||
@@ -2173,8 +2208,8 @@ size_t ZSTD_estimateCDictSize_advanced(
|
||||
{
|
||||
DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (U32)sizeof(ZSTD_CDict));
|
||||
DEBUGLOG(5, "CCtx estimate : %u",
|
||||
(U32)ZSTD_estimateCCtxSize_advanced_usingCParams(cParams));
|
||||
return sizeof(ZSTD_CDict) + ZSTD_estimateCCtxSize_advanced_usingCParams(cParams)
|
||||
(U32)ZSTD_estimateCCtxSize_usingCParams(cParams));
|
||||
return sizeof(ZSTD_CDict) + ZSTD_estimateCCtxSize_usingCParams(cParams)
|
||||
+ (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize);
|
||||
}
|
||||
|
||||
@@ -2299,7 +2334,7 @@ ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize,
|
||||
ZSTD_dictMode_e dictMode,
|
||||
ZSTD_compressionParameters cParams)
|
||||
{
|
||||
size_t const cctxSize = ZSTD_estimateCCtxSize_advanced_usingCParams(cParams);
|
||||
size_t const cctxSize = ZSTD_estimateCCtxSize_usingCParams(cParams);
|
||||
size_t const neededSize = sizeof(ZSTD_CDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize)
|
||||
+ cctxSize;
|
||||
ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace;
|
||||
@@ -2451,7 +2486,7 @@ size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
|
||||
ZSTD_CCtx_params params = zcs->requestedParams;
|
||||
params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
|
||||
params.cParams = ZSTD_getCParamsFromCCtxParams(params, pledgedSrcSize, 0);
|
||||
DEBUGLOG(5, "ZSTD_resetCStream");
|
||||
DEBUGLOG(4, "ZSTD_resetCStream");
|
||||
return ZSTD_resetCStream_internal(zcs, NULL, 0, ZSTD_dm_auto, zcs->cdict, params, pledgedSrcSize);
|
||||
}
|
||||
|
||||
@@ -2463,6 +2498,7 @@ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
|
||||
const void* dict, size_t dictSize, const ZSTD_CDict* cdict,
|
||||
ZSTD_CCtx_params params, unsigned long long pledgedSrcSize)
|
||||
{
|
||||
DEBUGLOG(4, "ZSTD_initCStream_internal");
|
||||
assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
|
||||
assert(!((dict) && (cdict))); /* either dict or cdict, not both */
|
||||
|
||||
@@ -2561,6 +2597,7 @@ MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity,
|
||||
|
||||
/** ZSTD_compressStream_generic():
|
||||
* internal function for all *compressStream*() variants and *compress_generic()
|
||||
* non-static, because can be called from zstdmt.c
|
||||
* @return : hint size for next input */
|
||||
size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
|
||||
ZSTD_outBuffer* output,
|
||||
@@ -2720,6 +2757,7 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
|
||||
ZSTD_inBuffer* input,
|
||||
ZSTD_EndDirective endOp)
|
||||
{
|
||||
DEBUGLOG(5, "ZSTD_compress_generic");
|
||||
/* check conditions */
|
||||
if (output->pos > output->size) return ERROR(GENERIC);
|
||||
if (input->pos > input->size) return ERROR(GENERIC);
|
||||
@@ -2733,6 +2771,7 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
|
||||
cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/);
|
||||
memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */
|
||||
assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */
|
||||
DEBUGLOG(4, "ZSTD_compress_generic : transparent init stage");
|
||||
|
||||
#ifdef ZSTD_MULTITHREAD
|
||||
if (params.nbThreads > 1) {
|
||||
@@ -2761,7 +2800,7 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
|
||||
#ifdef ZSTD_MULTITHREAD
|
||||
if (cctx->appliedParams.nbThreads > 1) {
|
||||
size_t const flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp);
|
||||
DEBUGLOG(5, "ZSTDMT_compressStream_generic : %u", (U32)flushMin);
|
||||
DEBUGLOG(5, "ZSTDMT_compressStream_generic result : %u", (U32)flushMin);
|
||||
if ( ZSTD_isError(flushMin)
|
||||
|| (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */
|
||||
ZSTD_startNewCompression(cctx);
|
||||
|
||||
@@ -14,14 +14,14 @@
|
||||
|
||||
#define LDM_BUCKET_SIZE_LOG 3
|
||||
#define LDM_MIN_MATCH_LENGTH 64
|
||||
#define LDM_HASH_LOG 20
|
||||
#define LDM_HASH_RLOG 7
|
||||
#define LDM_HASH_CHAR_OFFSET 10
|
||||
|
||||
size_t ZSTD_ldm_initializeParameters(ldmParams_t* params, U32 enableLdm)
|
||||
{
|
||||
ZSTD_STATIC_ASSERT(LDM_BUCKET_SIZE_LOG <= ZSTD_LDM_BUCKETSIZELOG_MAX);
|
||||
params->enableLdm = enableLdm>0;
|
||||
params->hashLog = LDM_HASH_LOG;
|
||||
params->hashLog = 0;
|
||||
params->bucketSizeLog = LDM_BUCKET_SIZE_LOG;
|
||||
params->minMatchLength = LDM_MIN_MATCH_LENGTH;
|
||||
params->hashEveryLog = ZSTD_LDM_HASHEVERYLOG_NOTSET;
|
||||
@@ -30,6 +30,10 @@ size_t ZSTD_ldm_initializeParameters(ldmParams_t* params, U32 enableLdm)
|
||||
|
||||
void ZSTD_ldm_adjustParameters(ldmParams_t* params, U32 windowLog)
|
||||
{
|
||||
if (params->hashLog == 0) {
|
||||
params->hashLog = MAX(ZSTD_HASHLOG_MIN, windowLog - LDM_HASH_RLOG);
|
||||
assert(params->hashLog <= ZSTD_HASHLOG_MAX);
|
||||
}
|
||||
if (params->hashEveryLog == ZSTD_LDM_HASHEVERYLOG_NOTSET) {
|
||||
params->hashEveryLog =
|
||||
windowLog < params->hashLog ? 0 : windowLog - params->hashLog;
|
||||
|
||||
@@ -20,7 +20,7 @@ extern "C" {
|
||||
* Long distance matching
|
||||
***************************************/
|
||||
|
||||
#define ZSTD_LDM_WINDOW_LOG 27
|
||||
#define ZSTD_LDM_DEFAULT_WINDOW_LOG ZSTD_WINDOWLOG_DEFAULTMAX
|
||||
#define ZSTD_LDM_HASHEVERYLOG_NOTSET 9999
|
||||
|
||||
/** ZSTD_compressBlock_ldm_generic() :
|
||||
|
||||
+10
-2
@@ -529,7 +529,14 @@ size_t ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx,
|
||||
} else {
|
||||
opt[cur].rep[2] = (opt[cur].off > 1) ? opt[cur-mlen].rep[1] : opt[cur-mlen].rep[2];
|
||||
opt[cur].rep[1] = (opt[cur].off > 0) ? opt[cur-mlen].rep[0] : opt[cur-mlen].rep[1];
|
||||
opt[cur].rep[0] = ((opt[cur].off==ZSTD_REP_MOVE_OPT) && (mlen != 1)) ? (opt[cur-mlen].rep[0] - 1) : (opt[cur-mlen].rep[opt[cur].off]);
|
||||
/* If opt[cur].off == ZSTD_REP_MOVE_OPT, then mlen != 1.
|
||||
* offset ZSTD_REP_MOVE_OPT is used for the special case
|
||||
* litLength == 0, where offset 0 means something special.
|
||||
* mlen == 1 means the previous byte was stored as a literal,
|
||||
* so they are mutually exclusive.
|
||||
*/
|
||||
assert(!(opt[cur].off == ZSTD_REP_MOVE_OPT && mlen == 1));
|
||||
opt[cur].rep[0] = (opt[cur].off == ZSTD_REP_MOVE_OPT) ? (opt[cur-mlen].rep[0] - 1) : (opt[cur-mlen].rep[opt[cur].off]);
|
||||
}
|
||||
|
||||
best_mlen = minMatch;
|
||||
@@ -804,7 +811,8 @@ size_t ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx,
|
||||
} else {
|
||||
opt[cur].rep[2] = (opt[cur].off > 1) ? opt[cur-mlen].rep[1] : opt[cur-mlen].rep[2];
|
||||
opt[cur].rep[1] = (opt[cur].off > 0) ? opt[cur-mlen].rep[0] : opt[cur-mlen].rep[1];
|
||||
opt[cur].rep[0] = ((opt[cur].off==ZSTD_REP_MOVE_OPT) && (mlen != 1)) ? (opt[cur-mlen].rep[0] - 1) : (opt[cur-mlen].rep[opt[cur].off]);
|
||||
assert(!(opt[cur].off == ZSTD_REP_MOVE_OPT && mlen == 1));
|
||||
opt[cur].rep[0] = (opt[cur].off == ZSTD_REP_MOVE_OPT) ? (opt[cur-mlen].rep[0] - 1) : (opt[cur-mlen].rep[opt[cur].off]);
|
||||
}
|
||||
|
||||
best_mlen = minMatch;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
|
||||
/* ====== Tuning parameters ====== */
|
||||
#define ZSTDMT_NBTHREADS_MAX 256
|
||||
#define ZSTDMT_NBTHREADS_MAX 200
|
||||
#define ZSTDMT_OVERLAPLOG_DEFAULT 6
|
||||
|
||||
|
||||
@@ -53,22 +53,24 @@ static unsigned long long GetCurrentClockTimeMicroseconds(void)
|
||||
}
|
||||
|
||||
#define MUTEX_WAIT_TIME_DLEVEL 6
|
||||
#define PTHREAD_MUTEX_LOCK(mutex) { \
|
||||
if (ZSTD_DEBUG>=MUTEX_WAIT_TIME_DLEVEL) { \
|
||||
#define ZSTD_PTHREAD_MUTEX_LOCK(mutex) { \
|
||||
if (ZSTD_DEBUG >= MUTEX_WAIT_TIME_DLEVEL) { \
|
||||
unsigned long long const beforeTime = GetCurrentClockTimeMicroseconds(); \
|
||||
pthread_mutex_lock(mutex); \
|
||||
ZSTD_pthread_mutex_lock(mutex); \
|
||||
{ unsigned long long const afterTime = GetCurrentClockTimeMicroseconds(); \
|
||||
unsigned long long const elapsedTime = (afterTime-beforeTime); \
|
||||
if (elapsedTime > 1000) { /* or whatever threshold you like; I'm using 1 millisecond here */ \
|
||||
DEBUGLOG(MUTEX_WAIT_TIME_DLEVEL, "Thread took %llu microseconds to acquire mutex %s \n", \
|
||||
elapsedTime, #mutex); \
|
||||
} } \
|
||||
} else pthread_mutex_lock(mutex); \
|
||||
} else { \
|
||||
ZSTD_pthread_mutex_lock(mutex); \
|
||||
} \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
# define PTHREAD_MUTEX_LOCK(m) pthread_mutex_lock(m)
|
||||
# define ZSTD_PTHREAD_MUTEX_LOCK(m) ZSTD_pthread_mutex_lock(m)
|
||||
# define DEBUG_PRINTHEX(l,p,n) {}
|
||||
|
||||
#endif
|
||||
@@ -85,7 +87,7 @@ typedef struct buffer_s {
|
||||
static const buffer_t g_nullBuffer = { NULL, 0 };
|
||||
|
||||
typedef struct ZSTDMT_bufferPool_s {
|
||||
pthread_mutex_t poolMutex;
|
||||
ZSTD_pthread_mutex_t poolMutex;
|
||||
size_t bufferSize;
|
||||
unsigned totalBuffers;
|
||||
unsigned nbBuffers;
|
||||
@@ -99,7 +101,7 @@ static ZSTDMT_bufferPool* ZSTDMT_createBufferPool(unsigned nbThreads, ZSTD_custo
|
||||
ZSTDMT_bufferPool* const bufPool = (ZSTDMT_bufferPool*)ZSTD_calloc(
|
||||
sizeof(ZSTDMT_bufferPool) + (maxNbBuffers-1) * sizeof(buffer_t), cMem);
|
||||
if (bufPool==NULL) return NULL;
|
||||
if (pthread_mutex_init(&bufPool->poolMutex, NULL)) {
|
||||
if (ZSTD_pthread_mutex_init(&bufPool->poolMutex, NULL)) {
|
||||
ZSTD_free(bufPool, cMem);
|
||||
return NULL;
|
||||
}
|
||||
@@ -113,10 +115,13 @@ static ZSTDMT_bufferPool* ZSTDMT_createBufferPool(unsigned nbThreads, ZSTD_custo
|
||||
static void ZSTDMT_freeBufferPool(ZSTDMT_bufferPool* bufPool)
|
||||
{
|
||||
unsigned u;
|
||||
DEBUGLOG(3, "ZSTDMT_freeBufferPool (address:%08X)", (U32)(size_t)bufPool);
|
||||
if (!bufPool) return; /* compatibility with free on NULL */
|
||||
for (u=0; u<bufPool->totalBuffers; u++)
|
||||
for (u=0; u<bufPool->totalBuffers; u++) {
|
||||
DEBUGLOG(4, "free buffer %2u (address:%08X)", u, (U32)(size_t)bufPool->bTable[u].start);
|
||||
ZSTD_free(bufPool->bTable[u].start, bufPool->cMem);
|
||||
pthread_mutex_destroy(&bufPool->poolMutex);
|
||||
}
|
||||
ZSTD_pthread_mutex_destroy(&bufPool->poolMutex);
|
||||
ZSTD_free(bufPool, bufPool->cMem);
|
||||
}
|
||||
|
||||
@@ -127,10 +132,10 @@ static size_t ZSTDMT_sizeof_bufferPool(ZSTDMT_bufferPool* bufPool)
|
||||
+ (bufPool->totalBuffers - 1) * sizeof(buffer_t);
|
||||
unsigned u;
|
||||
size_t totalBufferSize = 0;
|
||||
pthread_mutex_lock(&bufPool->poolMutex);
|
||||
ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
|
||||
for (u=0; u<bufPool->totalBuffers; u++)
|
||||
totalBufferSize += bufPool->bTable[u].size;
|
||||
pthread_mutex_unlock(&bufPool->poolMutex);
|
||||
ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
|
||||
|
||||
return poolSize + totalBufferSize;
|
||||
}
|
||||
@@ -146,20 +151,21 @@ static buffer_t ZSTDMT_getBuffer(ZSTDMT_bufferPool* bufPool)
|
||||
{
|
||||
size_t const bSize = bufPool->bufferSize;
|
||||
DEBUGLOG(5, "ZSTDMT_getBuffer");
|
||||
pthread_mutex_lock(&bufPool->poolMutex);
|
||||
ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
|
||||
if (bufPool->nbBuffers) { /* try to use an existing buffer */
|
||||
buffer_t const buf = bufPool->bTable[--(bufPool->nbBuffers)];
|
||||
size_t const availBufferSize = buf.size;
|
||||
bufPool->bTable[bufPool->nbBuffers] = g_nullBuffer;
|
||||
if ((availBufferSize >= bSize) & (availBufferSize <= 10*bSize)) {
|
||||
/* large enough, but not too much */
|
||||
pthread_mutex_unlock(&bufPool->poolMutex);
|
||||
ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
|
||||
return buf;
|
||||
}
|
||||
/* size conditions not respected : scratch this buffer, create new one */
|
||||
DEBUGLOG(5, "existing buffer does not meet size conditions => freeing");
|
||||
ZSTD_free(buf.start, bufPool->cMem);
|
||||
}
|
||||
pthread_mutex_unlock(&bufPool->poolMutex);
|
||||
ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
|
||||
/* create new buffer */
|
||||
DEBUGLOG(5, "create a new buffer");
|
||||
{ buffer_t buffer;
|
||||
@@ -175,13 +181,13 @@ static void ZSTDMT_releaseBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buf)
|
||||
{
|
||||
if (buf.start == NULL) return; /* compatible with release on NULL */
|
||||
DEBUGLOG(5, "ZSTDMT_releaseBuffer");
|
||||
pthread_mutex_lock(&bufPool->poolMutex);
|
||||
ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
|
||||
if (bufPool->nbBuffers < bufPool->totalBuffers) {
|
||||
bufPool->bTable[bufPool->nbBuffers++] = buf; /* stored for later use */
|
||||
pthread_mutex_unlock(&bufPool->poolMutex);
|
||||
ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
|
||||
return;
|
||||
}
|
||||
pthread_mutex_unlock(&bufPool->poolMutex);
|
||||
ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
|
||||
/* Reached bufferPool capacity (should not happen) */
|
||||
DEBUGLOG(5, "buffer pool capacity reached => freeing ");
|
||||
ZSTD_free(buf.start, bufPool->cMem);
|
||||
@@ -206,7 +212,7 @@ static ZSTD_CCtx_params ZSTDMT_makeJobCCtxParams(ZSTD_CCtx_params const params)
|
||||
/* a single CCtx Pool can be invoked from multiple threads in parallel */
|
||||
|
||||
typedef struct {
|
||||
pthread_mutex_t poolMutex;
|
||||
ZSTD_pthread_mutex_t poolMutex;
|
||||
unsigned totalCCtx;
|
||||
unsigned availCCtx;
|
||||
ZSTD_customMem cMem;
|
||||
@@ -219,7 +225,7 @@ static void ZSTDMT_freeCCtxPool(ZSTDMT_CCtxPool* pool)
|
||||
unsigned u;
|
||||
for (u=0; u<pool->totalCCtx; u++)
|
||||
ZSTD_freeCCtx(pool->cctx[u]); /* note : compatible with free on NULL */
|
||||
pthread_mutex_destroy(&pool->poolMutex);
|
||||
ZSTD_pthread_mutex_destroy(&pool->poolMutex);
|
||||
ZSTD_free(pool, pool->cMem);
|
||||
}
|
||||
|
||||
@@ -231,7 +237,7 @@ static ZSTDMT_CCtxPool* ZSTDMT_createCCtxPool(unsigned nbThreads,
|
||||
ZSTDMT_CCtxPool* const cctxPool = (ZSTDMT_CCtxPool*) ZSTD_calloc(
|
||||
sizeof(ZSTDMT_CCtxPool) + (nbThreads-1)*sizeof(ZSTD_CCtx*), cMem);
|
||||
if (!cctxPool) return NULL;
|
||||
if (pthread_mutex_init(&cctxPool->poolMutex, NULL)) {
|
||||
if (ZSTD_pthread_mutex_init(&cctxPool->poolMutex, NULL)) {
|
||||
ZSTD_free(cctxPool, cMem);
|
||||
return NULL;
|
||||
}
|
||||
@@ -247,7 +253,7 @@ static ZSTDMT_CCtxPool* ZSTDMT_createCCtxPool(unsigned nbThreads,
|
||||
/* only works during initialization phase, not during compression */
|
||||
static size_t ZSTDMT_sizeof_CCtxPool(ZSTDMT_CCtxPool* cctxPool)
|
||||
{
|
||||
pthread_mutex_lock(&cctxPool->poolMutex);
|
||||
ZSTD_pthread_mutex_lock(&cctxPool->poolMutex);
|
||||
{ unsigned const nbThreads = cctxPool->totalCCtx;
|
||||
size_t const poolSize = sizeof(*cctxPool)
|
||||
+ (nbThreads-1)*sizeof(ZSTD_CCtx*);
|
||||
@@ -256,7 +262,7 @@ static size_t ZSTDMT_sizeof_CCtxPool(ZSTDMT_CCtxPool* cctxPool)
|
||||
for (u=0; u<nbThreads; u++) {
|
||||
totalCCtxSize += ZSTD_sizeof_CCtx(cctxPool->cctx[u]);
|
||||
}
|
||||
pthread_mutex_unlock(&cctxPool->poolMutex);
|
||||
ZSTD_pthread_mutex_unlock(&cctxPool->poolMutex);
|
||||
return poolSize + totalCCtxSize;
|
||||
}
|
||||
}
|
||||
@@ -264,14 +270,14 @@ static size_t ZSTDMT_sizeof_CCtxPool(ZSTDMT_CCtxPool* cctxPool)
|
||||
static ZSTD_CCtx* ZSTDMT_getCCtx(ZSTDMT_CCtxPool* cctxPool)
|
||||
{
|
||||
DEBUGLOG(5, "ZSTDMT_getCCtx");
|
||||
pthread_mutex_lock(&cctxPool->poolMutex);
|
||||
ZSTD_pthread_mutex_lock(&cctxPool->poolMutex);
|
||||
if (cctxPool->availCCtx) {
|
||||
cctxPool->availCCtx--;
|
||||
{ ZSTD_CCtx* const cctx = cctxPool->cctx[cctxPool->availCCtx];
|
||||
pthread_mutex_unlock(&cctxPool->poolMutex);
|
||||
ZSTD_pthread_mutex_unlock(&cctxPool->poolMutex);
|
||||
return cctx;
|
||||
} }
|
||||
pthread_mutex_unlock(&cctxPool->poolMutex);
|
||||
ZSTD_pthread_mutex_unlock(&cctxPool->poolMutex);
|
||||
DEBUGLOG(5, "create one more CCtx");
|
||||
return ZSTD_createCCtx_advanced(cctxPool->cMem); /* note : can be NULL, when creation fails ! */
|
||||
}
|
||||
@@ -279,7 +285,7 @@ static ZSTD_CCtx* ZSTDMT_getCCtx(ZSTDMT_CCtxPool* cctxPool)
|
||||
static void ZSTDMT_releaseCCtx(ZSTDMT_CCtxPool* pool, ZSTD_CCtx* cctx)
|
||||
{
|
||||
if (cctx==NULL) return; /* compatibility with release on NULL */
|
||||
pthread_mutex_lock(&pool->poolMutex);
|
||||
ZSTD_pthread_mutex_lock(&pool->poolMutex);
|
||||
if (pool->availCCtx < pool->totalCCtx)
|
||||
pool->cctx[pool->availCCtx++] = cctx;
|
||||
else {
|
||||
@@ -287,7 +293,7 @@ static void ZSTDMT_releaseCCtx(ZSTDMT_CCtxPool* pool, ZSTD_CCtx* cctx)
|
||||
DEBUGLOG(5, "CCtx pool overflow : free cctx");
|
||||
ZSTD_freeCCtx(cctx);
|
||||
}
|
||||
pthread_mutex_unlock(&pool->poolMutex);
|
||||
ZSTD_pthread_mutex_unlock(&pool->poolMutex);
|
||||
}
|
||||
|
||||
|
||||
@@ -305,8 +311,8 @@ typedef struct {
|
||||
unsigned lastChunk;
|
||||
unsigned jobCompleted;
|
||||
unsigned jobScanned;
|
||||
pthread_mutex_t* jobCompleted_mutex;
|
||||
pthread_cond_t* jobCompleted_cond;
|
||||
ZSTD_pthread_mutex_t* jobCompleted_mutex;
|
||||
ZSTD_pthread_cond_t* jobCompleted_cond;
|
||||
ZSTD_CCtx_params params;
|
||||
const ZSTD_CDict* cdict;
|
||||
ZSTDMT_CCtxPool* cctxPool;
|
||||
@@ -373,11 +379,11 @@ _endJob:
|
||||
ZSTDMT_releaseCCtx(job->cctxPool, cctx);
|
||||
ZSTDMT_releaseBuffer(job->bufPool, job->src);
|
||||
job->src = g_nullBuffer; job->srcStart = NULL;
|
||||
PTHREAD_MUTEX_LOCK(job->jobCompleted_mutex);
|
||||
ZSTD_PTHREAD_MUTEX_LOCK(job->jobCompleted_mutex);
|
||||
job->jobCompleted = 1;
|
||||
job->jobScanned = 0;
|
||||
pthread_cond_signal(job->jobCompleted_cond);
|
||||
pthread_mutex_unlock(job->jobCompleted_mutex);
|
||||
ZSTD_pthread_cond_signal(job->jobCompleted_cond);
|
||||
ZSTD_pthread_mutex_unlock(job->jobCompleted_mutex);
|
||||
}
|
||||
|
||||
|
||||
@@ -395,8 +401,8 @@ struct ZSTDMT_CCtx_s {
|
||||
ZSTDMT_jobDescription* jobs;
|
||||
ZSTDMT_bufferPool* bufPool;
|
||||
ZSTDMT_CCtxPool* cctxPool;
|
||||
pthread_mutex_t jobCompleted_mutex;
|
||||
pthread_cond_t jobCompleted_cond;
|
||||
ZSTD_pthread_mutex_t jobCompleted_mutex;
|
||||
ZSTD_pthread_cond_t jobCompleted_cond;
|
||||
size_t targetSectionSize;
|
||||
size_t inBuffSize;
|
||||
size_t dictSize;
|
||||
@@ -459,11 +465,11 @@ ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbThreads, ZSTD_customMem cMem)
|
||||
ZSTDMT_freeCCtx(mtctx);
|
||||
return NULL;
|
||||
}
|
||||
if (pthread_mutex_init(&mtctx->jobCompleted_mutex, NULL)) {
|
||||
if (ZSTD_pthread_mutex_init(&mtctx->jobCompleted_mutex, NULL)) {
|
||||
ZSTDMT_freeCCtx(mtctx);
|
||||
return NULL;
|
||||
}
|
||||
if (pthread_cond_init(&mtctx->jobCompleted_cond, NULL)) {
|
||||
if (ZSTD_pthread_cond_init(&mtctx->jobCompleted_cond, NULL)) {
|
||||
ZSTDMT_freeCCtx(mtctx);
|
||||
return NULL;
|
||||
}
|
||||
@@ -483,28 +489,46 @@ static void ZSTDMT_releaseAllJobResources(ZSTDMT_CCtx* mtctx)
|
||||
unsigned jobID;
|
||||
DEBUGLOG(3, "ZSTDMT_releaseAllJobResources");
|
||||
for (jobID=0; jobID <= mtctx->jobIDMask; jobID++) {
|
||||
DEBUGLOG(4, "job%02u: release dst address %08X", jobID, (U32)(size_t)mtctx->jobs[jobID].dstBuff.start);
|
||||
ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[jobID].dstBuff);
|
||||
mtctx->jobs[jobID].dstBuff = g_nullBuffer;
|
||||
DEBUGLOG(4, "job%02u: release src address %08X", jobID, (U32)(size_t)mtctx->jobs[jobID].src.start);
|
||||
ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[jobID].src);
|
||||
mtctx->jobs[jobID].src = g_nullBuffer;
|
||||
}
|
||||
memset(mtctx->jobs, 0, (mtctx->jobIDMask+1)*sizeof(ZSTDMT_jobDescription));
|
||||
DEBUGLOG(4, "input: release address %08X", (U32)(size_t)mtctx->inBuff.buffer.start);
|
||||
ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->inBuff.buffer);
|
||||
mtctx->inBuff.buffer = g_nullBuffer;
|
||||
mtctx->allJobsCompleted = 1;
|
||||
}
|
||||
|
||||
static void ZSTDMT_waitForAllJobsCompleted(ZSTDMT_CCtx* zcs)
|
||||
{
|
||||
DEBUGLOG(4, "ZSTDMT_waitForAllJobsCompleted");
|
||||
while (zcs->doneJobID < zcs->nextJobID) {
|
||||
unsigned const jobID = zcs->doneJobID & zcs->jobIDMask;
|
||||
ZSTD_PTHREAD_MUTEX_LOCK(&zcs->jobCompleted_mutex);
|
||||
while (zcs->jobs[jobID].jobCompleted==0) {
|
||||
DEBUGLOG(5, "waiting for jobCompleted signal from chunk %u", zcs->doneJobID); /* we want to block when waiting for data to flush */
|
||||
ZSTD_pthread_cond_wait(&zcs->jobCompleted_cond, &zcs->jobCompleted_mutex);
|
||||
}
|
||||
ZSTD_pthread_mutex_unlock(&zcs->jobCompleted_mutex);
|
||||
zcs->doneJobID++;
|
||||
}
|
||||
}
|
||||
|
||||
size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx)
|
||||
{
|
||||
if (mtctx==NULL) return 0; /* compatible with free on NULL */
|
||||
POOL_free(mtctx->factory);
|
||||
if (!mtctx->allJobsCompleted) ZSTDMT_releaseAllJobResources(mtctx); /* stop workers first */
|
||||
ZSTDMT_freeBufferPool(mtctx->bufPool); /* release job resources into pools first */
|
||||
POOL_free(mtctx->factory); /* stop and free worker threads */
|
||||
ZSTDMT_releaseAllJobResources(mtctx); /* release job resources into pools first */
|
||||
ZSTD_free(mtctx->jobs, mtctx->cMem);
|
||||
ZSTDMT_freeBufferPool(mtctx->bufPool);
|
||||
ZSTDMT_freeCCtxPool(mtctx->cctxPool);
|
||||
ZSTD_freeCDict(mtctx->cdictLocal);
|
||||
pthread_mutex_destroy(&mtctx->jobCompleted_mutex);
|
||||
pthread_cond_destroy(&mtctx->jobCompleted_cond);
|
||||
ZSTD_pthread_mutex_destroy(&mtctx->jobCompleted_mutex);
|
||||
ZSTD_pthread_cond_destroy(&mtctx->jobCompleted_cond);
|
||||
ZSTD_free(mtctx, mtctx->cMem);
|
||||
return 0;
|
||||
}
|
||||
@@ -649,12 +673,12 @@ static size_t ZSTDMT_compress_advanced_internal(
|
||||
unsigned chunkID;
|
||||
for (chunkID=0; chunkID<nbChunks; chunkID++) {
|
||||
DEBUGLOG(5, "waiting for chunk %u ", chunkID);
|
||||
PTHREAD_MUTEX_LOCK(&mtctx->jobCompleted_mutex);
|
||||
ZSTD_PTHREAD_MUTEX_LOCK(&mtctx->jobCompleted_mutex);
|
||||
while (mtctx->jobs[chunkID].jobCompleted==0) {
|
||||
DEBUGLOG(5, "waiting for jobCompleted signal from chunk %u", chunkID);
|
||||
pthread_cond_wait(&mtctx->jobCompleted_cond, &mtctx->jobCompleted_mutex);
|
||||
ZSTD_pthread_cond_wait(&mtctx->jobCompleted_cond, &mtctx->jobCompleted_mutex);
|
||||
}
|
||||
pthread_mutex_unlock(&mtctx->jobCompleted_mutex);
|
||||
ZSTD_pthread_mutex_unlock(&mtctx->jobCompleted_mutex);
|
||||
DEBUGLOG(5, "ready to write chunk %u ", chunkID);
|
||||
|
||||
mtctx->jobs[chunkID].srcStart = NULL;
|
||||
@@ -667,9 +691,8 @@ static size_t ZSTDMT_compress_advanced_internal(
|
||||
if (chunkID >= compressWithinDst) { /* chunk compressed into its own buffer, which must be released */
|
||||
DEBUGLOG(5, "releasing buffer %u>=%u", chunkID, compressWithinDst);
|
||||
ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[chunkID].dstBuff);
|
||||
}
|
||||
mtctx->jobs[chunkID].dstBuff = g_nullBuffer;
|
||||
}
|
||||
} }
|
||||
mtctx->jobs[chunkID].dstBuff = g_nullBuffer;
|
||||
dstPos += cSize ;
|
||||
}
|
||||
} /* for (chunkID=0; chunkID<nbChunks; chunkID++) */
|
||||
@@ -724,21 +747,6 @@ size_t ZSTDMT_compressCCtx(ZSTDMT_CCtx* mtctx,
|
||||
/* ======= Streaming API ======= */
|
||||
/* ====================================== */
|
||||
|
||||
static void ZSTDMT_waitForAllJobsCompleted(ZSTDMT_CCtx* zcs)
|
||||
{
|
||||
DEBUGLOG(4, "ZSTDMT_waitForAllJobsCompleted");
|
||||
while (zcs->doneJobID < zcs->nextJobID) {
|
||||
unsigned const jobID = zcs->doneJobID & zcs->jobIDMask;
|
||||
PTHREAD_MUTEX_LOCK(&zcs->jobCompleted_mutex);
|
||||
while (zcs->jobs[jobID].jobCompleted==0) {
|
||||
DEBUGLOG(5, "waiting for jobCompleted signal from chunk %u", zcs->doneJobID); /* we want to block when waiting for data to flush */
|
||||
pthread_cond_wait(&zcs->jobCompleted_cond, &zcs->jobCompleted_mutex);
|
||||
}
|
||||
pthread_mutex_unlock(&zcs->jobCompleted_mutex);
|
||||
zcs->doneJobID++;
|
||||
}
|
||||
}
|
||||
|
||||
size_t ZSTDMT_initCStream_internal(
|
||||
ZSTDMT_CCtx* zcs,
|
||||
const void* dict, size_t dictSize, ZSTD_dictMode_e dictMode,
|
||||
@@ -923,13 +931,13 @@ static size_t ZSTDMT_flushNextJob(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output, unsi
|
||||
{
|
||||
unsigned const wJobID = zcs->doneJobID & zcs->jobIDMask;
|
||||
if (zcs->doneJobID == zcs->nextJobID) return 0; /* all flushed ! */
|
||||
PTHREAD_MUTEX_LOCK(&zcs->jobCompleted_mutex);
|
||||
ZSTD_PTHREAD_MUTEX_LOCK(&zcs->jobCompleted_mutex);
|
||||
while (zcs->jobs[wJobID].jobCompleted==0) {
|
||||
DEBUGLOG(5, "waiting for jobCompleted signal from job %u", zcs->doneJobID);
|
||||
if (!blockToFlush) { pthread_mutex_unlock(&zcs->jobCompleted_mutex); return 0; } /* nothing ready to be flushed => skip */
|
||||
pthread_cond_wait(&zcs->jobCompleted_cond, &zcs->jobCompleted_mutex); /* block when nothing available to flush */
|
||||
if (!blockToFlush) { ZSTD_pthread_mutex_unlock(&zcs->jobCompleted_mutex); return 0; } /* nothing ready to be flushed => skip */
|
||||
ZSTD_pthread_cond_wait(&zcs->jobCompleted_cond, &zcs->jobCompleted_mutex); /* block when nothing available to flush */
|
||||
}
|
||||
pthread_mutex_unlock(&zcs->jobCompleted_mutex);
|
||||
ZSTD_pthread_mutex_unlock(&zcs->jobCompleted_mutex);
|
||||
/* compression job completed : output can be flushed */
|
||||
{ ZSTDMT_jobDescription job = zcs->jobs[wJobID];
|
||||
if (!job.jobScanned) {
|
||||
@@ -973,7 +981,7 @@ static size_t ZSTDMT_flushNextJob(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output, unsi
|
||||
|
||||
|
||||
/** ZSTDMT_compressStream_generic() :
|
||||
* internal use only
|
||||
* internal use only - exposed to be invoked from zstd_compress.c
|
||||
* assumption : output and input are valid (pos <= size)
|
||||
* @return : minimum amount of data remaining to flush, 0 if none */
|
||||
size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
|
||||
@@ -982,20 +990,21 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
|
||||
ZSTD_EndDirective endOp)
|
||||
{
|
||||
size_t const newJobThreshold = mtctx->dictSize + mtctx->targetSectionSize;
|
||||
unsigned forwardInputProgress = 0;
|
||||
assert(output->pos <= output->size);
|
||||
assert(input->pos <= input->size);
|
||||
if ((mtctx->frameEnded) && (endOp==ZSTD_e_continue)) {
|
||||
/* current frame being ended. Only flush/end are allowed. Or start new frame with init */
|
||||
/* current frame being ended. Only flush/end are allowed */
|
||||
return ERROR(stage_wrong);
|
||||
}
|
||||
if (mtctx->params.nbThreads==1) { /* delegate to single-thread (synchronous) */
|
||||
return ZSTD_compressStream_generic(mtctx->cctxPool->cctx[0], output, input, endOp);
|
||||
}
|
||||
|
||||
/* single-pass shortcut (note : this is synchronous-mode) */
|
||||
if ( (mtctx->nextJobID==0) /* just started */
|
||||
&& (mtctx->inBuff.filled==0) /* nothing buffered */
|
||||
&& (endOp==ZSTD_e_end) /* end order */
|
||||
/* single-pass shortcut (note : synchronous-mode) */
|
||||
if ( (mtctx->nextJobID == 0) /* just started */
|
||||
&& (mtctx->inBuff.filled == 0) /* nothing buffered */
|
||||
&& (endOp == ZSTD_e_end) /* end order */
|
||||
&& (output->size - output->pos >= ZSTD_compressBound(input->size - input->pos)) ) { /* enough room */
|
||||
size_t const cSize = ZSTDMT_compress_advanced_internal(mtctx,
|
||||
(char*)output->dst + output->pos, output->size - output->pos,
|
||||
@@ -1013,15 +1022,16 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
|
||||
/* fill input buffer */
|
||||
if (input->size > input->pos) { /* support NULL input */
|
||||
if (mtctx->inBuff.buffer.start == NULL) {
|
||||
mtctx->inBuff.buffer = ZSTDMT_getBuffer(mtctx->bufPool);
|
||||
if (mtctx->inBuff.buffer.start == NULL) return ERROR(memory_allocation);
|
||||
mtctx->inBuff.buffer = ZSTDMT_getBuffer(mtctx->bufPool); /* note : may fail, in which case, no forward input progress */
|
||||
mtctx->inBuff.filled = 0;
|
||||
}
|
||||
{ size_t const toLoad = MIN(input->size - input->pos, mtctx->inBuffSize - mtctx->inBuff.filled);
|
||||
if (mtctx->inBuff.buffer.start) {
|
||||
size_t const toLoad = MIN(input->size - input->pos, mtctx->inBuffSize - mtctx->inBuff.filled);
|
||||
DEBUGLOG(5, "inBuff:%08X; inBuffSize=%u; ToCopy=%u", (U32)(size_t)mtctx->inBuff.buffer.start, (U32)mtctx->inBuffSize, (U32)toLoad);
|
||||
memcpy((char*)mtctx->inBuff.buffer.start + mtctx->inBuff.filled, (const char*)input->src + input->pos, toLoad);
|
||||
input->pos += toLoad;
|
||||
mtctx->inBuff.filled += toLoad;
|
||||
forwardInputProgress = toLoad>0;
|
||||
} }
|
||||
|
||||
if ( (mtctx->inBuff.filled >= newJobThreshold) /* filled enough : let's compress */
|
||||
@@ -1030,7 +1040,7 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
|
||||
}
|
||||
|
||||
/* check for potential compressed data ready to be flushed */
|
||||
CHECK_F( ZSTDMT_flushNextJob(mtctx, output, (mtctx->inBuff.filled == mtctx->inBuffSize) /* blockToFlush */) ); /* block if it wasn't possible to create new job due to saturation */
|
||||
CHECK_F( ZSTDMT_flushNextJob(mtctx, output, !forwardInputProgress /* blockToFlush */) ); /* block if there was no forward input progress */
|
||||
|
||||
if (input->pos < input->size) /* input not consumed : do not flush yet */
|
||||
endOp = ZSTD_e_continue;
|
||||
|
||||
+265
-130
@@ -35,7 +35,7 @@
|
||||
* Frames requiring more memory will be rejected.
|
||||
*/
|
||||
#ifndef ZSTD_MAXWINDOWSIZE_DEFAULT
|
||||
# define ZSTD_MAXWINDOWSIZE_DEFAULT (((U64)1 << ZSTD_WINDOWLOG_MAX) + 1) /* defined within zstd.h */
|
||||
# define ZSTD_MAXWINDOWSIZE_DEFAULT (((U32)1 << ZSTD_WINDOWLOG_DEFAULTMAX) + 1)
|
||||
#endif
|
||||
|
||||
|
||||
@@ -110,6 +110,7 @@ struct ZSTD_DCtx_s
|
||||
XXH64_state_t xxhState;
|
||||
size_t headerSize;
|
||||
U32 dictID;
|
||||
ZSTD_format_e format;
|
||||
const BYTE* litPtr;
|
||||
ZSTD_customMem customMem;
|
||||
size_t litSize;
|
||||
@@ -149,30 +150,21 @@ size_t ZSTD_sizeof_DCtx (const ZSTD_DCtx* dctx)
|
||||
|
||||
size_t ZSTD_estimateDCtxSize(void) { return sizeof(ZSTD_DCtx); }
|
||||
|
||||
size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)
|
||||
|
||||
static size_t ZSTD_startingInputLength(ZSTD_format_e format)
|
||||
{
|
||||
dctx->expected = ZSTD_frameHeaderSize_prefix;
|
||||
dctx->stage = ZSTDds_getFrameHeaderSize;
|
||||
dctx->decodedSize = 0;
|
||||
dctx->previousDstEnd = NULL;
|
||||
dctx->base = NULL;
|
||||
dctx->vBase = NULL;
|
||||
dctx->dictEnd = NULL;
|
||||
dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */
|
||||
dctx->litEntropy = dctx->fseEntropy = 0;
|
||||
dctx->dictID = 0;
|
||||
MEM_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue));
|
||||
memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */
|
||||
dctx->LLTptr = dctx->entropy.LLTable;
|
||||
dctx->MLTptr = dctx->entropy.MLTable;
|
||||
dctx->OFTptr = dctx->entropy.OFTable;
|
||||
dctx->HUFptr = dctx->entropy.hufTable;
|
||||
return 0;
|
||||
size_t const startingInputLength = (format==ZSTD_f_zstd1_magicless) ?
|
||||
ZSTD_frameHeaderSize_prefix - ZSTD_frameIdSize :
|
||||
ZSTD_frameHeaderSize_prefix;
|
||||
ZSTD_STATIC_ASSERT(ZSTD_FRAMEHEADERSIZE_PREFIX >= ZSTD_FRAMEIDSIZE);
|
||||
/* only supports formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless */
|
||||
assert( (format == ZSTD_f_zstd1) || (format == ZSTD_f_zstd1_magicless) );
|
||||
return startingInputLength;
|
||||
}
|
||||
|
||||
static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)
|
||||
{
|
||||
ZSTD_decompressBegin(dctx); /* cannot fail */
|
||||
dctx->format = ZSTD_f_zstd1; /* ZSTD_decompressBegin() invokes ZSTD_startingInputLength() with argument dctx->format */
|
||||
dctx->staticSize = 0;
|
||||
dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;
|
||||
dctx->ddict = NULL;
|
||||
@@ -183,6 +175,19 @@ static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)
|
||||
dctx->streamStage = zdss_init;
|
||||
}
|
||||
|
||||
ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize)
|
||||
{
|
||||
ZSTD_DCtx* const dctx = (ZSTD_DCtx*) workspace;
|
||||
|
||||
if ((size_t)workspace & 7) return NULL; /* 8-aligned */
|
||||
if (workspaceSize < sizeof(ZSTD_DCtx)) return NULL; /* minimum size */
|
||||
|
||||
ZSTD_initDCtx_internal(dctx);
|
||||
dctx->staticSize = workspaceSize;
|
||||
dctx->inBuff = (char*)(dctx+1);
|
||||
return dctx;
|
||||
}
|
||||
|
||||
ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem)
|
||||
{
|
||||
if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
|
||||
@@ -197,19 +202,6 @@ ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem)
|
||||
}
|
||||
}
|
||||
|
||||
ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize)
|
||||
{
|
||||
ZSTD_DCtx* dctx = (ZSTD_DCtx*) workspace;
|
||||
|
||||
if ((size_t)workspace & 7) return NULL; /* 8-aligned */
|
||||
if (workspaceSize < sizeof(ZSTD_DCtx)) return NULL; /* minimum size */
|
||||
|
||||
ZSTD_initDCtx_internal(dctx);
|
||||
dctx->staticSize = workspaceSize;
|
||||
dctx->inBuff = (char*)(dctx+1);
|
||||
return dctx;
|
||||
}
|
||||
|
||||
ZSTD_DCtx* ZSTD_createDCtx(void)
|
||||
{
|
||||
return ZSTD_createDCtx_advanced(ZSTD_defaultCMem);
|
||||
@@ -252,7 +244,7 @@ void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx)
|
||||
* Note 3 : Skippable Frame Identifiers are considered valid. */
|
||||
unsigned ZSTD_isFrame(const void* buffer, size_t size)
|
||||
{
|
||||
if (size < 4) return 0;
|
||||
if (size < ZSTD_frameIdSize) return 0;
|
||||
{ U32 const magic = MEM_readLE32(buffer);
|
||||
if (magic == ZSTD_MAGICNUMBER) return 1;
|
||||
if ((magic & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) return 1;
|
||||
@@ -263,40 +255,56 @@ unsigned ZSTD_isFrame(const void* buffer, size_t size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/** ZSTD_frameHeaderSize() :
|
||||
* srcSize must be >= ZSTD_frameHeaderSize_prefix.
|
||||
* @return : size of the Frame Header */
|
||||
size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize)
|
||||
/** ZSTD_frameHeaderSize_internal() :
|
||||
* srcSize must be large enough to reach header size fields.
|
||||
* note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless
|
||||
* @return : size of the Frame Header
|
||||
* or an error code, which can be tested with ZSTD_isError() */
|
||||
static size_t ZSTD_frameHeaderSize_internal(const void* src, size_t srcSize, ZSTD_format_e format)
|
||||
{
|
||||
if (srcSize < ZSTD_frameHeaderSize_prefix) return ERROR(srcSize_wrong);
|
||||
{ BYTE const fhd = ((const BYTE*)src)[4];
|
||||
size_t const minInputSize = ZSTD_startingInputLength(format);
|
||||
if (srcSize < minInputSize) return ERROR(srcSize_wrong);
|
||||
|
||||
{ BYTE const fhd = ((const BYTE*)src)[minInputSize-1];
|
||||
U32 const dictID= fhd & 3;
|
||||
U32 const singleSegment = (fhd >> 5) & 1;
|
||||
U32 const fcsId = fhd >> 6;
|
||||
return ZSTD_frameHeaderSize_prefix + !singleSegment + ZSTD_did_fieldSize[dictID] + ZSTD_fcs_fieldSize[fcsId]
|
||||
+ (singleSegment && !fcsId);
|
||||
return minInputSize + !singleSegment
|
||||
+ ZSTD_did_fieldSize[dictID] + ZSTD_fcs_fieldSize[fcsId]
|
||||
+ (singleSegment && !fcsId);
|
||||
}
|
||||
}
|
||||
|
||||
/** ZSTD_frameHeaderSize() :
|
||||
* srcSize must be >= ZSTD_frameHeaderSize_prefix.
|
||||
* @return : size of the Frame Header */
|
||||
size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_frameHeaderSize_internal(src, srcSize, ZSTD_f_zstd1);
|
||||
}
|
||||
|
||||
/** ZSTD_getFrameHeader() :
|
||||
* decode Frame Header, or require larger `srcSize`.
|
||||
* @return : 0, `zfhPtr` is correctly filled,
|
||||
* >0, `srcSize` is too small, result is expected `srcSize`,
|
||||
* or an error code, which can be tested using ZSTD_isError() */
|
||||
size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize)
|
||||
|
||||
/** ZSTD_getFrameHeader_internal() :
|
||||
* decode Frame Header, or require larger `srcSize`.
|
||||
* note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless
|
||||
* @return : 0, `zfhPtr` is correctly filled,
|
||||
* >0, `srcSize` is too small, value is wanted `srcSize` amount,
|
||||
* or an error code, which can be tested using ZSTD_isError() */
|
||||
static size_t ZSTD_getFrameHeader_internal(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format)
|
||||
{
|
||||
const BYTE* ip = (const BYTE*)src;
|
||||
if (srcSize < ZSTD_frameHeaderSize_prefix) return ZSTD_frameHeaderSize_prefix;
|
||||
size_t const minInputSize = ZSTD_startingInputLength(format);
|
||||
|
||||
if (MEM_readLE32(src) != ZSTD_MAGICNUMBER) {
|
||||
if (srcSize < minInputSize) return minInputSize;
|
||||
|
||||
if ( (format != ZSTD_f_zstd1_magicless)
|
||||
&& (MEM_readLE32(src) != ZSTD_MAGICNUMBER) ) {
|
||||
if ((MEM_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {
|
||||
/* skippable frame */
|
||||
if (srcSize < ZSTD_skippableHeaderSize)
|
||||
return ZSTD_skippableHeaderSize; /* magic number + frame length */
|
||||
memset(zfhPtr, 0, sizeof(*zfhPtr));
|
||||
zfhPtr->frameContentSize = MEM_readLE32((const char *)src + 4);
|
||||
zfhPtr->frameContentSize = MEM_readLE32((const char *)src + ZSTD_frameIdSize);
|
||||
zfhPtr->frameType = ZSTD_skippableFrame;
|
||||
return 0;
|
||||
}
|
||||
@@ -304,13 +312,13 @@ size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t src
|
||||
}
|
||||
|
||||
/* ensure there is enough `srcSize` to fully read/decode frame header */
|
||||
{ size_t const fhsize = ZSTD_frameHeaderSize(src, srcSize);
|
||||
{ size_t const fhsize = ZSTD_frameHeaderSize_internal(src, srcSize, format);
|
||||
if (srcSize < fhsize) return fhsize;
|
||||
zfhPtr->headerSize = (U32)fhsize;
|
||||
}
|
||||
|
||||
{ BYTE const fhdByte = ip[4];
|
||||
size_t pos = 5;
|
||||
{ BYTE const fhdByte = ip[minInputSize-1];
|
||||
size_t pos = minInputSize;
|
||||
U32 const dictIDSizeCode = fhdByte&3;
|
||||
U32 const checksumFlag = (fhdByte>>2)&1;
|
||||
U32 const singleSegment = (fhdByte>>5)&1;
|
||||
@@ -357,6 +365,18 @@ size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t src
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** ZSTD_getFrameHeader() :
|
||||
* decode Frame Header, or require larger `srcSize`.
|
||||
* note : this function does not consume input, it only reads it.
|
||||
* @return : 0, `zfhPtr` is correctly filled,
|
||||
* >0, `srcSize` is too small, value is wanted `srcSize` amount,
|
||||
* or an error code, which can be tested using ZSTD_isError() */
|
||||
size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize)
|
||||
{
|
||||
return ZSTD_getFrameHeader_internal(zfhPtr, src, srcSize, ZSTD_f_zstd1);
|
||||
}
|
||||
|
||||
|
||||
/** ZSTD_getFrameContentSize() :
|
||||
* compatible with legacy mode
|
||||
* @return : decompressed size of the single frame pointed to be `src` if known, otherwise
|
||||
@@ -390,14 +410,14 @@ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
|
||||
unsigned long long totalDstSize = 0;
|
||||
|
||||
while (srcSize >= ZSTD_frameHeaderSize_prefix) {
|
||||
const U32 magicNumber = MEM_readLE32(src);
|
||||
U32 const magicNumber = MEM_readLE32(src);
|
||||
|
||||
if ((magicNumber & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {
|
||||
size_t skippableSize;
|
||||
if (srcSize < ZSTD_skippableHeaderSize)
|
||||
return ERROR(srcSize_wrong);
|
||||
skippableSize = MEM_readLE32((const BYTE *)src + 4) +
|
||||
ZSTD_skippableHeaderSize;
|
||||
skippableSize = MEM_readLE32((const BYTE *)src + ZSTD_frameIdSize)
|
||||
+ ZSTD_skippableHeaderSize;
|
||||
if (srcSize < skippableSize) {
|
||||
return ZSTD_CONTENTSIZE_ERROR;
|
||||
}
|
||||
@@ -422,11 +442,9 @@ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
|
||||
src = (const BYTE *)src + frameSrcSize;
|
||||
srcSize -= frameSrcSize;
|
||||
}
|
||||
}
|
||||
} /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */
|
||||
|
||||
if (srcSize) {
|
||||
return ZSTD_CONTENTSIZE_ERROR;
|
||||
}
|
||||
if (srcSize) return ZSTD_CONTENTSIZE_ERROR;
|
||||
|
||||
return totalDstSize;
|
||||
}
|
||||
@@ -442,7 +460,8 @@ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
|
||||
unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize)
|
||||
{
|
||||
unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize);
|
||||
return ret >= ZSTD_CONTENTSIZE_ERROR ? 0 : ret;
|
||||
ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_ERROR < ZSTD_CONTENTSIZE_UNKNOWN);
|
||||
return (ret >= ZSTD_CONTENTSIZE_ERROR) ? 0 : ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -451,9 +470,9 @@ unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize)
|
||||
* @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */
|
||||
static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t headerSize)
|
||||
{
|
||||
size_t const result = ZSTD_getFrameHeader(&(dctx->fParams), src, headerSize);
|
||||
if (ZSTD_isError(result)) return result; /* invalid header */
|
||||
if (result>0) return ERROR(srcSize_wrong); /* headerSize too small */
|
||||
size_t const result = ZSTD_getFrameHeader_internal(&(dctx->fParams), src, headerSize, dctx->format);
|
||||
if (ZSTD_isError(result)) return result; /* invalid header */
|
||||
if (result>0) return ERROR(srcSize_wrong); /* headerSize too small */
|
||||
if (dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID))
|
||||
return ERROR(dictionary_wrong);
|
||||
if (dctx->fParams.checksumFlag) XXH64_reset(&dctx->xxhState, 0);
|
||||
@@ -499,7 +518,8 @@ static size_t ZSTD_setRleBlock(void* dst, size_t dstCapacity,
|
||||
}
|
||||
|
||||
/*! ZSTD_decodeLiteralsBlock() :
|
||||
@return : nb of bytes read from src (< srcSize ) */
|
||||
* @return : nb of bytes read from src (< srcSize )
|
||||
* note : symbol not declared but exposed for fullbench */
|
||||
size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
|
||||
const void* src, size_t srcSize) /* note : srcSize < BLOCKSIZE */
|
||||
{
|
||||
@@ -700,9 +720,9 @@ static const FSE_decode_t4 OF_defaultDTable[(1<<OF_DEFAULTNORMLOG)+1] = {
|
||||
}; /* OF_defaultDTable */
|
||||
|
||||
/*! ZSTD_buildSeqTable() :
|
||||
@return : nb bytes read from src,
|
||||
or an error code if it fails, testable with ZSTD_isError()
|
||||
*/
|
||||
* @return : nb bytes read from src,
|
||||
* or an error code if it fails, testable with ZSTD_isError()
|
||||
*/
|
||||
static size_t ZSTD_buildSeqTable(FSE_DTable* DTableSpace, const FSE_DTable** DTablePtr,
|
||||
symbolEncodingType_e type, U32 max, U32 maxLog,
|
||||
const void* src, size_t srcSize,
|
||||
@@ -862,6 +882,15 @@ size_t ZSTD_execSequenceLast7(BYTE* op,
|
||||
|
||||
typedef enum { ZSTD_lo_isRegularOffset, ZSTD_lo_isLongOffset=1 } ZSTD_longOffset_e;
|
||||
|
||||
/* We need to add at most (ZSTD_WINDOWLOG_MAX_32 - 1) bits to read the maximum
|
||||
* offset bits. But we can only read at most (STREAM_ACCUMULATOR_MIN_32 - 1)
|
||||
* bits before reloading. This value is the maximum number of bytes we read
|
||||
* after reloading when we are decoding long offets.
|
||||
*/
|
||||
#define LONG_OFFSETS_MAX_EXTRA_BITS_32 \
|
||||
(ZSTD_WINDOWLOG_MAX_32 > STREAM_ACCUMULATOR_MIN_32 \
|
||||
? ZSTD_WINDOWLOG_MAX_32 - STREAM_ACCUMULATOR_MIN_32 \
|
||||
: 0)
|
||||
|
||||
static seq_t ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets)
|
||||
{
|
||||
@@ -869,7 +898,7 @@ static seq_t ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e l
|
||||
|
||||
U32 const llCode = FSE_peekSymbol(&seqState->stateLL);
|
||||
U32 const mlCode = FSE_peekSymbol(&seqState->stateML);
|
||||
U32 const ofCode = FSE_peekSymbol(&seqState->stateOffb); /* <= maxOff, by table construction */
|
||||
U32 const ofCode = FSE_peekSymbol(&seqState->stateOffb); /* <= MaxOff, by table construction */
|
||||
|
||||
U32 const llBits = LL_bits[llCode];
|
||||
U32 const mlBits = ML_bits[mlCode];
|
||||
@@ -896,7 +925,7 @@ static seq_t ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e l
|
||||
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 };
|
||||
0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD, 0x1FFFFFFD, 0x3FFFFFFD, 0x7FFFFFFD };
|
||||
|
||||
/* sequence */
|
||||
{ size_t offset;
|
||||
@@ -904,8 +933,10 @@ static seq_t ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e l
|
||||
offset = 0;
|
||||
else {
|
||||
ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1);
|
||||
if (longOffsets) {
|
||||
int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN);
|
||||
ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5);
|
||||
assert(ofBits <= MaxOff);
|
||||
if (MEM_32bits() && longOffsets) {
|
||||
U32 const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN_32-1);
|
||||
offset = OF_base[ofCode] + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits);
|
||||
if (MEM_32bits() || extraBits) BIT_reloadDStream(&seqState->DStream);
|
||||
if (extraBits) offset += BIT_readBitsFast(&seqState->DStream, extraBits);
|
||||
@@ -936,13 +967,17 @@ static seq_t ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e l
|
||||
|
||||
seq.matchLength = ML_base[mlCode]
|
||||
+ ((mlCode>31) ? BIT_readBitsFast(&seqState->DStream, mlBits) : 0); /* <= 16 bits */
|
||||
if (MEM_32bits() && (mlBits+llBits>24)) BIT_reloadDStream(&seqState->DStream);
|
||||
if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32))
|
||||
BIT_reloadDStream(&seqState->DStream);
|
||||
if (MEM_64bits() && (totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog)))
|
||||
BIT_reloadDStream(&seqState->DStream);
|
||||
/* Verify that there is enough bits to read the rest of the data in 64-bit mode. */
|
||||
ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64);
|
||||
|
||||
seq.litLength = LL_base[llCode]
|
||||
+ ((llCode>15) ? BIT_readBitsFast(&seqState->DStream, llBits) : 0); /* <= 16 bits */
|
||||
if ( MEM_32bits()
|
||||
|| (totalBits > 64 - 7 - (LLFSELog+MLFSELog+OffFSELog)) )
|
||||
BIT_reloadDStream(&seqState->DStream);
|
||||
if (MEM_32bits())
|
||||
BIT_reloadDStream(&seqState->DStream);
|
||||
|
||||
DEBUGLOG(6, "seq: litL=%u, matchL=%u, offset=%u",
|
||||
(U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset);
|
||||
@@ -1102,7 +1137,6 @@ static size_t ZSTD_decompressSequences(
|
||||
}
|
||||
|
||||
|
||||
|
||||
HINT_INLINE
|
||||
seq_t ZSTD_decodeSequenceLong(seqState_t* seqState, ZSTD_longOffset_e const longOffsets)
|
||||
{
|
||||
@@ -1110,7 +1144,7 @@ seq_t ZSTD_decodeSequenceLong(seqState_t* seqState, ZSTD_longOffset_e const long
|
||||
|
||||
U32 const llCode = FSE_peekSymbol(&seqState->stateLL);
|
||||
U32 const mlCode = FSE_peekSymbol(&seqState->stateML);
|
||||
U32 const ofCode = FSE_peekSymbol(&seqState->stateOffb); /* <= maxOff, by table construction */
|
||||
U32 const ofCode = FSE_peekSymbol(&seqState->stateOffb); /* <= MaxOff, by table construction */
|
||||
|
||||
U32 const llBits = LL_bits[llCode];
|
||||
U32 const mlBits = ML_bits[mlCode];
|
||||
@@ -1137,7 +1171,7 @@ seq_t ZSTD_decodeSequenceLong(seqState_t* seqState, ZSTD_longOffset_e const long
|
||||
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 };
|
||||
0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD, 0x1FFFFFFD, 0x3FFFFFFD, 0x7FFFFFFD };
|
||||
|
||||
/* sequence */
|
||||
{ size_t offset;
|
||||
@@ -1145,8 +1179,10 @@ seq_t ZSTD_decodeSequenceLong(seqState_t* seqState, ZSTD_longOffset_e const long
|
||||
offset = 0;
|
||||
else {
|
||||
ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1);
|
||||
if (longOffsets) {
|
||||
int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN);
|
||||
ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5);
|
||||
assert(ofBits <= MaxOff);
|
||||
if (MEM_32bits() && longOffsets) {
|
||||
U32 const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN_32-1);
|
||||
offset = OF_base[ofCode] + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits);
|
||||
if (MEM_32bits() || extraBits) BIT_reloadDStream(&seqState->DStream);
|
||||
if (extraBits) offset += BIT_readBitsFast(&seqState->DStream, extraBits);
|
||||
@@ -1176,11 +1212,16 @@ seq_t ZSTD_decodeSequenceLong(seqState_t* seqState, ZSTD_longOffset_e const long
|
||||
}
|
||||
|
||||
seq.matchLength = ML_base[mlCode] + ((mlCode>31) ? BIT_readBitsFast(&seqState->DStream, mlBits) : 0); /* <= 16 bits */
|
||||
if (MEM_32bits() && (mlBits+llBits>24)) BIT_reloadDStream(&seqState->DStream);
|
||||
if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32))
|
||||
BIT_reloadDStream(&seqState->DStream);
|
||||
if (MEM_64bits() && (totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog)))
|
||||
BIT_reloadDStream(&seqState->DStream);
|
||||
/* Verify that there is enough bits to read the rest of the data in 64-bit mode. */
|
||||
ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64);
|
||||
|
||||
seq.litLength = LL_base[llCode] + ((llCode>15) ? BIT_readBitsFast(&seqState->DStream, llBits) : 0); /* <= 16 bits */
|
||||
if (MEM_32bits() ||
|
||||
(totalBits > 64 - 7 - (LLFSELog+MLFSELog+OffFSELog)) ) BIT_reloadDStream(&seqState->DStream);
|
||||
if (MEM_32bits())
|
||||
BIT_reloadDStream(&seqState->DStream);
|
||||
|
||||
{ size_t const pos = seqState->pos + seq.litLength;
|
||||
seq.match = seqState->base + pos - seq.offset; /* single memory segment */
|
||||
@@ -1375,7 +1416,7 @@ static size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
|
||||
/* windowSize could be any value at this point, since it is only validated
|
||||
* in the streaming API.
|
||||
*/
|
||||
DEBUGLOG(5, "ZSTD_decompressBlock_internal");
|
||||
DEBUGLOG(5, "ZSTD_decompressBlock_internal (size : %u)", (U32)srcSize);
|
||||
|
||||
if (srcSize >= ZSTD_BLOCKSIZE_MAX) return ERROR(srcSize_wrong);
|
||||
|
||||
@@ -1424,7 +1465,7 @@ ZSTDLIB_API size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, siz
|
||||
}
|
||||
|
||||
|
||||
size_t ZSTD_generateNxBytes(void* dst, size_t dstCapacity, BYTE byte, size_t length)
|
||||
static size_t ZSTD_generateNxBytes(void* dst, size_t dstCapacity, BYTE byte, size_t length)
|
||||
{
|
||||
if (length > dstCapacity) return ERROR(dstSize_tooSmall);
|
||||
memset(dst, byte, length);
|
||||
@@ -1444,7 +1485,7 @@ size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize)
|
||||
#endif
|
||||
if ( (srcSize >= ZSTD_skippableHeaderSize)
|
||||
&& (MEM_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START ) {
|
||||
return ZSTD_skippableHeaderSize + MEM_readLE32((const BYTE*)src + 4);
|
||||
return ZSTD_skippableHeaderSize + MEM_readLE32((const BYTE*)src + ZSTD_frameIdSize);
|
||||
} else {
|
||||
const BYTE* ip = (const BYTE*)src;
|
||||
const BYTE* const ipstart = ip;
|
||||
@@ -1607,13 +1648,15 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
|
||||
#endif
|
||||
|
||||
magicNumber = MEM_readLE32(src);
|
||||
DEBUGLOG(4, "reading magic number %08X (expecting %08X)",
|
||||
(U32)magicNumber, (U32)ZSTD_MAGICNUMBER);
|
||||
if (magicNumber != ZSTD_MAGICNUMBER) {
|
||||
if ((magicNumber & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {
|
||||
size_t skippableSize;
|
||||
if (srcSize < ZSTD_skippableHeaderSize)
|
||||
return ERROR(srcSize_wrong);
|
||||
skippableSize = MEM_readLE32((const BYTE *)src + 4) +
|
||||
ZSTD_skippableHeaderSize;
|
||||
skippableSize = MEM_readLE32((const BYTE*)src + ZSTD_frameIdSize)
|
||||
+ ZSTD_skippableHeaderSize;
|
||||
if (srcSize < skippableSize) return ERROR(srcSize_wrong);
|
||||
|
||||
src = (const BYTE *)src + skippableSize;
|
||||
@@ -1716,33 +1759,31 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
|
||||
{
|
||||
DEBUGLOG(5, "ZSTD_decompressContinue");
|
||||
/* Sanity check */
|
||||
if (srcSize != dctx->expected) return ERROR(srcSize_wrong); /* unauthorized */
|
||||
if (srcSize != dctx->expected) return ERROR(srcSize_wrong); /* not allowed */
|
||||
if (dstCapacity) ZSTD_checkContinuity(dctx, dst);
|
||||
|
||||
switch (dctx->stage)
|
||||
{
|
||||
case ZSTDds_getFrameHeaderSize :
|
||||
if (srcSize != ZSTD_frameHeaderSize_prefix) return ERROR(srcSize_wrong); /* unauthorized */
|
||||
assert(src != NULL);
|
||||
if ((MEM_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */
|
||||
memcpy(dctx->headerBuffer, src, ZSTD_frameHeaderSize_prefix);
|
||||
dctx->expected = ZSTD_skippableHeaderSize - ZSTD_frameHeaderSize_prefix; /* magic number + skippable frame length */
|
||||
dctx->stage = ZSTDds_decodeSkippableHeader;
|
||||
return 0;
|
||||
}
|
||||
dctx->headerSize = ZSTD_frameHeaderSize(src, ZSTD_frameHeaderSize_prefix);
|
||||
if (dctx->format == ZSTD_f_zstd1) { /* allows header */
|
||||
assert(srcSize >= ZSTD_frameIdSize); /* to read skippable magic number */
|
||||
if ((MEM_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */
|
||||
memcpy(dctx->headerBuffer, src, srcSize);
|
||||
dctx->expected = ZSTD_skippableHeaderSize - srcSize; /* remaining to load to get full skippable frame header */
|
||||
dctx->stage = ZSTDds_decodeSkippableHeader;
|
||||
return 0;
|
||||
} }
|
||||
dctx->headerSize = ZSTD_frameHeaderSize_internal(src, srcSize, dctx->format);
|
||||
if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize;
|
||||
memcpy(dctx->headerBuffer, src, ZSTD_frameHeaderSize_prefix);
|
||||
if (dctx->headerSize > ZSTD_frameHeaderSize_prefix) {
|
||||
dctx->expected = dctx->headerSize - ZSTD_frameHeaderSize_prefix;
|
||||
dctx->stage = ZSTDds_decodeFrameHeader;
|
||||
return 0;
|
||||
}
|
||||
dctx->expected = 0; /* not necessary to copy more */
|
||||
/* fall-through */
|
||||
memcpy(dctx->headerBuffer, src, srcSize);
|
||||
dctx->expected = dctx->headerSize - srcSize;
|
||||
dctx->stage = ZSTDds_decodeFrameHeader;
|
||||
return 0;
|
||||
|
||||
case ZSTDds_decodeFrameHeader:
|
||||
assert(src != NULL);
|
||||
memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_prefix, src, dctx->expected);
|
||||
memcpy(dctx->headerBuffer + (dctx->headerSize - srcSize), src, srcSize);
|
||||
CHECK_F(ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize));
|
||||
dctx->expected = ZSTD_blockHeaderSize;
|
||||
dctx->stage = ZSTDds_decodeBlockHeader;
|
||||
@@ -1774,6 +1815,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
case ZSTDds_decompressLastBlock:
|
||||
case ZSTDds_decompressBlock:
|
||||
DEBUGLOG(5, "case ZSTDds_decompressBlock");
|
||||
@@ -1819,29 +1861,31 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
|
||||
}
|
||||
return rSize;
|
||||
}
|
||||
|
||||
case ZSTDds_checkChecksum:
|
||||
DEBUGLOG(4, "case ZSTDds_checkChecksum");
|
||||
assert(srcSize == 4); /* guaranteed by dctx->expected */
|
||||
{ U32 const h32 = (U32)XXH64_digest(&dctx->xxhState);
|
||||
U32 const check32 = MEM_readLE32(src);
|
||||
DEBUGLOG(4, "calculated %08X :: %08X read", h32, check32);
|
||||
DEBUGLOG(4, "checksum : calculated %08X :: %08X read", h32, check32);
|
||||
if (check32 != h32) return ERROR(checksum_wrong);
|
||||
dctx->expected = 0;
|
||||
dctx->stage = ZSTDds_getFrameHeaderSize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
case ZSTDds_decodeSkippableHeader:
|
||||
{ assert(src != NULL);
|
||||
memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_prefix, src, dctx->expected);
|
||||
dctx->expected = MEM_readLE32(dctx->headerBuffer + 4);
|
||||
dctx->stage = ZSTDds_skipFrame;
|
||||
return 0;
|
||||
}
|
||||
assert(src != NULL);
|
||||
assert(srcSize <= ZSTD_skippableHeaderSize);
|
||||
memcpy(dctx->headerBuffer + (ZSTD_skippableHeaderSize - srcSize), src, srcSize); /* complete skippable header */
|
||||
dctx->expected = MEM_readLE32(dctx->headerBuffer + ZSTD_frameIdSize); /* note : dctx->expected can grow seriously large, beyond local buffer size */
|
||||
dctx->stage = ZSTDds_skipFrame;
|
||||
return 0;
|
||||
|
||||
case ZSTDds_skipFrame:
|
||||
{ dctx->expected = 0;
|
||||
dctx->stage = ZSTDds_getFrameHeaderSize;
|
||||
return 0;
|
||||
}
|
||||
dctx->expected = 0;
|
||||
dctx->stage = ZSTDds_getFrameHeaderSize;
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return ERROR(GENERIC); /* impossible */
|
||||
}
|
||||
@@ -1922,7 +1966,7 @@ static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict
|
||||
if (magic != ZSTD_MAGIC_DICTIONARY) {
|
||||
return ZSTD_refDictContent(dctx, dict, dictSize); /* pure content mode */
|
||||
} }
|
||||
dctx->dictID = MEM_readLE32((const char*)dict + 4);
|
||||
dctx->dictID = MEM_readLE32((const char*)dict + ZSTD_frameIdSize);
|
||||
|
||||
/* load entropy tables */
|
||||
{ size_t const eSize = ZSTD_loadEntropy(&dctx->entropy, dict, dictSize);
|
||||
@@ -1936,6 +1980,29 @@ static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict
|
||||
return ZSTD_refDictContent(dctx, dict, dictSize);
|
||||
}
|
||||
|
||||
/* Note : this function cannot fail */
|
||||
size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)
|
||||
{
|
||||
assert(dctx != NULL);
|
||||
dctx->expected = ZSTD_startingInputLength(dctx->format); /* dctx->format must be properly set */
|
||||
dctx->stage = ZSTDds_getFrameHeaderSize;
|
||||
dctx->decodedSize = 0;
|
||||
dctx->previousDstEnd = NULL;
|
||||
dctx->base = NULL;
|
||||
dctx->vBase = NULL;
|
||||
dctx->dictEnd = NULL;
|
||||
dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */
|
||||
dctx->litEntropy = dctx->fseEntropy = 0;
|
||||
dctx->dictID = 0;
|
||||
ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue));
|
||||
memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */
|
||||
dctx->LLTptr = dctx->entropy.LLTable;
|
||||
dctx->MLTptr = dctx->entropy.MLTable;
|
||||
dctx->OFTptr = dctx->entropy.OFTable;
|
||||
dctx->HUFptr = dctx->entropy.hufTable;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
|
||||
{
|
||||
CHECK_F( ZSTD_decompressBegin(dctx) );
|
||||
@@ -2002,7 +2069,7 @@ static size_t ZSTD_loadEntropy_inDDict(ZSTD_DDict* ddict)
|
||||
{ U32 const magic = MEM_readLE32(ddict->dictContent);
|
||||
if (magic != ZSTD_MAGIC_DICTIONARY) return 0; /* pure content mode */
|
||||
}
|
||||
ddict->dictID = MEM_readLE32((const char*)ddict->dictContent + 4);
|
||||
ddict->dictID = MEM_readLE32((const char*)ddict->dictContent + ZSTD_frameIdSize);
|
||||
|
||||
/* load entropy tables */
|
||||
CHECK_E( ZSTD_loadEntropy(&ddict->entropy, ddict->dictContent, ddict->dictSize), dictionary_corrupted );
|
||||
@@ -2123,7 +2190,7 @@ unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize)
|
||||
{
|
||||
if (dictSize < 8) return 0;
|
||||
if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) return 0;
|
||||
return MEM_readLE32((const char*)dict + 4);
|
||||
return MEM_readLE32((const char*)dict + ZSTD_frameIdSize);
|
||||
}
|
||||
|
||||
/*! ZSTD_getDictID_fromDDict() :
|
||||
@@ -2218,13 +2285,15 @@ size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t di
|
||||
return ZSTD_frameHeaderSize_prefix;
|
||||
}
|
||||
|
||||
/* note : this variant can't fail */
|
||||
size_t ZSTD_initDStream(ZSTD_DStream* zds)
|
||||
{
|
||||
return ZSTD_initDStream_usingDict(zds, NULL, 0);
|
||||
}
|
||||
|
||||
/* ZSTD_initDStream_usingDDict() :
|
||||
* ddict will just be referenced, and must outlive decompression session */
|
||||
* ddict will just be referenced, and must outlive decompression session
|
||||
* this function cannot fail */
|
||||
size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict)
|
||||
{
|
||||
size_t const initResult = ZSTD_initDStream(zds);
|
||||
@@ -2244,14 +2313,39 @@ size_t ZSTD_resetDStream(ZSTD_DStream* zds)
|
||||
size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds,
|
||||
ZSTD_DStreamParameter_e paramType, unsigned paramValue)
|
||||
{
|
||||
ZSTD_STATIC_ASSERT((unsigned)zdss_loadHeader >= (unsigned)zdss_init);
|
||||
if ((unsigned)zds->streamStage > (unsigned)zdss_loadHeader)
|
||||
return ERROR(stage_wrong);
|
||||
switch(paramType)
|
||||
{
|
||||
default : return ERROR(parameter_unsupported);
|
||||
case DStream_p_maxWindowSize : zds->maxWindowSize = paramValue ? paramValue : (U32)(-1); break;
|
||||
case DStream_p_maxWindowSize :
|
||||
DEBUGLOG(4, "setting maxWindowSize = %u KB", paramValue >> 10);
|
||||
zds->maxWindowSize = paramValue ? paramValue : (U32)(-1);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize)
|
||||
{
|
||||
ZSTD_STATIC_ASSERT((unsigned)zdss_loadHeader >= (unsigned)zdss_init);
|
||||
if ((unsigned)dctx->streamStage > (unsigned)zdss_loadHeader)
|
||||
return ERROR(stage_wrong);
|
||||
dctx->maxWindowSize = maxWindowSize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format)
|
||||
{
|
||||
DEBUGLOG(4, "ZSTD_DCtx_setFormat : %u", (unsigned)format);
|
||||
ZSTD_STATIC_ASSERT((unsigned)zdss_loadHeader >= (unsigned)zdss_init);
|
||||
if ((unsigned)dctx->streamStage > (unsigned)zdss_loadHeader)
|
||||
return ERROR(stage_wrong);
|
||||
dctx->format = format;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds)
|
||||
{
|
||||
@@ -2276,7 +2370,7 @@ size_t ZSTD_estimateDStreamSize(size_t windowSize)
|
||||
return ZSTD_estimateDCtxSize() + inBuffSize + outBuffSize;
|
||||
}
|
||||
|
||||
ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize)
|
||||
size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize)
|
||||
{
|
||||
U32 const windowSizeMax = 1U << ZSTD_WINDOWLOG_MAX; /* note : should be user-selectable */
|
||||
ZSTD_frameHeader zfh;
|
||||
@@ -2310,7 +2404,18 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||
U32 someMoreWork = 1;
|
||||
|
||||
DEBUGLOG(5, "ZSTD_decompressStream");
|
||||
if (input->pos > input->size) { /* forbidden */
|
||||
DEBUGLOG(5, "in: pos: %u vs size: %u",
|
||||
(U32)input->pos, (U32)input->size);
|
||||
return ERROR(srcSize_wrong);
|
||||
}
|
||||
if (output->pos > output->size) { /* forbidden */
|
||||
DEBUGLOG(5, "out: pos: %u vs size: %u",
|
||||
(U32)output->pos, (U32)output->size);
|
||||
return ERROR(dstSize_tooSmall);
|
||||
}
|
||||
DEBUGLOG(5, "input size : %u", (U32)(input->size - input->pos));
|
||||
|
||||
#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
|
||||
if (zds->legacyVersion) {
|
||||
/* legacy support is incompatible with static dctx */
|
||||
@@ -2327,7 +2432,9 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||
/* fall-through */
|
||||
|
||||
case zdss_loadHeader :
|
||||
{ size_t const hSize = ZSTD_getFrameHeader(&zds->fParams, zds->headerBuffer, zds->lhSize);
|
||||
DEBUGLOG(5, "stage zdss_loadHeader (srcSize : %u)", (U32)(iend - ip));
|
||||
{ size_t const hSize = ZSTD_getFrameHeader_internal(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format);
|
||||
DEBUGLOG(5, "header size : %u", (U32)hSize);
|
||||
if (ZSTD_isError(hSize)) {
|
||||
#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
|
||||
U32 const legacyVersion = ZSTD_isLegacy(istart, iend-istart);
|
||||
@@ -2380,7 +2487,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||
CHECK_F(ZSTD_decompressBegin_usingDDict(zds, zds->ddict));
|
||||
|
||||
if ((MEM_readLE32(zds->headerBuffer) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */
|
||||
zds->expected = MEM_readLE32(zds->headerBuffer + 4);
|
||||
zds->expected = MEM_readLE32(zds->headerBuffer + ZSTD_frameIdSize);
|
||||
zds->stage = ZSTDds_skipFrame;
|
||||
} else {
|
||||
CHECK_F(ZSTD_decodeFrameHeader(zds, zds->headerBuffer, zds->lhSize));
|
||||
@@ -2389,7 +2496,8 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||
}
|
||||
|
||||
/* control buffer memory usage */
|
||||
DEBUGLOG(4, "Control max buffer memory usage");
|
||||
DEBUGLOG(4, "Control max buffer memory usage (max %u KB)",
|
||||
(U32)(zds->maxWindowSize >> 10));
|
||||
zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN);
|
||||
if (zds->fParams.windowSize > zds->maxWindowSize) return ERROR(frameParameter_windowTooLarge);
|
||||
|
||||
@@ -2518,3 +2626,30 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||
return nextSrcSizeHint;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
size_t ZSTD_decompress_generic(ZSTD_DCtx* dctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
|
||||
{
|
||||
return ZSTD_decompressStream(dctx, output, input);
|
||||
}
|
||||
|
||||
size_t ZSTD_decompress_generic_simpleArgs (
|
||||
ZSTD_DCtx* dctx,
|
||||
void* dst, size_t dstCapacity, size_t* dstPos,
|
||||
const void* src, size_t srcSize, size_t* srcPos)
|
||||
{
|
||||
ZSTD_outBuffer output = { dst, dstCapacity, *dstPos };
|
||||
ZSTD_inBuffer input = { src, srcSize, *srcPos };
|
||||
/* ZSTD_compress_generic() will check validity of dstPos and srcPos */
|
||||
size_t const cErr = ZSTD_decompress_generic(dctx, &output, &input);
|
||||
*dstPos = output.pos;
|
||||
*srcPos = input.pos;
|
||||
return cErr;
|
||||
}
|
||||
|
||||
void ZSTD_DCtx_reset(ZSTD_DCtx* dctx)
|
||||
{
|
||||
(void)ZSTD_initDStream(dctx);
|
||||
dctx->format = ZSTD_f_zstd1;
|
||||
dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;
|
||||
}
|
||||
|
||||
+14
-14
@@ -711,8 +711,8 @@ ZDICTLIB_API size_t ZDICT_trainFromBuffer_cover(
|
||||
* compiled with multithreaded support.
|
||||
*/
|
||||
typedef struct COVER_best_s {
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
ZSTD_pthread_mutex_t mutex;
|
||||
ZSTD_pthread_cond_t cond;
|
||||
size_t liveJobs;
|
||||
void *dict;
|
||||
size_t dictSize;
|
||||
@@ -725,8 +725,8 @@ typedef struct COVER_best_s {
|
||||
*/
|
||||
static void COVER_best_init(COVER_best_t *best) {
|
||||
if (best==NULL) return; /* compatible with init on NULL */
|
||||
(void)pthread_mutex_init(&best->mutex, NULL);
|
||||
(void)pthread_cond_init(&best->cond, NULL);
|
||||
(void)ZSTD_pthread_mutex_init(&best->mutex, NULL);
|
||||
(void)ZSTD_pthread_cond_init(&best->cond, NULL);
|
||||
best->liveJobs = 0;
|
||||
best->dict = NULL;
|
||||
best->dictSize = 0;
|
||||
@@ -741,11 +741,11 @@ static void COVER_best_wait(COVER_best_t *best) {
|
||||
if (!best) {
|
||||
return;
|
||||
}
|
||||
pthread_mutex_lock(&best->mutex);
|
||||
ZSTD_pthread_mutex_lock(&best->mutex);
|
||||
while (best->liveJobs != 0) {
|
||||
pthread_cond_wait(&best->cond, &best->mutex);
|
||||
ZSTD_pthread_cond_wait(&best->cond, &best->mutex);
|
||||
}
|
||||
pthread_mutex_unlock(&best->mutex);
|
||||
ZSTD_pthread_mutex_unlock(&best->mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -759,8 +759,8 @@ static void COVER_best_destroy(COVER_best_t *best) {
|
||||
if (best->dict) {
|
||||
free(best->dict);
|
||||
}
|
||||
pthread_mutex_destroy(&best->mutex);
|
||||
pthread_cond_destroy(&best->cond);
|
||||
ZSTD_pthread_mutex_destroy(&best->mutex);
|
||||
ZSTD_pthread_cond_destroy(&best->cond);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -771,9 +771,9 @@ static void COVER_best_start(COVER_best_t *best) {
|
||||
if (!best) {
|
||||
return;
|
||||
}
|
||||
pthread_mutex_lock(&best->mutex);
|
||||
ZSTD_pthread_mutex_lock(&best->mutex);
|
||||
++best->liveJobs;
|
||||
pthread_mutex_unlock(&best->mutex);
|
||||
ZSTD_pthread_mutex_unlock(&best->mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -789,7 +789,7 @@ static void COVER_best_finish(COVER_best_t *best, size_t compressedSize,
|
||||
}
|
||||
{
|
||||
size_t liveJobs;
|
||||
pthread_mutex_lock(&best->mutex);
|
||||
ZSTD_pthread_mutex_lock(&best->mutex);
|
||||
--best->liveJobs;
|
||||
liveJobs = best->liveJobs;
|
||||
/* If the new dictionary is better */
|
||||
@@ -812,9 +812,9 @@ static void COVER_best_finish(COVER_best_t *best, size_t compressedSize,
|
||||
best->parameters = parameters;
|
||||
best->compressedSize = compressedSize;
|
||||
}
|
||||
pthread_mutex_unlock(&best->mutex);
|
||||
ZSTD_pthread_mutex_unlock(&best->mutex);
|
||||
if (liveJobs == 0) {
|
||||
pthread_cond_broadcast(&best->cond);
|
||||
ZSTD_pthread_cond_broadcast(&best->cond);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+217
-76
@@ -59,7 +59,7 @@ extern "C" {
|
||||
/*------ Version ------*/
|
||||
#define ZSTD_VERSION_MAJOR 1
|
||||
#define ZSTD_VERSION_MINOR 3
|
||||
#define ZSTD_VERSION_RELEASE 1
|
||||
#define ZSTD_VERSION_RELEASE 2
|
||||
|
||||
#define ZSTD_VERSION_NUMBER (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE)
|
||||
ZSTDLIB_API unsigned ZSTD_versionNumber(void); /**< useful to check dll version */
|
||||
@@ -131,10 +131,11 @@ ZSTDLIB_API unsigned long long ZSTD_getDecompressedSize(const void* src, size_t
|
||||
|
||||
|
||||
/*====== Helper functions ======*/
|
||||
ZSTDLIB_API int ZSTD_maxCLevel(void); /*!< maximum compression level available */
|
||||
#define ZSTD_COMPRESSBOUND(srcSize) ((srcSize) + ((srcSize)>>8) + (((srcSize) < 128 KB) ? ((128 KB - (srcSize)) >> 11) /* margin, from 64 to 0 */ : 0)) /* this formula ensures that bound(A) + bound(B) <= bound(A+B) as long as A and B >= 128 KB */
|
||||
ZSTDLIB_API size_t ZSTD_compressBound(size_t srcSize); /*!< maximum compressed size in worst case scenario */
|
||||
ZSTDLIB_API unsigned ZSTD_isError(size_t code); /*!< tells if a `size_t` function result is an error code */
|
||||
ZSTDLIB_API const char* ZSTD_getErrorName(size_t code); /*!< provides readable string from an error code */
|
||||
ZSTDLIB_API int ZSTD_maxCLevel(void); /*!< maximum compression level available */
|
||||
|
||||
|
||||
/***************************************
|
||||
@@ -376,30 +377,31 @@ ZSTDLIB_API size_t ZSTD_DStreamOutSize(void); /*!< recommended size for output
|
||||
#define ZSTD_MAGIC_SKIPPABLE_START 0x184D2A50U
|
||||
#define ZSTD_MAGIC_DICTIONARY 0xEC30A437 /* v0.7+ */
|
||||
|
||||
#define ZSTD_WINDOWLOG_MAX_32 27
|
||||
#define ZSTD_WINDOWLOG_MAX_64 27
|
||||
#define ZSTD_WINDOWLOG_MAX_32 30
|
||||
#define ZSTD_WINDOWLOG_MAX_64 31
|
||||
#define ZSTD_WINDOWLOG_MAX ((unsigned)(sizeof(size_t) == 4 ? ZSTD_WINDOWLOG_MAX_32 : ZSTD_WINDOWLOG_MAX_64))
|
||||
#define ZSTD_WINDOWLOG_MIN 10
|
||||
#define ZSTD_HASHLOG_MAX MIN(ZSTD_WINDOWLOG_MAX, 30)
|
||||
#define ZSTD_HASHLOG_MIN 6
|
||||
#define ZSTD_CHAINLOG_MAX MIN(ZSTD_WINDOWLOG_MAX+1, 30)
|
||||
#define ZSTD_CHAINLOG_MIN ZSTD_HASHLOG_MIN
|
||||
#define ZSTD_HASHLOG3_MAX 17
|
||||
#define ZSTD_SEARCHLOG_MAX (ZSTD_WINDOWLOG_MAX-1)
|
||||
#define ZSTD_SEARCHLOG_MIN 1
|
||||
#define ZSTD_SEARCHLENGTH_MAX 7 /* only for ZSTD_fast, other strategies are limited to 6 */
|
||||
#define ZSTD_SEARCHLENGTH_MIN 3 /* only for ZSTD_btopt, other strategies are limited to 4 */
|
||||
#define ZSTD_TARGETLENGTH_MIN 4
|
||||
#define ZSTD_TARGETLENGTH_MAX 999
|
||||
#define ZSTD_LDM_MINMATCH_MIN 4
|
||||
#define ZSTD_WINDOWLOG_MIN 10
|
||||
#define ZSTD_HASHLOG_MAX MIN(ZSTD_WINDOWLOG_MAX, 30)
|
||||
#define ZSTD_HASHLOG_MIN 6
|
||||
#define ZSTD_CHAINLOG_MAX MIN(ZSTD_WINDOWLOG_MAX+1, 30)
|
||||
#define ZSTD_CHAINLOG_MIN ZSTD_HASHLOG_MIN
|
||||
#define ZSTD_HASHLOG3_MAX 17
|
||||
#define ZSTD_SEARCHLOG_MAX (ZSTD_WINDOWLOG_MAX-1)
|
||||
#define ZSTD_SEARCHLOG_MIN 1
|
||||
#define ZSTD_SEARCHLENGTH_MAX 7 /* only for ZSTD_fast, other strategies are limited to 6 */
|
||||
#define ZSTD_SEARCHLENGTH_MIN 3 /* only for ZSTD_btopt, other strategies are limited to 4 */
|
||||
#define ZSTD_TARGETLENGTH_MIN 4 /* only useful for btopt */
|
||||
#define ZSTD_TARGETLENGTH_MAX 999 /* only useful for btopt */
|
||||
#define ZSTD_LDM_MINMATCH_MIN 4
|
||||
#define ZSTD_LDM_MINMATCH_MAX 4096
|
||||
#define ZSTD_LDM_BUCKETSIZELOG_MAX 8
|
||||
|
||||
#define ZSTD_FRAMEHEADERSIZE_MAX 18 /* for static allocation */
|
||||
#define ZSTD_FRAMEHEADERSIZE_MIN 6
|
||||
static const size_t ZSTD_frameHeaderSize_prefix = 5; /* minimum input size to know frame header size */
|
||||
static const size_t ZSTD_frameHeaderSize_max = ZSTD_FRAMEHEADERSIZE_MAX;
|
||||
#define ZSTD_FRAMEHEADERSIZE_PREFIX 5 /* minimum input size to know frame header size */
|
||||
#define ZSTD_FRAMEHEADERSIZE_MIN 6
|
||||
#define ZSTD_FRAMEHEADERSIZE_MAX 18 /* for static allocation */
|
||||
static const size_t ZSTD_frameHeaderSize_prefix = ZSTD_FRAMEHEADERSIZE_PREFIX;
|
||||
static const size_t ZSTD_frameHeaderSize_min = ZSTD_FRAMEHEADERSIZE_MIN;
|
||||
static const size_t ZSTD_frameHeaderSize_max = ZSTD_FRAMEHEADERSIZE_MAX;
|
||||
static const size_t ZSTD_skippableHeaderSize = 8; /* magic number + skippable frame length */
|
||||
|
||||
|
||||
@@ -486,7 +488,7 @@ ZSTDLIB_API size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize);
|
||||
|
||||
/*! ZSTD_sizeof_*() :
|
||||
* These functions give the current memory usage of selected object.
|
||||
* Object memory usage can evolve if it's re-used multiple times. */
|
||||
* Object memory usage can evolve when re-used multiple times. */
|
||||
ZSTDLIB_API size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx);
|
||||
ZSTDLIB_API size_t ZSTD_sizeof_DCtx(const ZSTD_DCtx* dctx);
|
||||
ZSTDLIB_API size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs);
|
||||
@@ -499,21 +501,21 @@ ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict);
|
||||
* of a future {D,C}Ctx, before its creation.
|
||||
* ZSTD_estimateCCtxSize() will provide a budget large enough for any compression level up to selected one.
|
||||
* It will also consider src size to be arbitrarily "large", which is worst case.
|
||||
* If srcSize is known to always be small, ZSTD_estimateCCtxSize_advanced_usingCParams() can provide a tighter estimation.
|
||||
* ZSTD_estimateCCtxSize_advanced_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
|
||||
* ZSTD_estimateCCtxSize_advanced_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is > 1.
|
||||
* If srcSize is known to always be small, ZSTD_estimateCCtxSize_usingCParams() can provide a tighter estimation.
|
||||
* ZSTD_estimateCCtxSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
|
||||
* ZSTD_estimateCCtxSize_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is > 1.
|
||||
* Note : CCtx estimation is only correct for single-threaded compression */
|
||||
ZSTDLIB_API size_t ZSTD_estimateCCtxSize(int compressionLevel);
|
||||
ZSTDLIB_API size_t ZSTD_estimateCCtxSize_advanced_usingCParams(ZSTD_compressionParameters cParams);
|
||||
ZSTDLIB_API size_t ZSTD_estimateCCtxSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* params);
|
||||
ZSTDLIB_API size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams);
|
||||
ZSTDLIB_API size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params);
|
||||
ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void);
|
||||
|
||||
/*! ZSTD_estimateCStreamSize() :
|
||||
* ZSTD_estimateCStreamSize() will provide a budget large enough for any compression level up to selected one.
|
||||
* It will also consider src size to be arbitrarily "large", which is worst case.
|
||||
* If srcSize is known to always be small, ZSTD_estimateCStreamSize_advanced_usingCParams() can provide a tighter estimation.
|
||||
* ZSTD_estimateCStreamSize_advanced_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
|
||||
* ZSTD_estimateCStreamSize_advanced_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is set to a value > 1.
|
||||
* If srcSize is known to always be small, ZSTD_estimateCStreamSize_usingCParams() can provide a tighter estimation.
|
||||
* ZSTD_estimateCStreamSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
|
||||
* ZSTD_estimateCStreamSize_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is set to a value > 1.
|
||||
* Note : CStream estimation is only correct for single-threaded compression.
|
||||
* ZSTD_DStream memory budget depends on window Size.
|
||||
* This information can be passed manually, using ZSTD_estimateDStreamSize,
|
||||
@@ -522,14 +524,14 @@ ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void);
|
||||
* an internal ?Dict will be created, which additional size is not estimated here.
|
||||
* In this case, get total size by adding ZSTD_estimate?DictSize */
|
||||
ZSTDLIB_API size_t ZSTD_estimateCStreamSize(int compressionLevel);
|
||||
ZSTDLIB_API size_t ZSTD_estimateCStreamSize_advanced_usingCParams(ZSTD_compressionParameters cParams);
|
||||
ZSTDLIB_API size_t ZSTD_estimateCStreamSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* params);
|
||||
ZSTDLIB_API size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams);
|
||||
ZSTDLIB_API size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params);
|
||||
ZSTDLIB_API size_t ZSTD_estimateDStreamSize(size_t windowSize);
|
||||
ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize);
|
||||
|
||||
typedef enum {
|
||||
ZSTD_dlm_byCopy = 0, /* Copy dictionary content internally. */
|
||||
ZSTD_dlm_byRef, /* Reference dictionary content -- the dictionary buffer must outlives its users. */
|
||||
ZSTD_dlm_byCopy = 0, /**< Copy dictionary content internally */
|
||||
ZSTD_dlm_byRef, /**< Reference dictionary content -- the dictionary buffer must outlive its users. */
|
||||
} ZSTD_dictLoadMethod_e;
|
||||
|
||||
/*! ZSTD_estimate?DictSize() :
|
||||
@@ -747,12 +749,12 @@ ZSTDLIB_API size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledg
|
||||
|
||||
|
||||
/*===== Advanced Streaming decompression functions =====*/
|
||||
typedef enum { DStream_p_maxWindowSize } ZSTD_DStreamParameter_e;
|
||||
ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem);
|
||||
ZSTDLIB_API ZSTD_DStream* ZSTD_initStaticDStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticDCtx() */
|
||||
ZSTDLIB_API size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, ZSTD_DStreamParameter_e paramType, unsigned paramValue);
|
||||
ZSTDLIB_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); /**< note: a dict will not be used if dict == NULL or dictSize < 8 */
|
||||
ZSTDLIB_API size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict); /**< note : ddict will just be referenced, and must outlive decompression session */
|
||||
typedef enum { DStream_p_maxWindowSize } ZSTD_DStreamParameter_e;
|
||||
ZSTDLIB_API size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, ZSTD_DStreamParameter_e paramType, unsigned paramValue); /* obsolete : this API will be removed in a future version */
|
||||
ZSTDLIB_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); /**< note: no dictionary will be used if dict == NULL or dictSize < 8 */
|
||||
ZSTDLIB_API size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict); /**< note : ddict is referenced, it must outlive decompression session */
|
||||
ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds); /**< re-use decompression parameters from previous init; saves dictionary loading */
|
||||
|
||||
|
||||
@@ -760,8 +762,8 @@ ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds); /**< re-use decompress
|
||||
* Buffer-less and synchronous inner streaming functions
|
||||
*
|
||||
* This is an advanced API, giving full control over buffer management, for users which need direct control over memory.
|
||||
* But it's also a complex one, with many restrictions (documented below).
|
||||
* Prefer using normal streaming API for an easier experience
|
||||
* But it's also a complex one, with several restrictions, documented below.
|
||||
* Prefer normal streaming API for an easier experience.
|
||||
********************************************************************* */
|
||||
|
||||
/**
|
||||
@@ -778,8 +780,8 @@ ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds); /**< re-use decompress
|
||||
|
||||
Then, consume your input using ZSTD_compressContinue().
|
||||
There are some important considerations to keep in mind when using this advanced function :
|
||||
- ZSTD_compressContinue() has no internal buffer. It uses externally provided buffer only.
|
||||
- Interface is synchronous : input is consumed entirely and produce 1+ (or more) compressed blocks.
|
||||
- ZSTD_compressContinue() has no internal buffer. It uses externally provided buffers only.
|
||||
- Interface is synchronous : input is consumed entirely and produces 1+ compressed blocks.
|
||||
- Caller must ensure there is enough space in `dst` to store compressed data under worst case scenario.
|
||||
Worst case evaluation is provided by ZSTD_compressBound().
|
||||
ZSTD_compressContinue() doesn't guarantee recover after a failed compression.
|
||||
@@ -790,9 +792,9 @@ ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds); /**< re-use decompress
|
||||
|
||||
Finish a frame with ZSTD_compressEnd(), which will write the last block(s) and optional checksum.
|
||||
It's possible to use srcSize==0, in which case, it will write a final empty block to end the frame.
|
||||
Without last block mark, frames will be considered unfinished (corrupted) by decoders.
|
||||
Without last block mark, frames are considered unfinished (hence corrupted) by compliant decoders.
|
||||
|
||||
`ZSTD_CCtx` object can be re-used (ZSTD_compressBegin()) to compress some new frame.
|
||||
`ZSTD_CCtx` object can be re-used (ZSTD_compressBegin()) to compress again.
|
||||
*/
|
||||
|
||||
/*===== Buffer-less streaming compression functions =====*/
|
||||
@@ -908,40 +910,64 @@ ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx);
|
||||
|
||||
|
||||
|
||||
/*=== New advanced API (experimental, and compression only) ===*/
|
||||
/* ============================================ */
|
||||
/** New advanced API (experimental) */
|
||||
/* ============================================ */
|
||||
|
||||
/* notes on API design :
|
||||
* In this proposal, parameters are pushed one by one into an existing CCtx,
|
||||
* In this proposal, parameters are pushed one by one into an existing context,
|
||||
* and then applied on all subsequent compression jobs.
|
||||
* When no parameter is ever provided, CCtx is created with compression level ZSTD_CLEVEL_DEFAULT.
|
||||
*
|
||||
* This API is intended to replace all others experimental API.
|
||||
* It can basically do all other use cases, and even new ones.
|
||||
* It stands a good chance to become "stable",
|
||||
* after a reasonable testing period.
|
||||
* In constrast with _advanced() variants, it stands a reasonable chance to become "stable",
|
||||
* after a good testing period.
|
||||
*/
|
||||
|
||||
/* note on naming convention :
|
||||
* Initially, the API favored names like ZSTD_setCCtxParameter() .
|
||||
* In this proposal, convention is changed towards ZSTD_CCtx_setParameter() .
|
||||
* The main driver is that it identifies more clearly the target object type.
|
||||
* It feels clearer in light of potential variants :
|
||||
* It feels clearer when considering multiple targets :
|
||||
* ZSTD_CDict_setParameter() (rather than ZSTD_setCDictParameter())
|
||||
* ZSTD_DCtx_setParameter() (rather than ZSTD_setDCtxParameter() )
|
||||
* Left variant feels easier to distinguish.
|
||||
* ZSTD_CCtxParams_setParameter() (rather than ZSTD_setCCtxParamsParameter() )
|
||||
* etc...
|
||||
*/
|
||||
|
||||
/* note on enum design :
|
||||
* All enum will be manually set to explicit values before reaching "stable API" status */
|
||||
* All enum will be pinned to explicit values before reaching "stable API" status */
|
||||
|
||||
typedef enum {
|
||||
/* Question : should we have a format ZSTD_f_auto ?
|
||||
* For the time being, it would mean exactly the same as ZSTD_f_zstd1.
|
||||
* But, in the future, should several formats be supported,
|
||||
* on the compression side, it would mean "default format".
|
||||
* On the decompression side, it would mean "multi format",
|
||||
* and ZSTD_f_zstd1 could be reserved to mean "accept *only* zstd frames".
|
||||
* Since meaning is a little different, another option could be to define different enums for compression and decompression.
|
||||
* This question could be kept for later, when there are actually multiple formats to support,
|
||||
* but there is also the question of pinning enum values, and pinning value `0` is especially important */
|
||||
ZSTD_f_zstd1 = 0, /* zstd frame format, specified in zstd_compression_format.md (default) */
|
||||
ZSTD_f_zstd1_magicless, /* Variant of zstd frame format, without initial 4-bytes magic number.
|
||||
* Useful to save 4 bytes per generated frame.
|
||||
* Decoder cannot recognise automatically this format, requiring instructions. */
|
||||
} ZSTD_format_e;
|
||||
|
||||
typedef enum {
|
||||
/* compression format */
|
||||
ZSTD_p_format = 10, /* See ZSTD_format_e enum definition.
|
||||
* Cast selected format as unsigned for ZSTD_CCtx_setParameter() compatibility. */
|
||||
|
||||
/* compression parameters */
|
||||
ZSTD_p_compressionLevel=100, /* Update all compression parameters according to pre-defined cLevel table
|
||||
* Default level is ZSTD_CLEVEL_DEFAULT==3.
|
||||
* Special: value 0 means "do not change cLevel". */
|
||||
ZSTD_p_windowLog, /* Maximum allowed back-reference distance, expressed as power of 2.
|
||||
* Must be clamped between ZSTD_WINDOWLOG_MIN and ZSTD_WINDOWLOG_MAX.
|
||||
* Special: value 0 means "do not change windowLog". */
|
||||
* Special: value 0 means "do not change windowLog".
|
||||
* Note: Using a window size greater than ZSTD_MAXWINDOWSIZE_DEFAULT (default: 2^27)
|
||||
* requires setting the maximum window size at least as large during decompression. */
|
||||
ZSTD_p_hashLog, /* Size of the probe table, as a power of 2.
|
||||
* Resulting table size is (1 << (hashLog+2)).
|
||||
* Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX.
|
||||
@@ -1009,7 +1035,7 @@ typedef enum {
|
||||
* Larger values increase memory usage and compression ratio, but decrease
|
||||
* compression speed.
|
||||
* Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX
|
||||
* (default: 20). */
|
||||
* (default: windowlog - 7). */
|
||||
ZSTD_p_ldmMinMatch, /* Minimum size of searched matches for long distance matcher.
|
||||
* Larger/too small values usually decrease compression ratio.
|
||||
* Must be clamped between ZSTD_LDM_MINMATCH_MIN
|
||||
@@ -1103,15 +1129,15 @@ ZSTDLIB_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* pre
|
||||
typedef enum {
|
||||
ZSTD_e_continue=0, /* collect more data, encoder transparently decides when to output result, for optimal conditions */
|
||||
ZSTD_e_flush, /* flush any data provided so far - frame will continue, future data can still reference previous data for better compression */
|
||||
ZSTD_e_end /* flush any remaining data and ends current frame. Any future compression starts a new frame. */
|
||||
ZSTD_e_end /* flush any remaining data and close current frame. Any additional data starts a new frame. */
|
||||
} ZSTD_EndDirective;
|
||||
|
||||
/*! ZSTD_compress_generic() :
|
||||
* Behave about the same as ZSTD_compressStream. To note :
|
||||
* - Compression parameters are pushed into CCtx before starting compression, using ZSTD_CCtx_setParameter()
|
||||
* - Compression parameters cannot be changed once compression is started.
|
||||
* - *dstPos must be <= dstCapacity, *srcPos must be <= srcSize
|
||||
* - *dspPos and *srcPos will be updated. They are guaranteed to remain below their respective limit.
|
||||
* - outpot->pos must be <= dstCapacity, input->pos must be <= srcSize
|
||||
* - outpot->pos and input->pos will be updated. They are guaranteed to remain below their respective limit.
|
||||
* - @return provides the minimum amount of data still to flush from internal buffers
|
||||
* or an error code, which can be tested using ZSTD_isError().
|
||||
* if @return != 0, flush is not fully completed, there is some data left within internal buffers.
|
||||
@@ -1130,6 +1156,7 @@ ZSTDLIB_API size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
|
||||
* Useful after an error, or to interrupt an ongoing compression job and start a new one.
|
||||
* Any internal data not yet flushed is cancelled.
|
||||
* Dictionary (if any) is dropped.
|
||||
* All parameters are back to default values.
|
||||
* It's possible to modify compression parameters after a reset.
|
||||
*/
|
||||
ZSTDLIB_API void ZSTD_CCtx_reset(ZSTD_CCtx* cctx); /* Not ready yet ! */
|
||||
@@ -1138,30 +1165,33 @@ ZSTDLIB_API void ZSTD_CCtx_reset(ZSTD_CCtx* cctx); /* Not ready yet ! */
|
||||
/*! ZSTD_compress_generic_simpleArgs() :
|
||||
* Same as ZSTD_compress_generic(),
|
||||
* but using only integral types as arguments.
|
||||
* Argument list is larger and less expressive than ZSTD_{in,out}Buffer,
|
||||
* Argument list is larger than ZSTD_{in,out}Buffer,
|
||||
* but can be helpful for binders from dynamic languages
|
||||
* which have troubles handling structures containing memory pointers.
|
||||
*/
|
||||
size_t ZSTD_compress_generic_simpleArgs (
|
||||
ZSTDLIB_API size_t ZSTD_compress_generic_simpleArgs (
|
||||
ZSTD_CCtx* cctx,
|
||||
void* dst, size_t dstCapacity, size_t* dstPos,
|
||||
const void* src, size_t srcSize, size_t* srcPos,
|
||||
ZSTD_EndDirective endOp);
|
||||
|
||||
|
||||
/** ZSTD_CCtx_params
|
||||
*
|
||||
/*! ZSTD_CCtx_params :
|
||||
* Quick howto :
|
||||
* - ZSTD_createCCtxParams() : Create a ZSTD_CCtx_params structure
|
||||
* - ZSTD_CCtxParam_setParameter() : Push parameters one by one into an
|
||||
* existing ZSTD_CCtx_params structure. This is similar to
|
||||
* ZSTD_CCtx_setParameter().
|
||||
* - ZSTD_CCtx_setParametersUsingCCtxParams() : Apply parameters to an existing CCtx. These
|
||||
* parameters will be applied to all subsequent compression jobs.
|
||||
* - ZSTD_CCtxParam_setParameter() : Push parameters one by one into
|
||||
* an existing ZSTD_CCtx_params structure.
|
||||
* This is similar to
|
||||
* ZSTD_CCtx_setParameter().
|
||||
* - ZSTD_CCtx_setParametersUsingCCtxParams() : Apply parameters to
|
||||
* an existing CCtx.
|
||||
* These parameters will be applied to
|
||||
* all subsequent compression jobs.
|
||||
* - ZSTD_compress_generic() : Do compression using the CCtx.
|
||||
* - ZSTD_freeCCtxParams() : Free the memory.
|
||||
*
|
||||
* This can be used with ZSTD_estimateCCtxSize_opaque() for static allocation
|
||||
* for single-threaded compression.
|
||||
* This can be used with ZSTD_estimateCCtxSize_advanced_usingCCtxParams()
|
||||
* for static allocation for single-threaded compression.
|
||||
*/
|
||||
ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void);
|
||||
|
||||
@@ -1189,22 +1219,133 @@ ZSTDLIB_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params);
|
||||
* Set one compression parameter, selected by enum ZSTD_cParameter.
|
||||
* Parameters must be applied to a ZSTD_CCtx using ZSTD_CCtx_setParametersUsingCCtxParams().
|
||||
* Note : when `value` is an enum, cast it to unsigned for proper type checking.
|
||||
* @result : 0, or an error code (which can be tested with ZSTD_isError()).
|
||||
* @result : 0, or an error code (which can be tested with ZSTD_isError()).
|
||||
*/
|
||||
ZSTDLIB_API size_t ZSTD_CCtxParam_setParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, unsigned value);
|
||||
|
||||
/*! ZSTD_CCtx_setParametersUsingCCtxParams() :
|
||||
* Apply a set of ZSTD_CCtx_params to the compression context.
|
||||
* This must be done before the dictionary is loaded.
|
||||
* The pledgedSrcSize is treated as unknown.
|
||||
* Multithreading parameters are applied only if nbThreads > 1.
|
||||
* Apply a set of ZSTD_CCtx_params to the compression context.
|
||||
* This must be done before the dictionary is loaded.
|
||||
* The pledgedSrcSize is treated as unknown.
|
||||
* Multithreading parameters are applied only if nbThreads > 1.
|
||||
*/
|
||||
ZSTDLIB_API size_t ZSTD_CCtx_setParametersUsingCCtxParams(
|
||||
ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params);
|
||||
|
||||
/**
|
||||
Block functions
|
||||
|
||||
/*=== Advanced parameters for decompression API ===*/
|
||||
|
||||
/* The following parameters must be set after creating a ZSTD_DCtx* (or ZSTD_DStream*) object,
|
||||
* but before starting decompression of a frame.
|
||||
*/
|
||||
|
||||
/*! ZSTD_DCtx_loadDictionary() :
|
||||
* Create an internal DDict from dict buffer,
|
||||
* to be used to decompress next frames.
|
||||
* @result : 0, or an error code (which can be tested with ZSTD_isError()).
|
||||
* Special : Adding a NULL (or 0-size) dictionary invalidates any previous dictionary,
|
||||
* meaning "return to no-dictionary mode".
|
||||
* Note 1 : `dict` content will be copied internally.
|
||||
* Use ZSTD_DCtx_loadDictionary_byReference()
|
||||
* to reference dictionary content instead.
|
||||
* In which case, the dictionary buffer must outlive its users.
|
||||
* Note 2 : Loading a dictionary involves building tables,
|
||||
* which has a non-negligible impact on CPU usage and latency.
|
||||
* Note 3 : Use ZSTD_DCtx_loadDictionary_advanced() to select
|
||||
* how dictionary content will be interpreted and loaded.
|
||||
*/
|
||||
ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); /* not implemented */
|
||||
ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); /* not implemented */
|
||||
ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictMode_e dictMode); /* not implemented */
|
||||
|
||||
|
||||
/*! ZSTD_DCtx_refDDict() :
|
||||
* Reference a prepared dictionary, to be used to decompress next frames.
|
||||
* The dictionary remains active for decompression of future frames using same DCtx.
|
||||
* @result : 0, or an error code (which can be tested with ZSTD_isError()).
|
||||
* Note 1 : Currently, only one dictionary can be managed.
|
||||
* Referencing a new dictionary effectively "discards" any previous one.
|
||||
* Special : adding a NULL DDict means "return to no-dictionary mode".
|
||||
* Note 2 : DDict is just referenced, its lifetime must outlive its usage from DCtx.
|
||||
*/
|
||||
ZSTDLIB_API size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); /* not implemented */
|
||||
|
||||
|
||||
/*! ZSTD_DCtx_refPrefix() :
|
||||
* Reference a prefix (single-usage dictionary) for next compression job.
|
||||
* Prefix is **only used once**. It must be explicitly referenced before each frame.
|
||||
* If there is a need to use same prefix multiple times, consider embedding it into a ZSTD_DDict instead.
|
||||
* @result : 0, or an error code (which can be tested with ZSTD_isError()).
|
||||
* Note 1 : Adding any prefix (including NULL) invalidates any previously set prefix or dictionary
|
||||
* Note 2 : Prefix buffer is referenced. It must outlive compression job.
|
||||
* Note 3 : By default, the prefix is treated as raw content (ZSTD_dm_rawContent).
|
||||
* Use ZSTD_CCtx_refPrefix_advanced() to alter dictMode.
|
||||
* Note 4 : Referencing a raw content prefix has almost no cpu nor memory cost.
|
||||
*/
|
||||
ZSTDLIB_API size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize); /* not implemented */
|
||||
ZSTDLIB_API size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictMode_e dictMode); /* not implemented */
|
||||
|
||||
|
||||
/*! ZSTD_DCtx_setMaxWindowSize() :
|
||||
* Refuses allocating internal buffers for frames requiring a window size larger than provided limit.
|
||||
* This is useful to prevent a decoder context from reserving too much memory for itself (potential attack scenario).
|
||||
* This parameter is only useful in streaming mode, since no internal buffer is allocated in direct mode.
|
||||
* By default, a decompression context accepts all window sizes <= (1 << ZSTD_WINDOWLOG_MAX)
|
||||
* @return : 0, or an error code (which can be tested using ZSTD_isError()).
|
||||
*/
|
||||
ZSTDLIB_API size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize);
|
||||
|
||||
|
||||
/*! ZSTD_DCtx_setFormat() :
|
||||
* Instruct the decoder context about what kind of data to decode next.
|
||||
* This instruction is mandatory to decode data without a fully-formed header,
|
||||
* such ZSTD_f_zstd1_magicless for example.
|
||||
* @return : 0, or an error code (which can be tested using ZSTD_isError()).
|
||||
*/
|
||||
ZSTDLIB_API size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format);
|
||||
|
||||
|
||||
/*! ZSTD_decompress_generic() :
|
||||
* Behave the same as ZSTD_decompressStream.
|
||||
* Decompression parameters cannot be changed once decompression is started.
|
||||
* @return : an error code, which can be tested using ZSTD_isError()
|
||||
* if >0, a hint, nb of expected input bytes for next invocation.
|
||||
* `0` means : a frame has just been fully decoded and flushed.
|
||||
*/
|
||||
ZSTDLIB_API size_t ZSTD_decompress_generic(ZSTD_DCtx* dctx,
|
||||
ZSTD_outBuffer* output,
|
||||
ZSTD_inBuffer* input);
|
||||
|
||||
|
||||
/*! ZSTD_decompress_generic_simpleArgs() :
|
||||
* Same as ZSTD_decompress_generic(),
|
||||
* but using only integral types as arguments.
|
||||
* Argument list is larger than ZSTD_{in,out}Buffer,
|
||||
* but can be helpful for binders from dynamic languages
|
||||
* which have troubles handling structures containing memory pointers.
|
||||
*/
|
||||
ZSTDLIB_API size_t ZSTD_decompress_generic_simpleArgs (
|
||||
ZSTD_DCtx* dctx,
|
||||
void* dst, size_t dstCapacity, size_t* dstPos,
|
||||
const void* src, size_t srcSize, size_t* srcPos);
|
||||
|
||||
|
||||
/*! ZSTD_DCtx_reset() :
|
||||
* Return a DCtx to clean state.
|
||||
* If a decompression was ongoing, any internal data not yet flushed is cancelled.
|
||||
* All parameters are back to default values, including sticky ones.
|
||||
* Dictionary (if any) is dropped.
|
||||
* Parameters can be modified again after a reset.
|
||||
*/
|
||||
ZSTDLIB_API void ZSTD_DCtx_reset(ZSTD_DCtx* dctx);
|
||||
|
||||
|
||||
|
||||
/* ============================ */
|
||||
/** Block level API */
|
||||
/* ============================ */
|
||||
|
||||
/*!
|
||||
Block functions produce and decode raw zstd blocks, without frame metadata.
|
||||
Frame metadata cost is typically ~18 bytes, which can be non-negligible for very small blocks (< 100 bytes).
|
||||
User will have to take in charge required information to regenerate data, such as compressed and content sizes.
|
||||
@@ -1216,7 +1357,7 @@ ZSTDLIB_API size_t ZSTD_CCtx_setParametersUsingCCtxParams(
|
||||
+ compression : any ZSTD_compressBegin*() variant, including with dictionary
|
||||
+ decompression : any ZSTD_decompressBegin*() variant, including with dictionary
|
||||
+ copyCCtx() and copyDCtx() can be used too
|
||||
- Block size is limited, it must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX
|
||||
- Block size is limited, it must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX == 128 KB
|
||||
+ If input is larger than a block size, it's necessary to split input data into multiple blocks
|
||||
+ For inputs larger than a single block size, consider using the regular ZSTD_compress() instead.
|
||||
Frame metadata is not that costly, and quickly becomes negligible as source size grows larger.
|
||||
|
||||
+5
-8
@@ -40,7 +40,7 @@ CPPFLAGS+= -I$(ZSTDDIR) -I$(ZSTDDIR)/common -I$(ZSTDDIR)/compress \
|
||||
-DZSTD_NEWAPI \
|
||||
-DXXH_NAMESPACE=ZSTD_ # because xxhash.o already compiled with this macro from library
|
||||
CFLAGS ?= -O3
|
||||
DEBUGFLAGS= -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \
|
||||
DEBUGFLAGS+=-Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \
|
||||
-Wstrict-aliasing=1 -Wswitch-enum -Wdeclaration-after-statement \
|
||||
-Wstrict-prototypes -Wundef -Wpointer-arith -Wformat-security \
|
||||
-Wvla -Wformat=2 -Winit-self -Wfloat-equal -Wwrite-strings \
|
||||
@@ -140,13 +140,10 @@ allVariants: zstd zstd-compress zstd-decompress zstd-small zstd-nolegacy
|
||||
|
||||
$(ZSTDDECOMP_O): CFLAGS += $(ALIGN_LOOP)
|
||||
|
||||
zstd zstd4 : CPPFLAGS += $(THREAD_CPP) $(ZLIBCPP) $(LZMACPP)
|
||||
zstd zstd4 : LDFLAGS += $(THREAD_LD) $(ZLIBLD) $(LZMALD)
|
||||
zstd4 : CPPFLAGS += $(LZ4CPP)
|
||||
zstd4 : LDFLAGS += $(LZ4LD)
|
||||
zstd : LZ4_MSG := - lz4 support is disabled
|
||||
zstd zstd4 : CPPFLAGS += -DZSTD_LEGACY_SUPPORT=$(ZSTD_LEGACY_SUPPORT)
|
||||
zstd zstd4 : $(ZSTDLIB_FILES) zstdcli.o fileio.o bench.o datagen.o dibio.o
|
||||
zstd : CPPFLAGS += $(THREAD_CPP) $(ZLIBCPP) $(LZMACPP) $(LZ4CPP)
|
||||
zstd : LDFLAGS += $(THREAD_LD) $(ZLIBLD) $(LZMALD) $(LZ4LD)
|
||||
zstd : CPPFLAGS += -DZSTD_LEGACY_SUPPORT=$(ZSTD_LEGACY_SUPPORT)
|
||||
zstd : $(ZSTDLIB_FILES) zstdcli.o fileio.o bench.o datagen.o dibio.o
|
||||
@echo "$(THREAD_MSG)"
|
||||
@echo "$(ZLIB_MSG)"
|
||||
@echo "$(LZMA_MSG)"
|
||||
|
||||
@@ -40,6 +40,16 @@ There are however other Makefile targets that create different variations of CLI
|
||||
In which case, linking stage will fail if `lzma` library cannot be found.
|
||||
This might be useful to prevent silent feature disabling.
|
||||
|
||||
- __HAVE_LZ4__ : `zstd` can compress and decompress files in `.lz4` formats.
|
||||
This is ordered through commands `--format=lz4`.
|
||||
Alternatively, symlinks named `lz4`, or `unlz4` will mimic intended behavior.
|
||||
`.lz4` support is automatically enabled when `lz4` library is detected at build time.
|
||||
It's possible to disable `.lz4` support, by setting HAVE_LZ4=0 .
|
||||
Example : make zstd HAVE_LZ4=0
|
||||
It's also possible to force compilation with lz4 support, using HAVE_LZ4=1.
|
||||
In which case, linking stage will fail if `lz4` library cannot be found.
|
||||
This might be useful to prevent silent feature disabling.
|
||||
|
||||
- __ZSTD_LEGACY_SUPPORT__ : `zstd` can decompress files compressed by older versions of `zstd`.
|
||||
Starting v0.8.0, all versions of `zstd` produce frames compliant with the [specification](../doc/zstd_compression_format.md), and are therefore compatible.
|
||||
But older versions (< v0.8.0) produced different, incompatible, frames.
|
||||
|
||||
+200
-69
@@ -37,6 +37,7 @@
|
||||
# include <io.h>
|
||||
#endif
|
||||
|
||||
#include "bitstream.h"
|
||||
#include "mem.h"
|
||||
#include "fileio.h"
|
||||
#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_magicNumber, ZSTD_frameHeaderSize_max */
|
||||
@@ -56,6 +57,7 @@
|
||||
|
||||
#define LZ4_MAGICNUMBER 0x184D2204
|
||||
#if defined(ZSTD_LZ4COMPRESS) || defined(ZSTD_LZ4DECOMPRESS)
|
||||
# define LZ4F_ENABLE_OBSOLETE_ENUMS
|
||||
# include <lz4frame.h>
|
||||
# include <lz4.h>
|
||||
#endif
|
||||
@@ -138,6 +140,24 @@ static clock_t g_time = 0;
|
||||
} }
|
||||
|
||||
|
||||
/*-************************************
|
||||
* Signal (Ctrl-C trapping)
|
||||
**************************************/
|
||||
#include <signal.h>
|
||||
|
||||
static const char* g_artefact = NULL;
|
||||
static void INThandler(int sig)
|
||||
{
|
||||
assert(sig==SIGINT); (void)sig;
|
||||
#if !defined(_MSC_VER)
|
||||
signal(sig, SIG_IGN); /* this invocation generates a buggy warning in Visual Studio */
|
||||
#endif
|
||||
if (g_artefact) remove(g_artefact);
|
||||
DISPLAY("\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
|
||||
/* ************************************************************
|
||||
* Avoid fseek()'s 2GiB barrier with MSVC, MacOS, *BSD, MinGW
|
||||
***************************************************************/
|
||||
@@ -347,13 +367,16 @@ static size_t FIO_createDictBuffer(void** bufferPtr, const char* fileName)
|
||||
fileHandle = fopen(fileName, "rb");
|
||||
if (fileHandle==0) EXM_THROW(31, "%s: %s", fileName, strerror(errno));
|
||||
fileSize = UTIL_getFileSize(fileName);
|
||||
if (fileSize > DICTSIZE_MAX)
|
||||
if (fileSize > DICTSIZE_MAX) {
|
||||
EXM_THROW(32, "Dictionary file %s is too large (> %u MB)",
|
||||
fileName, DICTSIZE_MAX >> 20); /* avoid extreme cases */
|
||||
}
|
||||
*bufferPtr = malloc((size_t)fileSize);
|
||||
if (*bufferPtr==NULL) EXM_THROW(34, "%s", strerror(errno));
|
||||
{ size_t const readSize = fread(*bufferPtr, 1, (size_t)fileSize, fileHandle);
|
||||
if (readSize!=fileSize) EXM_THROW(35, "Error reading dictionary file %s", fileName); }
|
||||
{ size_t const readSize = fread(*bufferPtr, 1, (size_t)fileSize, fileHandle);
|
||||
if (readSize!=fileSize)
|
||||
EXM_THROW(35, "Error reading dictionary file %s", fileName);
|
||||
}
|
||||
fclose(fileHandle);
|
||||
return (size_t)fileSize;
|
||||
}
|
||||
@@ -378,7 +401,7 @@ typedef struct {
|
||||
} cRess_t;
|
||||
|
||||
static cRess_t FIO_createCResources(const char* dictFileName, int cLevel,
|
||||
U64 srcSize, int srcIsRegularFile,
|
||||
U64 srcSize,
|
||||
ZSTD_compressionParameters* comprParams) {
|
||||
cRess_t ress;
|
||||
memset(&ress, 0, sizeof(ress));
|
||||
@@ -416,10 +439,9 @@ static cRess_t FIO_createCResources(const char* dictFileName, int cLevel,
|
||||
|
||||
#ifdef ZSTD_NEWAPI
|
||||
{ /* frame parameters */
|
||||
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_contentSizeFlag, srcIsRegularFile) );
|
||||
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_dictIDFlag, g_dictIDFlag) );
|
||||
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_checksumFlag, g_checksumFlag) );
|
||||
CHECK( ZSTD_CCtx_setPledgedSrcSize(ress.cctx, srcSize) );
|
||||
(void)srcSize;
|
||||
/* compression level */
|
||||
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_compressionLevel, cLevel) );
|
||||
/* long distance matching */
|
||||
@@ -442,13 +464,13 @@ static cRess_t FIO_createCResources(const char* dictFileName, int cLevel,
|
||||
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_targetLength, comprParams->targetLength) );
|
||||
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_compressionStrategy, (U32)comprParams->strategy) );
|
||||
/* multi-threading */
|
||||
DISPLAYLEVEL(5,"set nb threads = %u \n", g_nbThreads);
|
||||
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_nbThreads, g_nbThreads) );
|
||||
/* dictionary */
|
||||
CHECK( ZSTD_CCtx_loadDictionary(ress.cctx, dictBuffer, dictBuffSize) );
|
||||
}
|
||||
#elif defined(ZSTD_MULTITHREAD)
|
||||
{ ZSTD_parameters params = ZSTD_getParams(cLevel, srcSize, dictBuffSize);
|
||||
params.fParams.contentSizeFlag = srcIsRegularFile;
|
||||
params.fParams.checksumFlag = g_checksumFlag;
|
||||
params.fParams.noDictIDFlag = !g_dictIDFlag;
|
||||
if (comprParams->windowLog) params.cParams.windowLog = comprParams->windowLog;
|
||||
@@ -463,7 +485,6 @@ static cRess_t FIO_createCResources(const char* dictFileName, int cLevel,
|
||||
}
|
||||
#else
|
||||
{ ZSTD_parameters params = ZSTD_getParams(cLevel, srcSize, dictBuffSize);
|
||||
params.fParams.contentSizeFlag = srcIsRegularFile;
|
||||
params.fParams.checksumFlag = g_checksumFlag;
|
||||
params.fParams.noDictIDFlag = !g_dictIDFlag;
|
||||
if (comprParams->windowLog) params.cParams.windowLog = comprParams->windowLog;
|
||||
@@ -753,6 +774,7 @@ static int FIO_compressFilename_internal(cRess_t ress,
|
||||
U64 readsize = 0;
|
||||
U64 compressedfilesize = 0;
|
||||
U64 const fileSize = UTIL_getFileSize(srcFileName);
|
||||
DISPLAYLEVEL(5, "%s: %u bytes \n", srcFileName, (U32)fileSize);
|
||||
|
||||
switch (g_compressionType) {
|
||||
case FIO_zstdCompression:
|
||||
@@ -792,11 +814,12 @@ static int FIO_compressFilename_internal(cRess_t ress,
|
||||
|
||||
/* init */
|
||||
#ifdef ZSTD_NEWAPI
|
||||
/* nothing, reset is implied */
|
||||
if (fileSize!=0) /* when src is stdin, fileSize==0, but is effectively unknown */
|
||||
ZSTD_CCtx_setPledgedSrcSize(ress.cctx, fileSize); /* note : fileSize==0 means "empty" */
|
||||
#elif defined(ZSTD_MULTITHREAD)
|
||||
CHECK( ZSTDMT_resetCStream(ress.cctx, fileSize) );
|
||||
CHECK( ZSTDMT_resetCStream(ress.cctx, fileSize) ); /* note : fileSize==0 means "unknown" */
|
||||
#else
|
||||
CHECK( ZSTD_resetCStream(ress.cctx, fileSize) );
|
||||
CHECK( ZSTD_resetCStream(ress.cctx, fileSize) ); /* note : fileSize==0 means "unknown" */
|
||||
#endif
|
||||
|
||||
/* Main compression loop */
|
||||
@@ -845,10 +868,10 @@ static int FIO_compressFilename_internal(cRess_t ress,
|
||||
|
||||
/* End of Frame */
|
||||
{ size_t result = 1;
|
||||
while (result!=0) { /* note : is there any possibility of endless loop ? */
|
||||
while (result != 0) {
|
||||
ZSTD_outBuffer outBuff = { ress.dstBuffer, ress.dstBufferSize, 0 };
|
||||
#ifdef ZSTD_NEWAPI
|
||||
ZSTD_inBuffer inBuff = { NULL, 0, 0};
|
||||
ZSTD_inBuffer inBuff = { NULL, 0, 0 };
|
||||
result = ZSTD_compress_generic(ress.cctx,
|
||||
&outBuff, &inBuff, ZSTD_e_end);
|
||||
#elif defined(ZSTD_MULTITHREAD)
|
||||
@@ -856,11 +879,14 @@ static int FIO_compressFilename_internal(cRess_t ress,
|
||||
#else
|
||||
result = ZSTD_endStream(ress.cctx, &outBuff);
|
||||
#endif
|
||||
if (ZSTD_isError(result))
|
||||
if (ZSTD_isError(result)) {
|
||||
EXM_THROW(26, "Compression error during frame end : %s",
|
||||
ZSTD_getErrorName(result));
|
||||
{ size_t const sizeCheck = fwrite(ress.dstBuffer, 1, outBuff.pos, dstFile);
|
||||
if (sizeCheck!=outBuff.pos) EXM_THROW(27, "Write error : cannot write frame end into %s", dstFileName); }
|
||||
}
|
||||
{ size_t const sizeCheck = fwrite(ress.dstBuffer, 1, outBuff.pos, dstFile);
|
||||
if (sizeCheck!=outBuff.pos)
|
||||
EXM_THROW(27, "Write error : cannot write frame end into %s", dstFileName);
|
||||
}
|
||||
compressedfilesize += outBuff.pos;
|
||||
}
|
||||
}
|
||||
@@ -924,6 +950,14 @@ static int FIO_compressFilename_dstFile(cRess_t ress,
|
||||
ress.dstFile = FIO_openDstFile(dstFileName);
|
||||
if (ress.dstFile==NULL) return 1; /* could not open dstFileName */
|
||||
|
||||
if (UTIL_isRegularFile(dstFileName)) {
|
||||
g_artefact = dstFileName;
|
||||
signal(SIGINT, INThandler);
|
||||
} else {
|
||||
g_artefact = NULL;
|
||||
}
|
||||
|
||||
|
||||
if (strcmp (srcFileName, stdinmark) && UTIL_getFileStat(srcFileName, &statbuf))
|
||||
stat_result = 1;
|
||||
result = FIO_compressFilename_srcFile(ress, dstFileName, srcFileName, compressionLevel);
|
||||
@@ -938,6 +972,9 @@ static int FIO_compressFilename_dstFile(cRess_t ress,
|
||||
}
|
||||
else if (strcmp (dstFileName, stdoutmark) && stat_result)
|
||||
UTIL_setFileStat(dstFileName, &statbuf);
|
||||
|
||||
signal(SIGINT, SIG_DFL);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -947,9 +984,8 @@ int FIO_compressFilename(const char* dstFileName, const char* srcFileName,
|
||||
{
|
||||
clock_t const start = clock();
|
||||
U64 const srcSize = UTIL_getFileSize(srcFileName);
|
||||
int const isRegularFile = UTIL_isRegularFile(srcFileName);
|
||||
|
||||
cRess_t const ress = FIO_createCResources(dictFileName, compressionLevel, srcSize, isRegularFile, comprParams);
|
||||
cRess_t const ress = FIO_createCResources(dictFileName, compressionLevel, srcSize, comprParams);
|
||||
int const result = FIO_compressFilename_dstFile(ress, dstFileName, srcFileName, compressionLevel);
|
||||
|
||||
double const seconds = (double)(clock() - start) / CLOCKS_PER_SEC;
|
||||
@@ -970,8 +1006,7 @@ int FIO_compressMultipleFilenames(const char** inFileNamesTable, unsigned nbFile
|
||||
char* dstFileName = (char*)malloc(FNSPACE);
|
||||
size_t const suffixSize = suffix ? strlen(suffix) : 0;
|
||||
U64 const srcSize = (nbFiles != 1) ? 0 : UTIL_getFileSize(inFileNamesTable[0]) ;
|
||||
int const isRegularFile = (nbFiles != 1) ? 0 : UTIL_isRegularFile(inFileNamesTable[0]);
|
||||
cRess_t ress = FIO_createCResources(dictFileName, compressionLevel, srcSize, isRegularFile, comprParams);
|
||||
cRess_t ress = FIO_createCResources(dictFileName, compressionLevel, srcSize, comprParams);
|
||||
|
||||
/* init */
|
||||
if (dstFileName==NULL)
|
||||
@@ -1036,7 +1071,7 @@ static dRess_t FIO_createDResources(const char* dictFileName)
|
||||
/* Allocation */
|
||||
ress.dctx = ZSTD_createDStream();
|
||||
if (ress.dctx==NULL) EXM_THROW(60, "Can't create ZSTD_DStream");
|
||||
ZSTD_setDStreamParameter(ress.dctx, DStream_p_maxWindowSize, g_memLimit);
|
||||
CHECK( ZSTD_setDStreamParameter(ress.dctx, DStream_p_maxWindowSize, g_memLimit) );
|
||||
ress.srcBufferSize = ZSTD_DStreamInSize();
|
||||
ress.srcBuffer = malloc(ress.srcBufferSize);
|
||||
ress.dstBufferSize = ZSTD_DStreamOutSize();
|
||||
@@ -1167,6 +1202,35 @@ static unsigned FIO_passThrough(FILE* foutput, FILE* finput, void* buffer, size_
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void FIO_zstdErrorHelp(dRess_t* ress, size_t ret, char const* srcFileName)
|
||||
{
|
||||
ZSTD_frameHeader header;
|
||||
/* No special help for these errors */
|
||||
if (ZSTD_getErrorCode(ret) != ZSTD_error_frameParameter_windowTooLarge)
|
||||
return;
|
||||
/* Try to decode the frame header */
|
||||
ret = ZSTD_getFrameHeader(&header, ress->srcBuffer, ress->srcBufferLoaded);
|
||||
if (ret == 0) {
|
||||
U32 const windowSize = (U32)header.windowSize;
|
||||
U32 const windowLog = BIT_highbit32(windowSize) + ((windowSize & (windowSize - 1)) != 0);
|
||||
U32 const windowMB = (windowSize >> 20) + (windowSize & ((1 MB) - 1));
|
||||
assert(header.windowSize <= (U64)((U32)-1));
|
||||
assert(g_memLimit > 0);
|
||||
DISPLAYLEVEL(1, "%s : Window size larger than maximum : %llu > %u\n",
|
||||
srcFileName, header.windowSize, g_memLimit);
|
||||
if (windowLog <= ZSTD_WINDOWLOG_MAX) {
|
||||
DISPLAYLEVEL(1, "%s : Use --long=%u or --memory=%uMB\n",
|
||||
srcFileName, windowLog, windowMB);
|
||||
return;
|
||||
}
|
||||
} else if (ZSTD_getErrorCode(ret) != ZSTD_error_frameParameter_windowTooLarge) {
|
||||
DISPLAYLEVEL(1, "%s : Error decoding frame header to read window size : %s\n",
|
||||
srcFileName, ZSTD_getErrorName(ret));
|
||||
return;
|
||||
}
|
||||
DISPLAYLEVEL(1, "%s : Window log larger than ZSTD_WINDOWLOG_MAX=%u not supported\n",
|
||||
srcFileName, ZSTD_WINDOWLOG_MAX);
|
||||
}
|
||||
|
||||
/** FIO_decompressFrame() :
|
||||
* @return : size of decoded zstd frame, or an error code
|
||||
@@ -1180,14 +1244,18 @@ unsigned long long FIO_decompressZstdFrame(dRess_t* ress,
|
||||
U64 frameSize = 0;
|
||||
U32 storedSkips = 0;
|
||||
|
||||
ZSTD_resetDStream(ress->dctx);
|
||||
if (strlen(srcFileName)>20) srcFileName += strlen(srcFileName)-20; /* display last 20 characters */
|
||||
size_t const srcFileLength = strlen(srcFileName);
|
||||
if (srcFileLength>20) srcFileName += srcFileLength-20; /* display last 20 characters only */
|
||||
|
||||
/* Header loading (optional, saves one loop) */
|
||||
{ size_t const toRead = 9;
|
||||
if (ress->srcBufferLoaded < toRead)
|
||||
ress->srcBufferLoaded += fread(((char*)ress->srcBuffer) + ress->srcBufferLoaded, 1, toRead - ress->srcBufferLoaded, finput);
|
||||
}
|
||||
ZSTD_resetDStream(ress->dctx);
|
||||
|
||||
/* Header loading : ensures ZSTD_getFrameHeader() will succeed */
|
||||
{ size_t const toDecode = ZSTD_FRAMEHEADERSIZE_MAX;
|
||||
if (ress->srcBufferLoaded < toDecode) {
|
||||
size_t const toRead = toDecode - ress->srcBufferLoaded;
|
||||
void* const startPosition = (char*)ress->srcBuffer + ress->srcBufferLoaded;
|
||||
ress->srcBufferLoaded += fread(startPosition, 1, toRead, finput);
|
||||
} }
|
||||
|
||||
/* Main decompression Loop */
|
||||
while (1) {
|
||||
@@ -1197,6 +1265,7 @@ unsigned long long FIO_decompressZstdFrame(dRess_t* ress,
|
||||
if (ZSTD_isError(readSizeHint)) {
|
||||
DISPLAYLEVEL(1, "%s : Decoding error (36) : %s \n",
|
||||
srcFileName, ZSTD_getErrorName(readSizeHint));
|
||||
FIO_zstdErrorHelp(ress, readSizeHint, srcFileName);
|
||||
return FIO_ERROR_FRAME_DECODING;
|
||||
}
|
||||
|
||||
@@ -1219,14 +1288,17 @@ unsigned long long FIO_decompressZstdFrame(dRess_t* ress,
|
||||
}
|
||||
|
||||
/* Fill input buffer */
|
||||
{ size_t const toRead = MIN(readSizeHint, ress->srcBufferSize); /* support large skippable frames */
|
||||
if (ress->srcBufferLoaded < toRead)
|
||||
ress->srcBufferLoaded += fread((char*)ress->srcBuffer + ress->srcBufferLoaded,
|
||||
1, toRead - ress->srcBufferLoaded, finput);
|
||||
if (ress->srcBufferLoaded < toRead) {
|
||||
DISPLAYLEVEL(1, "%s : Read error (39) : premature end \n",
|
||||
srcFileName);
|
||||
return FIO_ERROR_FRAME_DECODING;
|
||||
{ size_t const toDecode = MIN(readSizeHint, ress->srcBufferSize); /* support large skippable frames */
|
||||
if (ress->srcBufferLoaded < toDecode) {
|
||||
size_t const toRead = toDecode - ress->srcBufferLoaded; /* > 0 */
|
||||
void* const startPosition = (char*)ress->srcBuffer + ress->srcBufferLoaded;
|
||||
size_t const readSize = fread(startPosition, 1, toRead, finput);
|
||||
if (readSize==0) {
|
||||
DISPLAYLEVEL(1, "%s : Read error (39) : premature end \n",
|
||||
srcFileName);
|
||||
return FIO_ERROR_FRAME_DECODING;
|
||||
}
|
||||
ress->srcBufferLoaded += readSize;
|
||||
} } }
|
||||
|
||||
FIO_fwriteSparseEnd(ress->dstFile, storedSkips);
|
||||
@@ -1587,6 +1659,13 @@ static int FIO_decompressDstFile(dRess_t ress,
|
||||
ress.dstFile = FIO_openDstFile(dstFileName);
|
||||
if (ress.dstFile==0) return 1;
|
||||
|
||||
if (UTIL_isRegularFile(dstFileName)) {
|
||||
g_artefact = dstFileName;
|
||||
signal(SIGINT, INThandler);
|
||||
} else {
|
||||
g_artefact = NULL;
|
||||
}
|
||||
|
||||
if ( strcmp(srcFileName, stdinmark)
|
||||
&& UTIL_getFileStat(srcFileName, &statbuf) )
|
||||
stat_result = 1;
|
||||
@@ -1607,6 +1686,9 @@ static int FIO_decompressDstFile(dRess_t ress,
|
||||
&& stat_result ) /* file permissions correctly extracted from src */
|
||||
UTIL_setFileStat(dstFileName, &statbuf); /* transfer file permissions from src into dst */
|
||||
}
|
||||
|
||||
signal(SIGINT, SIG_DFL);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1698,12 +1780,14 @@ int FIO_decompressMultipleFilenames(const char** srcNamesTable, unsigned nbFiles
|
||||
***************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
U64 decompressedSize;
|
||||
U64 compressedSize;
|
||||
U64 windowSize;
|
||||
int numActualFrames;
|
||||
int numSkippableFrames;
|
||||
unsigned long long decompressedSize;
|
||||
int decompUnavailable;
|
||||
unsigned long long compressedSize;
|
||||
int usesCheck;
|
||||
U32 nbFiles;
|
||||
} fileInfo_t;
|
||||
|
||||
/** getFileInfo() :
|
||||
@@ -1720,14 +1804,16 @@ static int getFileInfo(fileInfo_t* info, const char* inFileName){
|
||||
DISPLAY("Error: could not open source file %s\n", inFileName);
|
||||
return 3;
|
||||
}
|
||||
info->compressedSize = (unsigned long long)UTIL_getFileSize(inFileName);
|
||||
info->compressedSize = UTIL_getFileSize(inFileName);
|
||||
|
||||
/* begin analyzing frame */
|
||||
for ( ; ; ) {
|
||||
BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX];
|
||||
size_t const numBytesRead = fread(headerBuffer, 1, sizeof(headerBuffer), srcFile);
|
||||
if (numBytesRead < ZSTD_frameHeaderSize_min) {
|
||||
if (feof(srcFile) && numBytesRead == 0 && info->compressedSize > 0) {
|
||||
if ( feof(srcFile)
|
||||
&& (numBytesRead == 0)
|
||||
&& (info->compressedSize > 0) ) {
|
||||
break;
|
||||
}
|
||||
else if (feof(srcFile)) {
|
||||
@@ -1744,12 +1830,19 @@ static int getFileInfo(fileInfo_t* info, const char* inFileName){
|
||||
{ U32 const magicNumber = MEM_readLE32(headerBuffer);
|
||||
/* Zstandard frame */
|
||||
if (magicNumber == ZSTD_MAGICNUMBER) {
|
||||
ZSTD_frameHeader header;
|
||||
U64 const frameContentSize = ZSTD_getFrameContentSize(headerBuffer, numBytesRead);
|
||||
if (frameContentSize == ZSTD_CONTENTSIZE_ERROR || frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN) {
|
||||
info->decompUnavailable = 1;
|
||||
} else {
|
||||
info->decompressedSize += frameContentSize;
|
||||
}
|
||||
if (ZSTD_getFrameHeader(&header, headerBuffer, numBytesRead) != 0) {
|
||||
DISPLAY("Error: could not decode frame header\n");
|
||||
detectError = 1;
|
||||
break;
|
||||
}
|
||||
info->windowSize = header.windowSize;
|
||||
/* move to the end of the frame header */
|
||||
{ size_t const headerSize = ZSTD_frameHeaderSize(headerBuffer, numBytesRead);
|
||||
if (ZSTD_isError(headerSize)) {
|
||||
@@ -1829,37 +1922,45 @@ static int getFileInfo(fileInfo_t* info, const char* inFileName){
|
||||
}
|
||||
} /* end analyzing frame */
|
||||
fclose(srcFile);
|
||||
info->nbFiles = 1;
|
||||
return detectError;
|
||||
}
|
||||
|
||||
static void displayInfo(const char* inFileName, fileInfo_t* info, int displayLevel){
|
||||
unsigned const unit = info->compressedSize < (1 MB) ? (1 KB) : (1 MB);
|
||||
const char* const unitStr = info->compressedSize < (1 MB) ? "KB" : "MB";
|
||||
double const windowSizeUnit = (double)info->windowSize / unit;
|
||||
double const compressedSizeUnit = (double)info->compressedSize / unit;
|
||||
double const decompressedSizeUnit = (double)info->decompressedSize / unit;
|
||||
double const ratio = (info->compressedSize == 0) ? 0 : ((double)info->decompressedSize)/info->compressedSize;
|
||||
const char* const checkString = (info->usesCheck ? "XXH64" : "None");
|
||||
if (displayLevel <= 2) {
|
||||
if (!info->decompUnavailable) {
|
||||
DISPLAYOUT("Skippable Non-Skippable Compressed Uncompressed Ratio Check Filename\n");
|
||||
DISPLAYOUT("%9d %13d %7.2f %2s %9.2f %2s %5.3f %5s %s\n",
|
||||
info->numSkippableFrames, info->numActualFrames,
|
||||
DISPLAYOUT("%6d %5d %7.2f %2s %9.2f %2s %5.3f %5s %s\n",
|
||||
info->numSkippableFrames + info->numActualFrames,
|
||||
info->numSkippableFrames,
|
||||
compressedSizeUnit, unitStr, decompressedSizeUnit, unitStr,
|
||||
ratio, checkString, inFileName);
|
||||
} else {
|
||||
DISPLAYOUT("Skippable Non-Skippable Compressed Check Filename\n");
|
||||
DISPLAYOUT("%9d %13d %7.2f MB %5s %s\n",
|
||||
info->numSkippableFrames, info->numActualFrames,
|
||||
compressedSizeUnit, checkString, inFileName);
|
||||
DISPLAYOUT("%6d %5d %7.2f %2s %5s %s\n",
|
||||
info->numSkippableFrames + info->numActualFrames,
|
||||
info->numSkippableFrames,
|
||||
compressedSizeUnit, unitStr,
|
||||
checkString, inFileName);
|
||||
}
|
||||
} else {
|
||||
DISPLAYOUT("# Zstandard Frames: %d\n", info->numActualFrames);
|
||||
DISPLAYOUT("# Skippable Frames: %d\n", info->numSkippableFrames);
|
||||
DISPLAYOUT("Window Size: %.2f %2s (%llu B)\n",
|
||||
windowSizeUnit, unitStr,
|
||||
(unsigned long long)info->windowSize);
|
||||
DISPLAYOUT("Compressed Size: %.2f %2s (%llu B)\n",
|
||||
compressedSizeUnit, unitStr, info->compressedSize);
|
||||
compressedSizeUnit, unitStr,
|
||||
(unsigned long long)info->compressedSize);
|
||||
if (!info->decompUnavailable) {
|
||||
DISPLAYOUT("Decompressed Size: %.2f %2s (%llu B)\n",
|
||||
decompressedSizeUnit, unitStr, info->decompressedSize);
|
||||
decompressedSizeUnit, unitStr,
|
||||
(unsigned long long)info->decompressedSize);
|
||||
DISPLAYOUT("Ratio: %.4f\n", ratio);
|
||||
}
|
||||
DISPLAYOUT("Check: %s\n", checkString);
|
||||
@@ -1867,33 +1968,40 @@ static void displayInfo(const char* inFileName, fileInfo_t* info, int displayLev
|
||||
}
|
||||
}
|
||||
|
||||
static fileInfo_t FIO_addFInfo(fileInfo_t fi1, fileInfo_t fi2)
|
||||
{
|
||||
fileInfo_t total;
|
||||
total.numActualFrames = fi1.numActualFrames + fi2.numActualFrames;
|
||||
total.numSkippableFrames = fi1.numSkippableFrames + fi2.numSkippableFrames;
|
||||
total.compressedSize = fi1.compressedSize + fi2.compressedSize;
|
||||
total.decompressedSize = fi1.decompressedSize + fi2.decompressedSize;
|
||||
total.decompUnavailable = fi1.decompUnavailable | fi2.decompUnavailable;
|
||||
total.usesCheck = fi1.usesCheck & fi2.usesCheck;
|
||||
total.nbFiles = fi1.nbFiles + fi2.nbFiles;
|
||||
return total;
|
||||
}
|
||||
|
||||
static int FIO_listFile(const char* inFileName, int displayLevel, unsigned fileNo, unsigned numFiles){
|
||||
static int FIO_listFile(fileInfo_t* total, const char* inFileName, int displayLevel){
|
||||
/* initialize info to avoid warnings */
|
||||
fileInfo_t info;
|
||||
memset(&info, 0, sizeof(info));
|
||||
DISPLAYOUT("%s (%u/%u):\n", inFileName, fileNo, numFiles);
|
||||
{
|
||||
int const error = getFileInfo(&info, inFileName);
|
||||
{ int const error = getFileInfo(&info, inFileName);
|
||||
if (error == 1) {
|
||||
/* display error, but provide output */
|
||||
DISPLAY("An error occurred with getting file info\n");
|
||||
DISPLAY("An error occurred while getting file info \n");
|
||||
}
|
||||
else if (error == 2) {
|
||||
DISPLAYOUT("File %s not compressed with zstd\n", inFileName);
|
||||
if (displayLevel > 2) {
|
||||
DISPLAYOUT("\n");
|
||||
}
|
||||
DISPLAYOUT("File %s not compressed by zstd \n", inFileName);
|
||||
if (displayLevel > 2) DISPLAYOUT("\n");
|
||||
return 1;
|
||||
}
|
||||
else if (error == 3) {
|
||||
/* error occurred with opening the file */
|
||||
if (displayLevel > 2) {
|
||||
DISPLAYOUT("\n");
|
||||
}
|
||||
/* error occurred while opening the file */
|
||||
if (displayLevel > 2) DISPLAYOUT("\n");
|
||||
return 1;
|
||||
}
|
||||
displayInfo(inFileName, &info, displayLevel);
|
||||
*total = FIO_addFInfo(*total, info);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
@@ -1903,15 +2011,38 @@ int FIO_listMultipleFiles(unsigned numFiles, const char** filenameTable, int dis
|
||||
DISPLAYOUT("No files given\n");
|
||||
return 0;
|
||||
}
|
||||
DISPLAYOUT("===========================================\n");
|
||||
DISPLAYOUT("Printing information about compressed files\n");
|
||||
DISPLAYOUT("===========================================\n");
|
||||
DISPLAYOUT("Number of files listed: %u\n", numFiles);
|
||||
{
|
||||
int error = 0;
|
||||
if (displayLevel <= 2) {
|
||||
DISPLAYOUT("Frames Skips Compressed Uncompressed Ratio Check Filename\n");
|
||||
}
|
||||
{ int error = 0;
|
||||
unsigned u;
|
||||
fileInfo_t total;
|
||||
memset(&total, 0, sizeof(total));
|
||||
total.usesCheck = 1;
|
||||
for (u=0; u<numFiles;u++) {
|
||||
error |= FIO_listFile(filenameTable[u], displayLevel, u+1, numFiles);
|
||||
error |= FIO_listFile(&total, filenameTable[u], displayLevel);
|
||||
}
|
||||
if (numFiles > 1 && displayLevel <= 2) {
|
||||
unsigned const unit = total.compressedSize < (1 MB) ? (1 KB) : (1 MB);
|
||||
const char* const unitStr = total.compressedSize < (1 MB) ? "KB" : "MB";
|
||||
double const compressedSizeUnit = (double)total.compressedSize / unit;
|
||||
double const decompressedSizeUnit = (double)total.decompressedSize / unit;
|
||||
double const ratio = (total.compressedSize == 0) ? 0 : ((double)total.decompressedSize)/total.compressedSize;
|
||||
const char* const checkString = (total.usesCheck ? "XXH64" : "");
|
||||
DISPLAYOUT("----------------------------------------------------------------- \n");
|
||||
if (total.decompUnavailable) {
|
||||
DISPLAYOUT("%6d %5d %7.2f %2s %5s %u files\n",
|
||||
total.numSkippableFrames + total.numActualFrames,
|
||||
total.numSkippableFrames,
|
||||
compressedSizeUnit, unitStr,
|
||||
checkString, total.nbFiles);
|
||||
} else {
|
||||
DISPLAYOUT("%6d %5d %7.2f %2s %9.2f %2s %5.3f %5s %u files\n",
|
||||
total.numSkippableFrames + total.numActualFrames,
|
||||
total.numSkippableFrames,
|
||||
compressedSizeUnit, unitStr, decompressedSizeUnit, unitStr,
|
||||
ratio, checkString, total.nbFiles);
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
+20
-6
@@ -60,11 +60,11 @@ In most places where an integer argument is expected, an optional suffix is supp
|
||||
.
|
||||
.TP
|
||||
\fBKiB\fR
|
||||
Multiply the integer by 1,024 (2^10)\. \fBKi\fR, \fBK\fR, and \fBKB\fR are accepted as synonyms for \fBKiB\fR\.
|
||||
Multiply the integer by 1,024 (2\e \fBKi\fR, \fBK\fR, and \fBKB\fR are accepted as synonyms for \fBKiB\fR\.
|
||||
.
|
||||
.TP
|
||||
\fBMiB\fR
|
||||
Multiply the integer by 1,048,576 (2^20)\. \fBMi\fR, \fBM\fR, and \fBMB\fR are accepted as synonyms for \fBMiB\fR\.
|
||||
Multiply the integer by 1,048,576 (2\e \fBMi\fR, \fBM\fR, and \fBMB\fR are accepted as synonyms for \fBMiB\fR\.
|
||||
.
|
||||
.SS "Operation mode"
|
||||
If multiple operation mode options are given, the last one takes effect\.
|
||||
@@ -104,8 +104,11 @@ Display information related to a zstd compressed file, such as size, ratio, and
|
||||
unlocks high compression levels 20+ (maximum 22), using a lot more memory\. Note that decompression will also require more memory when using these levels\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-long\fR
|
||||
enables long distance matching\. This increases the window size (\fBwindowLog\fR) and memory usage for both the compressor and decompressor\. This setting is designed to improve the compression ratio for files with long matches at a large distance (up to the maximum window size, 128 MiB)\.
|
||||
\fB\-\-long[=#]\fR
|
||||
enables long distance matching with \fB#\fR \fBwindowLog\fR, if not \fB#\fR is not present it defaults to \fB27\fR\. This increases the window size (\fBwindowLog\fR) and memory usage for both the compressor and decompressor\. This setting is designed to improve the compression ratio for files with long matches at a large distance\.
|
||||
.
|
||||
.IP
|
||||
Note: If \fBwindowLog\fR is set to larger than 27, \fB\-\-long=windowLog\fR or \fB\-\-memory=windowSize\fR needs to be passed to the decompressor\.
|
||||
.
|
||||
.TP
|
||||
\fB\-T#\fR, \fB\-\-threads=#\fR
|
||||
@@ -148,6 +151,10 @@ keep source file(s) after successful compression or decompression\. This is the
|
||||
operate recursively on dictionaries
|
||||
.
|
||||
.TP
|
||||
\fB\-\-format=FORMAT\fR
|
||||
compress and decompress in other formats\. If compiled with support, zstd can compress to or decompress from other compression algorithm formats\. Possibly available options are \fBgzip\fR, \fBxz\fR, \fBlzma\fR, and \fBlz4\fR\.
|
||||
.
|
||||
.TP
|
||||
\fB\-h\fR/\fB\-H\fR, \fB\-\-help\fR
|
||||
display help/long help and exit
|
||||
.
|
||||
@@ -190,6 +197,10 @@ Dictionary saved into \fBfile\fR (default name: dictionary)\.
|
||||
Limit dictionary to specified size (default: 112640)\.
|
||||
.
|
||||
.TP
|
||||
\fB\-B#\fR
|
||||
Split input files in blocks of size # (default: no split)
|
||||
.
|
||||
.TP
|
||||
\fB\-\-dictID=#\fR
|
||||
A dictionary ID is a locally unique ID that a decoder can use to verify it is using the right dictionary\. By default, zstd will create a 4\-bytes random number ID\. It\'s possible to give a precise number instead\. Short numbers have an advantage : an ID < 256 will only need 1 byte in the compressed frame header, and an ID < 65536 will only need 2 bytes\. This compares favorably to 4 bytes default\. However, it\'s up to the dictionary manager to not assign twice the same ID to 2 different dictionaries\.
|
||||
.
|
||||
@@ -267,7 +278,10 @@ There are 8 strategies numbered from 1 to 8, from faster to stronger: 1=ZSTD_fas
|
||||
Specify the maximum number of bits for a match distance\.
|
||||
.
|
||||
.IP
|
||||
The higher number of increases the chance to find a match which usually improves compression ratio\. It also increases memory requirements for the compressor and decompressor\. The minimum \fIwlog\fR is 10 (1 KiB) and the maximum is 27 (128 MiB)\.
|
||||
The higher number of increases the chance to find a match which usually improves compression ratio\. It also increases memory requirements for the compressor and decompressor\. The minimum \fIwlog\fR is 10 (1 KiB) and the maximum is 30 (1 GiB) on 32\-bit platforms and 31 (2 GiB) on 64\-bit platforms\.
|
||||
.
|
||||
.IP
|
||||
Note: If \fBwindowLog\fR is set to larger than 27, \fB\-\-long=windowLog\fR or \fB\-\-memory=windowSize\fR needs to be passed to the decompressor\.
|
||||
.
|
||||
.TP
|
||||
\fBhashLog\fR=\fIhlog\fR, \fBhlog\fR=\fIhlog\fR
|
||||
@@ -340,7 +354,7 @@ Bigger hash tables usually improve compression ratio at the expense of more memo
|
||||
The minimum \fIldmhlog\fR is 6 and the maximum is 26 (default: 20)\.
|
||||
.
|
||||
.TP
|
||||
\fBldmSearchLength\fR=\fIldmslen\fR, \fBldmSlen\fR=\fIldmslen\fR
|
||||
\fBldmSearchLength\fR=\fIldmslen\fR, \fBldmslen\fR=\fIldmslen\fR
|
||||
Specify the minimum searched length of a match for long distance matching\.
|
||||
.
|
||||
.IP
|
||||
|
||||
+18
-6
@@ -105,12 +105,16 @@ the last one takes effect.
|
||||
* `--ultra`:
|
||||
unlocks high compression levels 20+ (maximum 22), using a lot more memory.
|
||||
Note that decompression will also require more memory when using these levels.
|
||||
* `--long`:
|
||||
enables long distance matching.
|
||||
* `--long[=#]`:
|
||||
enables long distance matching with `#` `windowLog`, if not `#` is not
|
||||
present it defaults to `27`.
|
||||
This increases the window size (`windowLog`) and memory usage for both the
|
||||
compressor and decompressor. This setting is designed to improve the
|
||||
compression ratio for files with long matches at a large distance
|
||||
(up to the maximum window size, 128 MiB).
|
||||
compressor and decompressor.
|
||||
This setting is designed to improve the compression ratio for files with
|
||||
long matches at a large distance.
|
||||
|
||||
Note: If `windowLog` is set to larger than 27, `--long=windowLog` or
|
||||
`--memory=windowSize` needs to be passed to the decompressor.
|
||||
* `-T#`, `--threads=#`:
|
||||
Compress using `#` threads (default: 1).
|
||||
If `#` is 0, attempt to detect and use the number of physical CPU cores.
|
||||
@@ -143,6 +147,10 @@ the last one takes effect.
|
||||
This is the default behavior.
|
||||
* `-r`:
|
||||
operate recursively on dictionaries
|
||||
* `--format=FORMAT`:
|
||||
compress and decompress in other formats. If compiled with
|
||||
support, zstd can compress to or decompress from other compression algorithm
|
||||
formats. Possibly available options are `gzip`, `xz`, `lzma`, and `lz4`.
|
||||
* `-h`/`-H`, `--help`:
|
||||
display help/long help and exit
|
||||
* `-V`, `--version`:
|
||||
@@ -275,7 +283,11 @@ The list of available _options_:
|
||||
The higher number of increases the chance to find a match which usually
|
||||
improves compression ratio.
|
||||
It also increases memory requirements for the compressor and decompressor.
|
||||
The minimum _wlog_ is 10 (1 KiB) and the maximum is 27 (128 MiB).
|
||||
The minimum _wlog_ is 10 (1 KiB) and the maximum is 30 (1 GiB) on 32-bit
|
||||
platforms and 31 (2 GiB) on 64-bit platforms.
|
||||
|
||||
Note: If `windowLog` is set to larger than 27, `--long=windowLog` or
|
||||
`--memory=windowSize` needs to be passed to the decompressor.
|
||||
|
||||
- `hashLog`=_hlog_, `hlog`=_hlog_:
|
||||
Specify the maximum number of bits for a hash table.
|
||||
|
||||
+30
-2
@@ -61,6 +61,8 @@
|
||||
#define ZSTD_UNLZMA "unlzma"
|
||||
#define ZSTD_XZ "xz"
|
||||
#define ZSTD_UNXZ "unxz"
|
||||
#define ZSTD_LZ4 "lz4"
|
||||
#define ZSTD_UNLZ4 "unlz4"
|
||||
|
||||
#define KB *(1 <<10)
|
||||
#define MB *(1 <<20)
|
||||
@@ -72,6 +74,7 @@ static const char* g_defaultDictName = "dictionary";
|
||||
static const unsigned g_defaultMaxDictSize = 110 KB;
|
||||
static const int g_defaultDictCLevel = 3;
|
||||
static const unsigned g_defaultSelectivityLevel = 9;
|
||||
static const unsigned g_defaultMaxWindowLog = 27;
|
||||
#define OVERLAP_LOG_DEFAULT 9999
|
||||
#define LDM_PARAM_DEFAULT 9999 /* Default for parameters where 0 is valid */
|
||||
static U32 g_overlapLog = OVERLAP_LOG_DEFAULT;
|
||||
@@ -129,7 +132,7 @@ static int usage_advanced(const char* programName)
|
||||
DISPLAY( " -l : print information about zstd compressed files \n");
|
||||
#ifndef ZSTD_NOCOMPRESS
|
||||
DISPLAY( "--ultra : enable levels beyond %i, up to %i (requires more memory)\n", ZSTDCLI_CLEVEL_MAX, ZSTD_maxCLevel());
|
||||
DISPLAY( "--long : enable long distance matching (requires more memory)\n");
|
||||
DISPLAY( "--long[=#] : enable long distance matching with given window log (default : %u)\n", g_defaultMaxWindowLog);
|
||||
#ifdef ZSTD_MULTITHREAD
|
||||
DISPLAY( " -T# : use # threads for compression (default:1) \n");
|
||||
DISPLAY( " -B# : select size of each job (default:0==automatic) \n");
|
||||
@@ -403,6 +406,7 @@ int main(int argCount, const char* argv[])
|
||||
int cover = 1;
|
||||
#endif
|
||||
|
||||
|
||||
/* init */
|
||||
(void)recursive; (void)cLevelLast; /* not used when ZSTD_NOBENCH set */
|
||||
(void)dictCLevel; (void)dictSelect; (void)dictID; (void)maxDictSize; /* not used when ZSTD_NODICT set */
|
||||
@@ -425,6 +429,8 @@ int main(int argCount, const char* argv[])
|
||||
if (exeNameMatch(programName, ZSTD_UNLZMA)) { operation=zom_decompress; FIO_setCompressionType(FIO_lzmaCompression); FIO_setRemoveSrcFile(1); } /* behave like unlzma */
|
||||
if (exeNameMatch(programName, ZSTD_XZ)) { suffix = XZ_EXTENSION; FIO_setCompressionType(FIO_xzCompression); FIO_setRemoveSrcFile(1); } /* behave like xz */
|
||||
if (exeNameMatch(programName, ZSTD_UNXZ)) { operation=zom_decompress; FIO_setCompressionType(FIO_xzCompression); FIO_setRemoveSrcFile(1); } /* behave like unxz */
|
||||
if (exeNameMatch(programName, ZSTD_LZ4)) { suffix = LZ4_EXTENSION; FIO_setCompressionType(FIO_lz4Compression); FIO_setRemoveSrcFile(1); } /* behave like xz */
|
||||
if (exeNameMatch(programName, ZSTD_UNLZ4)) { operation=zom_decompress; FIO_setCompressionType(FIO_lz4Compression); FIO_setRemoveSrcFile(1); } /* behave like unxz */
|
||||
memset(&compressionParams, 0, sizeof(compressionParams));
|
||||
|
||||
/* command switches */
|
||||
@@ -459,7 +465,6 @@ int main(int argCount, const char* argv[])
|
||||
if (!strcmp(argument, "--quiet")) { g_displayLevel--; continue; }
|
||||
if (!strcmp(argument, "--stdout")) { forceStdout=1; outFileName=stdoutmark; g_displayLevel-=(g_displayLevel==2); continue; }
|
||||
if (!strcmp(argument, "--ultra")) { ultra=1; continue; }
|
||||
if (!strcmp(argument, "--long")) { ldmFlag = 1; continue; }
|
||||
if (!strcmp(argument, "--check")) { FIO_setChecksumFlag(2); continue; }
|
||||
if (!strcmp(argument, "--no-check")) { FIO_setChecksumFlag(0); continue; }
|
||||
if (!strcmp(argument, "--sparse")) { FIO_setSparseWrite(2); continue; }
|
||||
@@ -514,6 +519,22 @@ int main(int argCount, const char* argv[])
|
||||
if (longCommandWArg(&argument, "--maxdict=")) { maxDictSize = readU32FromChar(&argument); continue; }
|
||||
if (longCommandWArg(&argument, "--dictID=")) { dictID = readU32FromChar(&argument); continue; }
|
||||
if (longCommandWArg(&argument, "--zstd=")) { if (!parseCompressionParameters(argument, &compressionParams)) CLEAN_RETURN(badusage(programName)); continue; }
|
||||
if (longCommandWArg(&argument, "--long")) {
|
||||
unsigned ldmWindowLog = 0;
|
||||
ldmFlag = 1;
|
||||
/* Parse optional window log */
|
||||
if (*argument == '=') {
|
||||
++argument;
|
||||
ldmWindowLog = readU32FromChar(&argument);
|
||||
} else if (*argument != 0) {
|
||||
/* Invalid character following --long */
|
||||
CLEAN_RETURN(badusage(programName));
|
||||
}
|
||||
/* Only set windowLog if not already set by --zstd */
|
||||
if (compressionParams.windowLog == 0)
|
||||
compressionParams.windowLog = ldmWindowLog;
|
||||
continue;
|
||||
}
|
||||
/* fall-through, will trigger bad_usage() later on */
|
||||
}
|
||||
|
||||
@@ -830,6 +851,13 @@ int main(int argCount, const char* argv[])
|
||||
#endif
|
||||
} else { /* decompression or test */
|
||||
#ifndef ZSTD_NODECOMPRESS
|
||||
if (memLimit == 0) {
|
||||
if (compressionParams.windowLog == 0)
|
||||
memLimit = (U32)1 << g_defaultMaxWindowLog;
|
||||
else {
|
||||
memLimit = (U32)1 << (compressionParams.windowLog & 31);
|
||||
}
|
||||
}
|
||||
FIO_setMemLimit(memLimit);
|
||||
if (filenameIdx==1 && outFileName)
|
||||
operationResult = FIO_decompressFilename(outFileName, filenameTable[0], dictFileName);
|
||||
|
||||
+52
-19
@@ -23,18 +23,18 @@ PRGDIR = ../programs
|
||||
PYTHON ?= python3
|
||||
TESTARTEFACT := versionsTest namespaceTest
|
||||
|
||||
DEBUGLEVEL= 1
|
||||
DEBUGFLAGS= -g -DZSTD_DEBUG=$(DEBUGLEVEL)
|
||||
CPPFLAGS += -I$(ZSTDDIR) -I$(ZSTDDIR)/common -I$(ZSTDDIR)/compress \
|
||||
-I$(ZSTDDIR)/dictBuilder -I$(ZSTDDIR)/deprecated -I$(PRGDIR)
|
||||
CFLAGS ?= -O3
|
||||
CFLAGS += -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \
|
||||
-Wstrict-aliasing=1 -Wswitch-enum -Wdeclaration-after-statement \
|
||||
-Wstrict-prototypes -Wundef -Wformat-security \
|
||||
-Wvla -Wformat=2 -Winit-self -Wfloat-equal -Wwrite-strings \
|
||||
-Wredundant-decls
|
||||
CFLAGS += $(DEBUGFLAGS) $(MOREFLAGS)
|
||||
FLAGS = $(CPPFLAGS) $(CFLAGS) $(LDFLAGS)
|
||||
DEBUGLEVEL ?= 1
|
||||
DEBUGFLAGS = -g -DZSTD_DEBUG=$(DEBUGLEVEL)
|
||||
CPPFLAGS += -I$(ZSTDDIR) -I$(ZSTDDIR)/common -I$(ZSTDDIR)/compress \
|
||||
-I$(ZSTDDIR)/dictBuilder -I$(ZSTDDIR)/deprecated -I$(PRGDIR)
|
||||
CFLAGS ?= -O3
|
||||
CFLAGS += -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \
|
||||
-Wstrict-aliasing=1 -Wswitch-enum -Wdeclaration-after-statement \
|
||||
-Wstrict-prototypes -Wundef -Wformat-security \
|
||||
-Wvla -Wformat=2 -Winit-self -Wfloat-equal -Wwrite-strings \
|
||||
-Wredundant-decls
|
||||
CFLAGS += $(DEBUGFLAGS) $(MOREFLAGS)
|
||||
FLAGS = $(CPPFLAGS) $(CFLAGS) $(LDFLAGS)
|
||||
|
||||
|
||||
ZSTDCOMMON_FILES := $(ZSTDDIR)/common/*.c
|
||||
@@ -58,8 +58,8 @@ endif
|
||||
MULTITHREAD = $(MULTITHREAD_CPP) $(MULTITHREAD_LD)
|
||||
|
||||
VOID = /dev/null
|
||||
ZSTREAM_TESTTIME ?= -T2mn
|
||||
FUZZERTEST ?= -T5mn
|
||||
ZSTREAM_TESTTIME ?= -T90s
|
||||
FUZZERTEST ?= -T200s
|
||||
ZSTDRTTEST = --test-large-data
|
||||
DECODECORPUS_TESTTIME ?= -T30
|
||||
|
||||
@@ -208,7 +208,7 @@ clean:
|
||||
zstreamtest$(EXT) zstreamtest32$(EXT) \
|
||||
datagen$(EXT) paramgrill$(EXT) roundTripCrash$(EXT) longmatch$(EXT) \
|
||||
symbols$(EXT) invalidDictionaries$(EXT) legacy$(EXT) poolTests$(EXT) \
|
||||
decodecorpus$(EXT)
|
||||
decodecorpus$(EXT)
|
||||
@echo Cleaning completed
|
||||
|
||||
|
||||
@@ -241,7 +241,7 @@ endif
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
#make tests validated only for MSYS, Linux, OSX, BSD, Hurd and Solaris targets
|
||||
# make tests validated only for below targets
|
||||
#-----------------------------------------------------------------------------
|
||||
ifneq (,$(filter $(HOST_OS),MSYS POSIX))
|
||||
|
||||
@@ -316,9 +316,9 @@ test-zbuff32: zbufftest32
|
||||
|
||||
test-zstream: zstreamtest
|
||||
$(QEMU_SYS) ./zstreamtest $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS)
|
||||
$(QEMU_SYS) ./zstreamtest --mt $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS)
|
||||
$(QEMU_SYS) ./zstreamtest --newapi $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS)
|
||||
$(QEMU_SYS) ./zstreamtest --opaqueapi $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS)
|
||||
$(QEMU_SYS) ./zstreamtest --mt -t1 $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS)
|
||||
$(QEMU_SYS) ./zstreamtest --newapi -t1 $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS)
|
||||
$(QEMU_SYS) ./zstreamtest --opaqueapi -t1 $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS)
|
||||
|
||||
test-zstream32: zstreamtest32
|
||||
$(QEMU_SYS) ./zstreamtest32 $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS)
|
||||
@@ -374,4 +374,37 @@ test-decodecorpus-cli: decodecorpus
|
||||
test-pool: poolTests
|
||||
$(QEMU_SYS) ./poolTests
|
||||
|
||||
test-lz4: ZSTD = LD_LIBRARY_PATH=/usr/local/lib $(PRGDIR)/zstd
|
||||
test-lz4: ZSTD_LZ4 = LD_LIBRARY_PATH=/usr/local/lib ./lz4
|
||||
test-lz4: ZSTD_UNLZ4 = LD_LIBRARY_PATH=/usr/local/lib ./unlz4
|
||||
test-lz4: zstd decodecorpus
|
||||
ln -s $(PRGDIR)/zstd lz4
|
||||
ln -s $(PRGDIR)/zstd unlz4
|
||||
|
||||
./decodecorpus -ptmp
|
||||
# lz4 -> zstd
|
||||
lz4 < tmp | \
|
||||
$(ZSTD) -d | \
|
||||
cmp - tmp
|
||||
lz4 < tmp | \
|
||||
$(ZSTD_UNLZ4) | \
|
||||
cmp - tmp
|
||||
# zstd -> lz4
|
||||
$(ZSTD) --format=lz4 < tmp | \
|
||||
lz4 -d | \
|
||||
cmp - tmp
|
||||
$(ZSTD_LZ4) < tmp | \
|
||||
lz4 -d | \
|
||||
cmp - tmp
|
||||
# zstd -> zstd
|
||||
$(ZSTD) --format=lz4 < tmp | \
|
||||
$(ZSTD) -d | \
|
||||
cmp - tmp
|
||||
# zstd -> zstd
|
||||
$(ZSTD) < tmp | \
|
||||
$(ZSTD) -d | \
|
||||
cmp - tmp
|
||||
|
||||
rm tmp lz4 unlz4
|
||||
|
||||
endif
|
||||
|
||||
+64
-94
@@ -45,7 +45,7 @@
|
||||
**************************************/
|
||||
#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
|
||||
#define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); }
|
||||
static U32 g_displayLevel = 0;
|
||||
static U32 g_displayLevel = 2;
|
||||
|
||||
#define DISPLAYUPDATE(...) \
|
||||
do { \
|
||||
@@ -174,21 +174,19 @@ const char *BLOCK_TYPES[] = {"raw", "rle", "compressed"};
|
||||
#define MAX_DECOMPRESSED_SIZE (1ULL << MAX_DECOMPRESSED_SIZE_LOG)
|
||||
|
||||
#define MAX_WINDOW_LOG 22 /* Recommended support is 8MB, so limit to 4MB + mantissa */
|
||||
#define MAX_BLOCK_SIZE_LOG 17
|
||||
#define MAX_BLOCK_SIZE (1ULL << MAX_BLOCK_SIZE_LOG) /* 128 KB */
|
||||
|
||||
#define MIN_SEQ_LEN (3)
|
||||
#define MAX_NB_SEQ ((MAX_BLOCK_SIZE + MIN_SEQ_LEN - 1) / MIN_SEQ_LEN)
|
||||
#define MAX_NB_SEQ ((ZSTD_BLOCKSIZE_MAX + MIN_SEQ_LEN - 1) / MIN_SEQ_LEN)
|
||||
|
||||
BYTE CONTENT_BUFFER[MAX_DECOMPRESSED_SIZE];
|
||||
BYTE FRAME_BUFFER[MAX_DECOMPRESSED_SIZE * 2];
|
||||
BYTE LITERAL_BUFFER[MAX_BLOCK_SIZE];
|
||||
BYTE LITERAL_BUFFER[ZSTD_BLOCKSIZE_MAX];
|
||||
|
||||
seqDef SEQUENCE_BUFFER[MAX_NB_SEQ];
|
||||
BYTE SEQUENCE_LITERAL_BUFFER[MAX_BLOCK_SIZE]; /* storeSeq expects a place to copy literals to */
|
||||
BYTE SEQUENCE_LLCODE[MAX_BLOCK_SIZE];
|
||||
BYTE SEQUENCE_MLCODE[MAX_BLOCK_SIZE];
|
||||
BYTE SEQUENCE_OFCODE[MAX_BLOCK_SIZE];
|
||||
BYTE SEQUENCE_LITERAL_BUFFER[ZSTD_BLOCKSIZE_MAX]; /* storeSeq expects a place to copy literals to */
|
||||
BYTE SEQUENCE_LLCODE[ZSTD_BLOCKSIZE_MAX];
|
||||
BYTE SEQUENCE_MLCODE[ZSTD_BLOCKSIZE_MAX];
|
||||
BYTE SEQUENCE_OFCODE[ZSTD_BLOCKSIZE_MAX];
|
||||
|
||||
unsigned WKSP[1024];
|
||||
|
||||
@@ -249,7 +247,7 @@ typedef enum {
|
||||
* Global variables (set from command line)
|
||||
*********************************************************/
|
||||
U32 g_maxDecompressedSizeLog = MAX_DECOMPRESSED_SIZE_LOG; /* <= 20 */
|
||||
U32 g_maxBlockSize = MAX_BLOCK_SIZE; /* <= 128 KB */
|
||||
U32 g_maxBlockSize = ZSTD_BLOCKSIZE_MAX; /* <= 128 KB */
|
||||
|
||||
/*-*******************************************************
|
||||
* Generator Functions
|
||||
@@ -356,10 +354,10 @@ static void writeFrameHeader(U32* seed, frame_t* frame, dictInfo info)
|
||||
}
|
||||
}
|
||||
|
||||
DISPLAYLEVEL(2, " frame content size:\t%u\n", (U32)fh.contentSize);
|
||||
DISPLAYLEVEL(2, " frame window size:\t%u\n", fh.windowSize);
|
||||
DISPLAYLEVEL(2, " content size flag:\t%d\n", contentSizeFlag);
|
||||
DISPLAYLEVEL(2, " single segment flag:\t%d\n", singleSegment);
|
||||
DISPLAYLEVEL(3, " frame content size:\t%u\n", (U32)fh.contentSize);
|
||||
DISPLAYLEVEL(3, " frame window size:\t%u\n", fh.windowSize);
|
||||
DISPLAYLEVEL(3, " content size flag:\t%d\n", contentSizeFlag);
|
||||
DISPLAYLEVEL(3, " single segment flag:\t%d\n", singleSegment);
|
||||
|
||||
frame->data = op + pos;
|
||||
frame->header = fh;
|
||||
@@ -881,7 +879,7 @@ static size_t writeSequences(U32* seed, frame_t* frame, seqStore_t* seqStorePtr,
|
||||
frame->stats.offsetSymbolSet, 28)) {
|
||||
Offtype = set_repeat;
|
||||
} else if (!(RAND(seed) & 3)) {
|
||||
FSE_buildCTable_wksp(CTable_OffsetBits, OF_defaultNorm, MaxOff, OF_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
|
||||
FSE_buildCTable_wksp(CTable_OffsetBits, OF_defaultNorm, DefaultMaxOff, OF_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
|
||||
Offtype = set_basic;
|
||||
} else {
|
||||
size_t nbSeq_1 = nbSeq;
|
||||
@@ -1034,9 +1032,9 @@ static void writeBlock(U32* seed, frame_t* frame, size_t contentSize,
|
||||
BYTE *const header = (BYTE*)frame->data;
|
||||
BYTE *op = header + 3;
|
||||
|
||||
DISPLAYLEVEL(3, " block:\n");
|
||||
DISPLAYLEVEL(3, " block content size: %u\n", (U32)contentSize);
|
||||
DISPLAYLEVEL(3, " last block: %s\n", lastBlock ? "yes" : "no");
|
||||
DISPLAYLEVEL(4, " block:\n");
|
||||
DISPLAYLEVEL(4, " block content size: %u\n", (U32)contentSize);
|
||||
DISPLAYLEVEL(4, " last block: %s\n", lastBlock ? "yes" : "no");
|
||||
|
||||
if (blockTypeDesc == 0) {
|
||||
/* Raw data frame */
|
||||
@@ -1066,7 +1064,7 @@ static void writeBlock(U32* seed, frame_t* frame, size_t contentSize,
|
||||
|
||||
frame->data = op;
|
||||
compressedSize = writeCompressedBlock(seed, frame, contentSize, info);
|
||||
if (compressedSize > contentSize) {
|
||||
if (compressedSize >= contentSize) { /* compressed block must be strictly smaller than uncompressed one */
|
||||
blockType = 0;
|
||||
memcpy(op, frame->src, contentSize);
|
||||
|
||||
@@ -1082,8 +1080,8 @@ static void writeBlock(U32* seed, frame_t* frame, size_t contentSize,
|
||||
}
|
||||
frame->src = (BYTE*)frame->src + contentSize;
|
||||
|
||||
DISPLAYLEVEL(3, " block type: %s\n", BLOCK_TYPES[blockType]);
|
||||
DISPLAYLEVEL(3, " block size field: %u\n", (U32)blockSize);
|
||||
DISPLAYLEVEL(4, " block type: %s\n", BLOCK_TYPES[blockType]);
|
||||
DISPLAYLEVEL(4, " block size field: %u\n", (U32)blockSize);
|
||||
|
||||
header[0] = (BYTE) ((lastBlock | (blockType << 1) | (blockSize << 3)) & 0xff);
|
||||
MEM_writeLE16(header + 1, (U16) (blockSize >> 5));
|
||||
@@ -1103,13 +1101,13 @@ static void writeBlocks(U32* seed, frame_t* frame, dictInfo info)
|
||||
blockContentSize = contentLeft;
|
||||
} else {
|
||||
if (contentLeft > 0 && (RAND(seed) & 7)) {
|
||||
/* some variable size blocks */
|
||||
/* some variable size block */
|
||||
blockContentSize = RAND(seed) % (MIN(maxBlockSize, contentLeft)+1);
|
||||
} else if (contentLeft > maxBlockSize && (RAND(seed) & 1)) {
|
||||
/* some full size blocks */
|
||||
/* some full size block */
|
||||
blockContentSize = maxBlockSize;
|
||||
} else {
|
||||
/* some empty blocks */
|
||||
/* some empty block */
|
||||
blockContentSize = 0;
|
||||
}
|
||||
}
|
||||
@@ -1125,7 +1123,7 @@ static void writeChecksum(frame_t* frame)
|
||||
{
|
||||
/* write checksum so implementations can verify their output */
|
||||
U64 digest = XXH64(frame->srcStart, (BYTE*)frame->src-(BYTE*)frame->srcStart, 0);
|
||||
DISPLAYLEVEL(2, " checksum: %08x\n", (U32)digest);
|
||||
DISPLAYLEVEL(3, " checksum: %08x\n", (U32)digest);
|
||||
MEM_writeLE32(frame->data, (U32)digest);
|
||||
frame->data = (BYTE*)frame->data + 4;
|
||||
}
|
||||
@@ -1146,8 +1144,7 @@ static void outputBuffer(const void* buf, size_t size, const char* const path)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
{
|
||||
size_t fsize = size;
|
||||
{ size_t fsize = size;
|
||||
size_t written = 0;
|
||||
while (written < fsize) {
|
||||
written += fwrite(ip + written, 1, fsize - written, out);
|
||||
@@ -1187,23 +1184,21 @@ static U32 generateCompressedBlock(U32 seed, frame_t* frame, dictInfo info)
|
||||
size_t blockContentSize;
|
||||
int blockWritten = 0;
|
||||
BYTE* op;
|
||||
DISPLAYLEVEL(1, "block seed: %u\n", seed);
|
||||
DISPLAYLEVEL(4, "block seed: %u\n", seed);
|
||||
initFrame(frame);
|
||||
op = (BYTE*)frame->data;
|
||||
|
||||
while (!blockWritten) {
|
||||
size_t cSize;
|
||||
/* generate window size */
|
||||
{
|
||||
int const exponent = RAND(&seed) % (MAX_WINDOW_LOG - 10);
|
||||
{ int const exponent = RAND(&seed) % (MAX_WINDOW_LOG - 10);
|
||||
int const mantissa = RAND(&seed) % 8;
|
||||
frame->header.windowSize = (1U << (exponent + 10));
|
||||
frame->header.windowSize += (frame->header.windowSize / 8) * mantissa;
|
||||
}
|
||||
|
||||
/* generate content size */
|
||||
{
|
||||
size_t const maxBlockSize = MIN(g_maxBlockSize, frame->header.windowSize);
|
||||
{ size_t const maxBlockSize = MIN(g_maxBlockSize, frame->header.windowSize);
|
||||
if (RAND(&seed) & 15) {
|
||||
/* some full size blocks */
|
||||
blockContentSize = maxBlockSize;
|
||||
@@ -1220,13 +1215,13 @@ static U32 generateCompressedBlock(U32 seed, frame_t* frame, dictInfo info)
|
||||
frame->oldStats = frame->stats;
|
||||
frame->data = op;
|
||||
cSize = writeCompressedBlock(&seed, frame, blockContentSize, info);
|
||||
if (cSize > blockContentSize) {
|
||||
if (cSize >= blockContentSize) { /* compressed size must be strictly smaller than decompressed size : https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#blocks */
|
||||
/* data doesn't compress -- try again */
|
||||
frame->stats = frame->oldStats; /* don't update the stats */
|
||||
DISPLAYLEVEL(3, " can't compress block\n");
|
||||
DISPLAYLEVEL(5, " can't compress block : try again \n");
|
||||
} else {
|
||||
blockWritten = 1;
|
||||
DISPLAYLEVEL(3, " block size: %u\n", (U32)cSize);
|
||||
DISPLAYLEVEL(4, " block size: %u \n", (U32)cSize);
|
||||
frame->src = (BYTE*)frame->src + blockContentSize;
|
||||
}
|
||||
}
|
||||
@@ -1237,7 +1232,7 @@ static U32 generateCompressedBlock(U32 seed, frame_t* frame, dictInfo info)
|
||||
static U32 generateFrame(U32 seed, frame_t* fr, dictInfo info)
|
||||
{
|
||||
/* generate a complete frame */
|
||||
DISPLAYLEVEL(1, "frame seed: %u\n", seed);
|
||||
DISPLAYLEVEL(3, "frame seed: %u\n", seed);
|
||||
initFrame(fr);
|
||||
|
||||
writeFrameHeader(&seed, fr, info);
|
||||
@@ -1251,7 +1246,8 @@ static U32 generateFrame(U32 seed, frame_t* fr, dictInfo info)
|
||||
* Dictionary Helper Functions
|
||||
*********************************************************/
|
||||
/* returns 0 if successful, otherwise returns 1 upon error */
|
||||
static int genRandomDict(U32 dictID, U32 seed, size_t dictSize, BYTE* fullDict){
|
||||
static int genRandomDict(U32 dictID, U32 seed, size_t dictSize, BYTE* fullDict)
|
||||
{
|
||||
/* allocate space for samples */
|
||||
int ret = 0;
|
||||
unsigned const numSamples = 4;
|
||||
@@ -1263,27 +1259,20 @@ static int genRandomDict(U32 dictID, U32 seed, size_t dictSize, BYTE* fullDict){
|
||||
}
|
||||
|
||||
/* generate samples */
|
||||
{
|
||||
unsigned literalValue = 1;
|
||||
{ unsigned literalValue = 1;
|
||||
unsigned samplesPos = 0;
|
||||
size_t currSize = 1;
|
||||
while (literalValue <= 4) {
|
||||
sampleSizes[literalValue - 1] = currSize;
|
||||
{
|
||||
size_t k;
|
||||
{ size_t k;
|
||||
for (k = 0; k < currSize; k++) {
|
||||
*(samples + (samplesPos++)) = (BYTE)literalValue;
|
||||
}
|
||||
}
|
||||
} }
|
||||
literalValue++;
|
||||
currSize *= 16;
|
||||
}
|
||||
}
|
||||
} }
|
||||
|
||||
|
||||
{
|
||||
/* create variables */
|
||||
size_t dictWriteSize = 0;
|
||||
{ size_t dictWriteSize = 0;
|
||||
ZDICT_params_t zdictParams;
|
||||
size_t const headerSize = MAX(dictSize/4, 256);
|
||||
size_t const dictContentSize = dictSize - headerSize;
|
||||
@@ -1403,24 +1392,19 @@ static size_t testDecodeWithDict(U32 seed, genType_e genType)
|
||||
}
|
||||
|
||||
/* generate random dictionary */
|
||||
{
|
||||
int const ret = genRandomDict(dictID, seed, dictSize, fullDict);
|
||||
if (ret != 0) {
|
||||
errorDetected = ERROR(GENERIC);
|
||||
goto dictTestCleanup;
|
||||
}
|
||||
if (genRandomDict(dictID, seed, dictSize, fullDict)) { /* return 0 on success */
|
||||
errorDetected = ERROR(GENERIC);
|
||||
goto dictTestCleanup;
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
frame_t fr;
|
||||
{ frame_t fr;
|
||||
dictInfo info;
|
||||
ZSTD_DCtx* const dctx = ZSTD_createDCtx();
|
||||
size_t ret;
|
||||
|
||||
/* get dict info */
|
||||
{
|
||||
size_t const headerSize = MAX(dictSize/4, 256);
|
||||
{ size_t const headerSize = MAX(dictSize/4, 256);
|
||||
size_t const dictContentSize = dictSize-headerSize;
|
||||
BYTE* const dictContent = fullDict+headerSize;
|
||||
info = initDictInfo(1, dictContentSize, dictContent, dictID);
|
||||
@@ -1429,13 +1413,13 @@ static size_t testDecodeWithDict(U32 seed, genType_e genType)
|
||||
/* manually decompress and check difference */
|
||||
if (genType == gt_frame) {
|
||||
/* Test frame */
|
||||
seed = generateFrame(seed, &fr, info);
|
||||
generateFrame(seed, &fr, info);
|
||||
ret = ZSTD_decompress_usingDict(dctx, DECOMPRESSED_BUFFER, MAX_DECOMPRESSED_SIZE,
|
||||
fr.dataStart, (BYTE*)fr.data - (BYTE*)fr.dataStart,
|
||||
fullDict, dictSize);
|
||||
} else {
|
||||
/* Test block */
|
||||
seed = generateCompressedBlock(seed, &fr, info);
|
||||
generateCompressedBlock(seed, &fr, info);
|
||||
ret = ZSTD_decompressBegin_usingDict(dctx, fullDict, dictSize);
|
||||
if (ZSTD_isError(ret)) {
|
||||
errorDetected = ret;
|
||||
@@ -1488,8 +1472,7 @@ static int runBlockTest(U32* seed)
|
||||
{
|
||||
frame_t fr;
|
||||
U32 const seedCopy = *seed;
|
||||
{
|
||||
dictInfo const info = initDictInfo(0, 0, NULL, 0);
|
||||
{ dictInfo const info = initDictInfo(0, 0, NULL, 0);
|
||||
*seed = generateCompressedBlock(*seed, &fr, info);
|
||||
}
|
||||
|
||||
@@ -1501,8 +1484,7 @@ static int runBlockTest(U32* seed)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
size_t const r = testDecodeWithDict(*seed, gt_block);
|
||||
{ size_t const r = testDecodeWithDict(*seed, gt_block);
|
||||
if (ZSTD_isError(r)) {
|
||||
DISPLAY("Error in block mode with dictionary on test seed %u: %s\n",
|
||||
seedCopy, ZSTD_getErrorName(r));
|
||||
@@ -1516,30 +1498,28 @@ static int runFrameTest(U32* seed)
|
||||
{
|
||||
frame_t fr;
|
||||
U32 const seedCopy = *seed;
|
||||
{
|
||||
dictInfo const info = initDictInfo(0, 0, NULL, 0);
|
||||
{ dictInfo const info = initDictInfo(0, 0, NULL, 0);
|
||||
*seed = generateFrame(*seed, &fr, info);
|
||||
}
|
||||
|
||||
{ size_t const r = testDecodeSimple(&fr);
|
||||
if (ZSTD_isError(r)) {
|
||||
DISPLAY("Error in simple mode on test seed %u: %s\n", seedCopy,
|
||||
ZSTD_getErrorName(r));
|
||||
DISPLAY("Error in simple mode on test seed %u: %s\n",
|
||||
seedCopy, ZSTD_getErrorName(r));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
{ size_t const r = testDecodeStreaming(&fr);
|
||||
if (ZSTD_isError(r)) {
|
||||
DISPLAY("Error in streaming mode on test seed %u: %s\n", seedCopy,
|
||||
ZSTD_getErrorName(r));
|
||||
DISPLAY("Error in streaming mode on test seed %u: %s\n",
|
||||
seedCopy, ZSTD_getErrorName(r));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
{
|
||||
/* don't create a dictionary that is too big */
|
||||
size_t const r = testDecodeWithDict(*seed, gt_frame);
|
||||
{ size_t const r = testDecodeWithDict(*seed, gt_frame); /* avoid big dictionaries */
|
||||
if (ZSTD_isError(r)) {
|
||||
DISPLAY("Error in dictionary mode on test seed %u: %s\n", seedCopy, ZSTD_getErrorName(r));
|
||||
DISPLAY("Error in dictionary mode on test seed %u: %s\n",
|
||||
seedCopy, ZSTD_getErrorName(r));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -1563,17 +1543,11 @@ static int runTestMode(U32 seed, unsigned numFiles, unsigned const testDurationS
|
||||
DISPLAYUPDATE("\r%u/%u ", fnum, numFiles);
|
||||
else
|
||||
DISPLAYUPDATE("\r%u ", fnum);
|
||||
{
|
||||
int ret;
|
||||
if (genType == gt_frame) {
|
||||
ret = runFrameTest(&seed);
|
||||
} else {
|
||||
ret = runBlockTest(&seed);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
{ int const ret = (genType == gt_frame) ?
|
||||
runFrameTest(&seed) :
|
||||
runBlockTest(&seed);
|
||||
if (ret) return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1594,8 +1568,7 @@ static int generateFile(U32 seed, const char* const path,
|
||||
|
||||
DISPLAY("seed: %u\n", seed);
|
||||
|
||||
{
|
||||
dictInfo const info = initDictInfo(0, 0, NULL, 0);
|
||||
{ dictInfo const info = initDictInfo(0, 0, NULL, 0);
|
||||
if (genType == gt_frame) {
|
||||
generateFrame(seed, &fr, info);
|
||||
} else {
|
||||
@@ -1622,8 +1595,7 @@ static int generateCorpus(U32 seed, unsigned numFiles, const char* const path,
|
||||
|
||||
DISPLAYUPDATE("\r%u/%u ", fnum, numFiles);
|
||||
|
||||
{
|
||||
dictInfo const info = initDictInfo(0, 0, NULL, 0);
|
||||
{ dictInfo const info = initDictInfo(0, 0, NULL, 0);
|
||||
if (genType == gt_frame) {
|
||||
seed = generateFrame(seed, &fr, info);
|
||||
} else {
|
||||
@@ -1673,8 +1645,7 @@ static int generateCorpusWithDict(U32 seed, unsigned numFiles, const char* const
|
||||
}
|
||||
|
||||
/* randomly generate the dictionary */
|
||||
{
|
||||
int const ret = genRandomDict(dictID, seed, dictSize, fullDict);
|
||||
{ int const ret = genRandomDict(dictID, seed, dictSize, fullDict);
|
||||
if (ret != 0) {
|
||||
errorDetected = ret;
|
||||
goto dictCleanup;
|
||||
@@ -1695,8 +1666,7 @@ static int generateCorpusWithDict(U32 seed, unsigned numFiles, const char* const
|
||||
}
|
||||
|
||||
/* generate random compressed/decompressed files */
|
||||
{
|
||||
unsigned fnum;
|
||||
{ unsigned fnum;
|
||||
for (fnum = 0; fnum < MAX(numFiles, 1); fnum++) {
|
||||
frame_t fr;
|
||||
DISPLAYUPDATE("\r%u/%u ", fnum, numFiles);
|
||||
@@ -1907,7 +1877,7 @@ int main(int argc, char** argv)
|
||||
genType = gt_block;
|
||||
} else if (longCommandWArg(&argument, "max-block-size-log=")) {
|
||||
U32 value = readU32FromChar(&argument);
|
||||
if (value >= 2 && value <= MAX_BLOCK_SIZE) {
|
||||
if (value >= 2 && value <= ZSTD_BLOCKSIZE_MAX) {
|
||||
g_maxBlockSize = 1U << value;
|
||||
}
|
||||
} else if (longCommandWArg(&argument, "max-content-size-log=")) {
|
||||
|
||||
@@ -376,6 +376,7 @@ static size_t benchMem(const void* src, size_t srcSize, U32 benchNb)
|
||||
skippedSize = frameHeaderSize + ZSTD_blockHeaderSize;
|
||||
memcpy(buff2, dstBuff+skippedSize, g_cSize-skippedSize);
|
||||
srcSize = srcSize > 128 KB ? 128 KB : srcSize; /* speed relative to block */
|
||||
ZSTD_decompressBegin(g_zdc);
|
||||
break;
|
||||
}
|
||||
case 32: /* ZSTD_decodeSeqHeaders */
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# test artefacts
|
||||
corpora
|
||||
block_decompress
|
||||
block_round_trip
|
||||
simple_round_trip
|
||||
+33
-5
@@ -14,6 +14,13 @@ CPPFLAGS ?=
|
||||
LDFLAGS ?=
|
||||
ARFLAGS ?=
|
||||
LIB_FUZZING_ENGINE ?= libregression.a
|
||||
PYTHON ?= python
|
||||
ifeq ($(shell uname), Darwin)
|
||||
DOWNLOAD?=curl -L -o
|
||||
else
|
||||
DOWNLOAD?=wget -O
|
||||
endif
|
||||
CORPORA_URL_PREFIX:=https://github.com/facebook/zstd/releases/download/fuzz-corpora/
|
||||
|
||||
ZSTDDIR = ../../lib
|
||||
PRGDIR = ../../programs
|
||||
@@ -48,18 +55,20 @@ FUZZ_SRC := \
|
||||
FUZZ_OBJ := $(patsubst %.c,%.o, $(wildcard $(FUZZ_SRC)))
|
||||
|
||||
|
||||
.PHONY: default all clean
|
||||
.PHONY: default all clean cleanall
|
||||
|
||||
default: all
|
||||
|
||||
all: \
|
||||
FUZZ_TARGETS := \
|
||||
simple_round_trip \
|
||||
stream_round_trip \
|
||||
block_round_trip \
|
||||
block_round_trip \
|
||||
simple_decompress \
|
||||
stream_decompress \
|
||||
block_decompress
|
||||
|
||||
all: $(FUZZ_TARGETS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(FUZZ_CPPFLAGS) $(FUZZ_CFLAGS) $^ -c -o $@
|
||||
|
||||
@@ -93,7 +102,26 @@ libFuzzer:
|
||||
@git clone https://chromium.googlesource.com/chromium/llvm-project/llvm/lib/Fuzzer
|
||||
@cd Fuzzer && ./build.sh
|
||||
|
||||
corpora/%_seed_corpus.zip:
|
||||
@mkdir -p corpora
|
||||
$(DOWNLOAD) $@ $(CORPORA_URL_PREFIX)$*_seed_corpus.zip
|
||||
|
||||
corpora/%: corpora/%_seed_corpus.zip
|
||||
unzip -q $^ -d $@
|
||||
|
||||
.PHONY: corpora
|
||||
corpora: $(patsubst %,corpora/%,$(FUZZ_TARGETS))
|
||||
|
||||
regressiontest: corpora
|
||||
CC="$(CC)" CXX="$(CXX)" CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" LDFLAGS="$(LDFLAGS)" $(PYTHON) ./fuzz.py build all
|
||||
$(PYTHON) ./fuzz.py regression all
|
||||
|
||||
clean:
|
||||
@$(MAKE) -C $(ZSTDDIR) clean
|
||||
@$(RM) -f *.a *.o
|
||||
@$(RM) -f simple_round_trip stream_round_trip simple_decompress stream_decompress
|
||||
@$(RM) *.a *.o
|
||||
@$(RM) simple_round_trip stream_round_trip simple_decompress \
|
||||
stream_decompress block_decompress block_round_trip
|
||||
|
||||
cleanall:
|
||||
@$(RM) -r Fuzzer
|
||||
@$(RM) -r corpora
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
# Fuzzing
|
||||
|
||||
Each fuzzing target can be built with multiple engines.
|
||||
Zstd provides a fuzz corpus for each target that can be downloaded with
|
||||
the command:
|
||||
|
||||
```
|
||||
make corpora
|
||||
```
|
||||
|
||||
It will download each corpus into `./corpora/TARGET`.
|
||||
|
||||
## fuzz.py
|
||||
|
||||
|
||||
@@ -34,27 +34,20 @@ static size_t roundTripTest(void *result, size_t resultCapacity,
|
||||
void *compressed, size_t compressedCapacity,
|
||||
const void *src, size_t srcSize)
|
||||
{
|
||||
int const cLevel = FUZZ_rand(&seed) % kMaxClevel;
|
||||
size_t ret = ZSTD_compressBegin(cctx, cLevel);
|
||||
int const cLevel = FUZZ_rand(&seed) % kMaxClevel;
|
||||
ZSTD_parameters const params = ZSTD_getParams(cLevel, srcSize, 0);
|
||||
size_t ret = ZSTD_compressBegin_advanced(cctx, NULL, 0, params, srcSize);
|
||||
FUZZ_ZASSERT(ret);
|
||||
|
||||
if (ZSTD_isError(ret)) {
|
||||
fprintf(stderr, "ZSTD_compressBegin() error: %s\n",
|
||||
ZSTD_getErrorName(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ZSTD_compressBlock(cctx, compressed, compressedCapacity, src, srcSize);
|
||||
if (ZSTD_isError(ret)) {
|
||||
fprintf(stderr, "ZSTD_compressBlock() error: %s\n", ZSTD_getErrorName(ret));
|
||||
return ret;
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = ZSTD_compressBlock(cctx, compressed, compressedCapacity, src, srcSize);
|
||||
FUZZ_ZASSERT(ret);
|
||||
if (ret == 0) {
|
||||
FUZZ_ASSERT(resultCapacity >= srcSize);
|
||||
memcpy(result, src, srcSize);
|
||||
return srcSize;
|
||||
}
|
||||
ZSTD_decompressBegin(dctx);
|
||||
return ZSTD_decompressBlock(dctx, result, resultCapacity, compressed, ret);
|
||||
}
|
||||
ZSTD_decompressBegin(dctx);
|
||||
return ZSTD_decompressBlock(dctx, result, resultCapacity, compressed, ret);
|
||||
}
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
@@ -87,7 +80,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
{
|
||||
size_t const result =
|
||||
roundTripTest(rBuf, neededBufSize, cBuf, neededBufSize, src, size);
|
||||
FUZZ_ASSERT_MSG(!ZSTD_isError(result), ZSTD_getErrorName(result));
|
||||
FUZZ_ZASSERT(result);
|
||||
FUZZ_ASSERT_MSG(result == size, "Incorrect regenerated size");
|
||||
FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
[libfuzzer]
|
||||
max_len = 8192
|
||||
+151
-54
@@ -1,4 +1,4 @@
|
||||
#! /usr/bin/env python
|
||||
#!/usr/bin/env python
|
||||
|
||||
# ################################################################
|
||||
# Copyright (c) 2016-present, Facebook, Inc.
|
||||
@@ -82,11 +82,39 @@ def tmpdir():
|
||||
shutil.rmtree(dirpath, ignore_errors=True)
|
||||
|
||||
|
||||
def parse_targets(in_targets):
|
||||
targets = set()
|
||||
for target in in_targets:
|
||||
if not target:
|
||||
continue
|
||||
if target == 'all':
|
||||
targets = targets.union(TARGETS)
|
||||
elif target in TARGETS:
|
||||
targets.add(target)
|
||||
else:
|
||||
raise RuntimeError('{} is not a valid target'.format(target))
|
||||
return list(targets)
|
||||
|
||||
|
||||
def targets_parser(args, description):
|
||||
parser = argparse.ArgumentParser(prog=args.pop(0), description=description)
|
||||
parser.add_argument(
|
||||
'TARGET',
|
||||
nargs='*',
|
||||
type=str,
|
||||
help='Fuzz target(s) to build {{{}}}'.format(', '.join(ALL_TARGETS)))
|
||||
args, extra = parser.parse_known_args(args)
|
||||
args.extra = extra
|
||||
|
||||
args.TARGET = parse_targets(args.TARGET)
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def parse_env_flags(args, flags):
|
||||
"""
|
||||
Look for flags set by environment variables.
|
||||
"""
|
||||
flags = ' '.join(flags)
|
||||
san_flags = ','.join(re.findall('-fsanitize=((?:[a-z]+,?)+)', flags))
|
||||
nosan_flags = ','.join(re.findall('-fno-sanitize=((?:[a-z]+,?)+)', flags))
|
||||
|
||||
@@ -112,6 +140,34 @@ def parse_env_flags(args, flags):
|
||||
return args
|
||||
|
||||
|
||||
def compiler_version(cc, cxx):
|
||||
"""
|
||||
Determines the compiler and version.
|
||||
Only works for clang and gcc.
|
||||
"""
|
||||
cc_version_bytes = subprocess.check_output([cc, "--version"])
|
||||
cxx_version_bytes = subprocess.check_output([cxx, "--version"])
|
||||
if cc_version_bytes.startswith(b'clang'):
|
||||
assert(cxx_version_bytes.startswith(b'clang'))
|
||||
compiler = 'clang'
|
||||
if cc_version_bytes.startswith(b'gcc'):
|
||||
assert(cxx_version_bytes.startswith(b'g++'))
|
||||
compiler = 'gcc'
|
||||
version_regex = b'([0-9])+\.([0-9])+\.([0-9])+'
|
||||
version_match = re.search(version_regex, cc_version_bytes)
|
||||
version = tuple(int(version_match.group(i)) for i in range(1, 4))
|
||||
return compiler, version
|
||||
|
||||
|
||||
def overflow_ubsan_flags(cc, cxx):
|
||||
compiler, version = compiler_version(cc, cxx)
|
||||
if compiler == 'gcc':
|
||||
return ['-fno-sanitize=signed-integer-overflow']
|
||||
if compiler == 'clang' and version >= (5, 0, 0):
|
||||
return ['-fno-sanitize=pointer-overflow']
|
||||
return []
|
||||
|
||||
|
||||
def build_parser(args):
|
||||
description = """
|
||||
Cleans the repository and builds a fuzz target (or all).
|
||||
@@ -336,7 +392,7 @@ def build(args):
|
||||
if args.ubsan:
|
||||
ubsan_flags = ['-fsanitize=undefined']
|
||||
if not args.ubsan_pointer_overflow:
|
||||
ubsan_flags += ['-fno-sanitize=pointer-overflow']
|
||||
ubsan_flags += overflow_ubsan_flags(cc, cxx)
|
||||
common_flags += ubsan_flags
|
||||
|
||||
if args.stateful_fuzzing:
|
||||
@@ -424,36 +480,42 @@ def libfuzzer_parser(args):
|
||||
if args.TARGET and args.TARGET not in TARGETS:
|
||||
raise RuntimeError('{} is not a valid target'.format(args.TARGET))
|
||||
|
||||
if not args.corpora:
|
||||
args.corpora = abs_join(CORPORA_DIR, args.TARGET)
|
||||
if not args.artifact:
|
||||
args.artifact = abs_join(CORPORA_DIR, '{}-crash'.format(args.TARGET))
|
||||
if not args.seed:
|
||||
args.seed = abs_join(CORPORA_DIR, '{}-seed'.format(args.TARGET))
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def libfuzzer(args):
|
||||
try:
|
||||
args = libfuzzer_parser(args)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return 1
|
||||
target = abs_join(FUZZ_DIR, args.TARGET)
|
||||
def libfuzzer(target, corpora=None, artifact=None, seed=None, extra_args=None):
|
||||
if corpora is None:
|
||||
corpora = abs_join(CORPORA_DIR, target)
|
||||
if artifact is None:
|
||||
artifact = abs_join(CORPORA_DIR, '{}-crash'.format(target))
|
||||
if seed is None:
|
||||
seed = abs_join(CORPORA_DIR, '{}-seed'.format(target))
|
||||
if extra_args is None:
|
||||
extra_args = []
|
||||
|
||||
corpora = [create(args.corpora)]
|
||||
artifact = create(args.artifact)
|
||||
seed = check(args.seed)
|
||||
target = abs_join(FUZZ_DIR, target)
|
||||
|
||||
corpora = [create(corpora)]
|
||||
artifact = create(artifact)
|
||||
seed = check(seed)
|
||||
|
||||
corpora += [artifact]
|
||||
if seed is not None:
|
||||
corpora += [seed]
|
||||
|
||||
cmd = [target, '-artifact_prefix={}/'.format(artifact)]
|
||||
cmd += corpora + args.extra
|
||||
cmd += corpora + extra_args
|
||||
print(' '.join(cmd))
|
||||
subprocess.call(cmd)
|
||||
subprocess.check_call(cmd)
|
||||
|
||||
|
||||
def libfuzzer_cmd(args):
|
||||
try:
|
||||
args = libfuzzer_parser(args)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return 1
|
||||
libfuzzer(args.TARGET, args.corpora, args.artifact, args.seed, args.extra)
|
||||
return 0
|
||||
|
||||
|
||||
@@ -518,39 +580,15 @@ def afl(args):
|
||||
return 0
|
||||
|
||||
|
||||
def regression_parser(args):
|
||||
description = """
|
||||
Runs one or more regression tests.
|
||||
The fuzzer should have been built with with
|
||||
LIB_FUZZING_ENGINE='libregression.a'.
|
||||
Takes input from CORPORA.
|
||||
"""
|
||||
parser = argparse.ArgumentParser(prog=args.pop(0), description=description)
|
||||
parser.add_argument(
|
||||
'TARGET',
|
||||
nargs='*',
|
||||
type=str,
|
||||
help='Fuzz target(s) to build {{{}}}'.format(', '.join(ALL_TARGETS)))
|
||||
args = parser.parse_args(args)
|
||||
|
||||
targets = set()
|
||||
for target in args.TARGET:
|
||||
if not target:
|
||||
continue
|
||||
if target == 'all':
|
||||
targets = targets.union(TARGETS)
|
||||
elif target in TARGETS:
|
||||
targets.add(target)
|
||||
else:
|
||||
raise RuntimeError('{} is not a valid target'.format(target))
|
||||
args.TARGET = list(targets)
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def regression(args):
|
||||
try:
|
||||
args = regression_parser(args)
|
||||
description = """
|
||||
Runs one or more regression tests.
|
||||
The fuzzer should have been built with with
|
||||
LIB_FUZZING_ENGINE='libregression.a'.
|
||||
Takes input from CORPORA.
|
||||
"""
|
||||
args = targets_parser(args, description)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return 1
|
||||
@@ -673,6 +711,56 @@ def gen(args):
|
||||
return 0
|
||||
|
||||
|
||||
def minimize(args):
|
||||
try:
|
||||
description = """
|
||||
Runs a libfuzzer fuzzer with -merge=1 to build a minimal corpus in
|
||||
TARGET_seed_corpus. All extra args are passed to libfuzzer.
|
||||
"""
|
||||
args = targets_parser(args, description)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return 1
|
||||
|
||||
for target in args.TARGET:
|
||||
# Merge the corpus + anything else into the seed_corpus
|
||||
corpus = abs_join(CORPORA_DIR, target)
|
||||
seed_corpus = abs_join(CORPORA_DIR, "{}_seed_corpus".format(target))
|
||||
extra_args = [corpus, "-merge=1"] + args.extra
|
||||
libfuzzer(target, corpora=seed_corpus, extra_args=extra_args)
|
||||
seeds = set(os.listdir(seed_corpus))
|
||||
# Copy all crashes directly into the seed_corpus if not already present
|
||||
crashes = abs_join(CORPORA_DIR, '{}-crash'.format(target))
|
||||
for crash in os.listdir(crashes):
|
||||
if crash not in seeds:
|
||||
shutil.copy(abs_join(crashes, crash), seed_corpus)
|
||||
seeds.add(crash)
|
||||
|
||||
|
||||
def zip_cmd(args):
|
||||
try:
|
||||
description = """
|
||||
Zips up the seed corpus.
|
||||
"""
|
||||
args = targets_parser(args, description)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return 1
|
||||
|
||||
for target in args.TARGET:
|
||||
# Zip the seed_corpus
|
||||
seed_corpus = abs_join(CORPORA_DIR, "{}_seed_corpus".format(target))
|
||||
seeds = [abs_join(seed_corpus, f) for f in os.listdir(seed_corpus)]
|
||||
zip_file = "{}.zip".format(seed_corpus)
|
||||
cmd = ["zip", "-q", "-j", "-9", zip_file]
|
||||
print(' '.join(cmd + [abs_join(seed_corpus, '*')]))
|
||||
subprocess.check_call(cmd + seeds)
|
||||
|
||||
|
||||
def list_cmd(args):
|
||||
print("\n".join(TARGETS))
|
||||
|
||||
|
||||
def short_help(args):
|
||||
name = args[0]
|
||||
print("Usage: {} [OPTIONS] COMMAND [ARGS]...\n".format(name))
|
||||
@@ -690,6 +778,9 @@ def help(args):
|
||||
print("\tafl\t\tRun an AFL fuzzer")
|
||||
print("\tregression\tRun a regression test")
|
||||
print("\tgen\t\tGenerate a seed corpus for a fuzzer")
|
||||
print("\tminimize\tMinimize the test corpora")
|
||||
print("\tzip\t\tZip the minimized corpora up")
|
||||
print("\tlist\t\tList the available targets")
|
||||
|
||||
|
||||
def main():
|
||||
@@ -705,13 +796,19 @@ def main():
|
||||
if command == "build":
|
||||
return build(args)
|
||||
if command == "libfuzzer":
|
||||
return libfuzzer(args)
|
||||
return libfuzzer_cmd(args)
|
||||
if command == "regression":
|
||||
return regression(args)
|
||||
if command == "afl":
|
||||
return afl(args)
|
||||
if command == "gen":
|
||||
return gen(args)
|
||||
if command == "minimize":
|
||||
return minimize(args)
|
||||
if command == "zip":
|
||||
return zip_cmd(args)
|
||||
if command == "list":
|
||||
return list_cmd(args)
|
||||
short_help(args)
|
||||
print("Error: No such command {} (pass -h for help)".format(command))
|
||||
return 1
|
||||
|
||||
@@ -38,23 +38,20 @@ static size_t roundTripTest(void *result, size_t resultCapacity,
|
||||
if (FUZZ_rand(&seed) & 1) {
|
||||
ZSTD_inBuffer in = {src, srcSize, 0};
|
||||
ZSTD_outBuffer out = {compressed, compressedCapacity, 0};
|
||||
size_t err;
|
||||
|
||||
ZSTD_CCtx_reset(cctx);
|
||||
FUZZ_setRandomParameters(cctx, &seed);
|
||||
size_t const err = ZSTD_compress_generic(cctx, &out, &in, ZSTD_e_end);
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
FUZZ_setRandomParameters(cctx, srcSize, &seed);
|
||||
err = ZSTD_compress_generic(cctx, &out, &in, ZSTD_e_end);
|
||||
FUZZ_ZASSERT(err);
|
||||
FUZZ_ASSERT(err == 0);
|
||||
cSize = out.pos;
|
||||
} else {
|
||||
int const cLevel = FUZZ_rand(&seed) % kMaxClevel;
|
||||
cSize = ZSTD_compressCCtx(
|
||||
cctx, compressed, compressedCapacity, src, srcSize, cLevel);
|
||||
}
|
||||
if (ZSTD_isError(cSize)) {
|
||||
fprintf(stderr, "Compression error: %s\n", ZSTD_getErrorName(cSize));
|
||||
return cSize;
|
||||
}
|
||||
FUZZ_ZASSERT(cSize);
|
||||
return ZSTD_decompressDCtx(dctx, result, resultCapacity, compressed, cSize);
|
||||
}
|
||||
|
||||
@@ -86,7 +83,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
{
|
||||
size_t const result =
|
||||
roundTripTest(rBuf, neededBufSize, cBuf, neededBufSize, src, size);
|
||||
FUZZ_ASSERT_MSG(!ZSTD_isError(result), ZSTD_getErrorName(result));
|
||||
FUZZ_ZASSERT(result);
|
||||
FUZZ_ASSERT_MSG(result == size, "Incorrect regenerated size");
|
||||
FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!");
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ static size_t compress(uint8_t *dst, size_t capacity,
|
||||
{
|
||||
size_t dstSize = 0;
|
||||
ZSTD_CCtx_reset(cctx);
|
||||
FUZZ_setRandomParameters(cctx, &seed);
|
||||
FUZZ_setRandomParameters(cctx, srcSize, &seed);
|
||||
|
||||
while (srcSize > 0) {
|
||||
ZSTD_inBuffer in = makeInBuffer(&src, &srcSize);
|
||||
@@ -85,7 +85,10 @@ static size_t compress(uint8_t *dst, size_t capacity,
|
||||
/* Reset the compressor when the frame is finished */
|
||||
if (ret == 0) {
|
||||
ZSTD_CCtx_reset(cctx);
|
||||
FUZZ_setRandomParameters(cctx, &seed);
|
||||
if ((FUZZ_rand(&seed) & 7) == 0) {
|
||||
size_t const remaining = in.size - in.pos;
|
||||
FUZZ_setRandomParameters(cctx, remaining, &seed);
|
||||
}
|
||||
mode = -1;
|
||||
}
|
||||
break;
|
||||
@@ -146,7 +149,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
size_t const cSize = compress(cBuf, neededBufSize, src, size);
|
||||
size_t const rSize =
|
||||
ZSTD_decompressDCtx(dctx, rBuf, neededBufSize, cBuf, cSize);
|
||||
FUZZ_ASSERT_MSG(!ZSTD_isError(rSize), ZSTD_getErrorName(rSize));
|
||||
FUZZ_ZASSERT(rSize);
|
||||
FUZZ_ASSERT_MSG(rSize == size, "Incorrect regenerated size");
|
||||
FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!");
|
||||
}
|
||||
|
||||
+53
-15
@@ -13,30 +13,68 @@
|
||||
#include "fuzz_helpers.h"
|
||||
#include "zstd.h"
|
||||
|
||||
static void setRand(ZSTD_CCtx *cctx, ZSTD_cParameter param, unsigned min,
|
||||
unsigned max, uint32_t *state) {
|
||||
unsigned const value = FUZZ_rand32(state, min, max);
|
||||
FUZZ_ZASSERT(ZSTD_CCtx_setParameter(cctx, param, value));
|
||||
static void set(ZSTD_CCtx *cctx, ZSTD_cParameter param, unsigned value)
|
||||
{
|
||||
FUZZ_ZASSERT(ZSTD_CCtx_setParameter(cctx, param, value));
|
||||
}
|
||||
|
||||
void FUZZ_setRandomParameters(ZSTD_CCtx *cctx, uint32_t *state)
|
||||
static void setRand(ZSTD_CCtx *cctx, ZSTD_cParameter param, unsigned min,
|
||||
unsigned max, uint32_t *state) {
|
||||
unsigned const value = FUZZ_rand32(state, min, max);
|
||||
set(cctx, param, value);
|
||||
}
|
||||
|
||||
ZSTD_compressionParameters FUZZ_randomCParams(size_t srcSize, uint32_t *state)
|
||||
{
|
||||
setRand(cctx, ZSTD_p_windowLog, ZSTD_WINDOWLOG_MIN, 23, state);
|
||||
setRand(cctx, ZSTD_p_hashLog, ZSTD_HASHLOG_MIN, 23, state);
|
||||
setRand(cctx, ZSTD_p_chainLog, ZSTD_CHAINLOG_MIN, 24, state);
|
||||
setRand(cctx, ZSTD_p_searchLog, ZSTD_SEARCHLOG_MIN, 9, state);
|
||||
setRand(cctx, ZSTD_p_minMatch, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX,
|
||||
state);
|
||||
setRand(cctx, ZSTD_p_targetLength, ZSTD_TARGETLENGTH_MIN,
|
||||
ZSTD_TARGETLENGTH_MAX, state);
|
||||
setRand(cctx, ZSTD_p_compressionStrategy, ZSTD_fast, ZSTD_btultra, state);
|
||||
/* Select compression parameters */
|
||||
ZSTD_compressionParameters cParams;
|
||||
cParams.windowLog = FUZZ_rand32(state, ZSTD_WINDOWLOG_MIN, 15);
|
||||
cParams.hashLog = FUZZ_rand32(state, ZSTD_HASHLOG_MIN, 15);
|
||||
cParams.chainLog = FUZZ_rand32(state, ZSTD_CHAINLOG_MIN, 16);
|
||||
cParams.searchLog = FUZZ_rand32(state, ZSTD_SEARCHLOG_MIN, 9);
|
||||
cParams.searchLength = FUZZ_rand32(state, ZSTD_SEARCHLENGTH_MIN,
|
||||
ZSTD_SEARCHLENGTH_MAX);
|
||||
cParams.targetLength = FUZZ_rand32(state, ZSTD_TARGETLENGTH_MIN,
|
||||
ZSTD_TARGETLENGTH_MAX);
|
||||
cParams.strategy = FUZZ_rand32(state, ZSTD_fast, ZSTD_btultra);
|
||||
return ZSTD_adjustCParams(cParams, srcSize, 0);
|
||||
}
|
||||
|
||||
ZSTD_frameParameters FUZZ_randomFParams(uint32_t *state)
|
||||
{
|
||||
/* Select frame parameters */
|
||||
ZSTD_frameParameters fParams;
|
||||
fParams.contentSizeFlag = FUZZ_rand32(state, 0, 1);
|
||||
fParams.checksumFlag = FUZZ_rand32(state, 0, 1);
|
||||
fParams.noDictIDFlag = FUZZ_rand32(state, 0, 1);
|
||||
return fParams;
|
||||
}
|
||||
|
||||
ZSTD_parameters FUZZ_randomParams(size_t srcSize, uint32_t *state)
|
||||
{
|
||||
ZSTD_parameters params;
|
||||
params.cParams = FUZZ_randomCParams(srcSize, state);
|
||||
params.fParams = FUZZ_randomFParams(state);
|
||||
return params;
|
||||
}
|
||||
|
||||
void FUZZ_setRandomParameters(ZSTD_CCtx *cctx, size_t srcSize, uint32_t *state)
|
||||
{
|
||||
ZSTD_compressionParameters cParams = FUZZ_randomCParams(srcSize, state);
|
||||
set(cctx, ZSTD_p_windowLog, cParams.windowLog);
|
||||
set(cctx, ZSTD_p_hashLog, cParams.hashLog);
|
||||
set(cctx, ZSTD_p_chainLog, cParams.chainLog);
|
||||
set(cctx, ZSTD_p_searchLog, cParams.searchLog);
|
||||
set(cctx, ZSTD_p_minMatch, cParams.searchLength);
|
||||
set(cctx, ZSTD_p_targetLength, cParams.targetLength);
|
||||
set(cctx, ZSTD_p_compressionStrategy, cParams.strategy);
|
||||
/* Select frame parameters */
|
||||
setRand(cctx, ZSTD_p_contentSizeFlag, 0, 1, state);
|
||||
setRand(cctx, ZSTD_p_checksumFlag, 0, 1, state);
|
||||
setRand(cctx, ZSTD_p_dictIDFlag, 0, 1, state);
|
||||
/* Select long distance matchig parameters */
|
||||
setRand(cctx, ZSTD_p_enableLongDistanceMatching, 0, 1, state);
|
||||
setRand(cctx, ZSTD_p_ldmHashLog, ZSTD_HASHLOG_MIN, 24, state);
|
||||
setRand(cctx, ZSTD_p_ldmHashLog, ZSTD_HASHLOG_MIN, 16, state);
|
||||
setRand(cctx, ZSTD_p_ldmMinMatch, ZSTD_LDM_MINMATCH_MIN,
|
||||
ZSTD_LDM_MINMATCH_MAX, state);
|
||||
setRand(cctx, ZSTD_p_ldmBucketSizeLog, 0, ZSTD_LDM_BUCKETSIZELOG_MAX,
|
||||
|
||||
@@ -21,7 +21,11 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void FUZZ_setRandomParameters(ZSTD_CCtx *cctx, uint32_t *state);
|
||||
void FUZZ_setRandomParameters(ZSTD_CCtx *cctx, size_t srcSize, uint32_t *state);
|
||||
|
||||
ZSTD_compressionParameters FUZZ_randomCParams(size_t srcSize, uint32_t *state);
|
||||
ZSTD_frameParameters FUZZ_randomFParams(uint32_t *state);
|
||||
ZSTD_parameters FUZZ_randomParams(size_t srcSize, uint32_t *state);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
+39
-3
@@ -510,8 +510,7 @@ static int basicUnitTests(U32 seed, double compressibility)
|
||||
/* only use the first half so we don't push against size limit of compressedBuffer */
|
||||
size_t const segSize = (CNBuffSize / 2) / segs;
|
||||
for (i = 0; i < segs; i++) {
|
||||
CHECK_V(r,
|
||||
ZSTD_compress(
|
||||
CHECK_V(r, ZSTD_compress(
|
||||
(BYTE *)compressedBuffer + off, CNBuffSize - off,
|
||||
(BYTE *)CNBuffer + segSize * i,
|
||||
segSize, 5));
|
||||
@@ -918,6 +917,43 @@ static int basicUnitTests(U32 seed, double compressibility)
|
||||
ZSTD_freeCCtx(cctx);
|
||||
}
|
||||
|
||||
/* custom formats tests */
|
||||
{ ZSTD_CCtx* const cctx = ZSTD_createCCtx();
|
||||
size_t const inputSize = CNBuffSize / 2; /* won't cause pb with small dict size */
|
||||
|
||||
/* basic block compression */
|
||||
DISPLAYLEVEL(4, "test%3i : magic-less format test : ", testNb++);
|
||||
CHECK( ZSTD_CCtx_setParameter(cctx, ZSTD_p_format, ZSTD_f_zstd1_magicless) );
|
||||
{ ZSTD_inBuffer in = { CNBuffer, inputSize, 0 };
|
||||
ZSTD_outBuffer out = { compressedBuffer, ZSTD_compressBound(inputSize), 0 };
|
||||
size_t const result = ZSTD_compress_generic(cctx, &out, &in, ZSTD_e_end);
|
||||
if (result != 0) goto _output_error;
|
||||
if (in.pos != in.size) goto _output_error;
|
||||
cSize = out.pos;
|
||||
}
|
||||
DISPLAYLEVEL(4, "OK (compress : %u -> %u bytes)\n", (U32)inputSize, (U32)cSize);
|
||||
|
||||
DISPLAYLEVEL(4, "test%3i : decompress normally (should fail) : ", testNb++);
|
||||
{ size_t const decodeResult = ZSTD_decompressDCtx(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize);
|
||||
if (ZSTD_getErrorCode(decodeResult) != ZSTD_error_prefix_unknown) goto _output_error;
|
||||
DISPLAYLEVEL(4, "OK : %s \n", ZSTD_getErrorName(decodeResult));
|
||||
}
|
||||
|
||||
DISPLAYLEVEL(4, "test%3i : decompress with magic-less instruction : ", testNb++);
|
||||
ZSTD_DCtx_reset(dctx);
|
||||
CHECK( ZSTD_DCtx_setFormat(dctx, ZSTD_f_zstd1_magicless) );
|
||||
{ ZSTD_inBuffer in = { compressedBuffer, cSize, 0 };
|
||||
ZSTD_outBuffer out = { decodedBuffer, CNBuffSize, 0 };
|
||||
size_t const result = ZSTD_decompress_generic(dctx, &out, &in);
|
||||
if (result != 0) goto _output_error;
|
||||
if (in.pos != in.size) goto _output_error;
|
||||
if (out.pos != inputSize) goto _output_error;
|
||||
DISPLAYLEVEL(4, "OK : regenerated %u bytes \n", (U32)out.pos);
|
||||
}
|
||||
|
||||
ZSTD_freeCCtx(cctx);
|
||||
}
|
||||
|
||||
/* block API tests */
|
||||
{ ZSTD_CCtx* const cctx = ZSTD_createCCtx();
|
||||
static const size_t dictSize = 65 KB;
|
||||
@@ -961,8 +997,8 @@ static int basicUnitTests(U32 seed, double compressibility)
|
||||
DISPLAYLEVEL(4, "OK \n");
|
||||
|
||||
ZSTD_freeCCtx(cctx);
|
||||
ZSTD_freeDCtx(dctx);
|
||||
}
|
||||
ZSTD_freeDCtx(dctx);
|
||||
|
||||
/* long rle test */
|
||||
{ size_t sampleSize = 0;
|
||||
|
||||
+2
-2
@@ -391,8 +391,8 @@ static int BMK_seed(winnerInfo_t* winners, const ZSTD_compressionParameters para
|
||||
double W_DMemUsed_note = W_ratioNote * ( 40 + 9*cLevel) - log((double)W_DMemUsed);
|
||||
double O_DMemUsed_note = O_ratioNote * ( 40 + 9*cLevel) - log((double)O_DMemUsed);
|
||||
|
||||
size_t W_CMemUsed = (1 << params.windowLog) + ZSTD_estimateCCtxSize_advanced_usingCParams(params);
|
||||
size_t O_CMemUsed = (1 << winners[cLevel].params.windowLog) + ZSTD_estimateCCtxSize_advanced_usingCParams(winners[cLevel].params);
|
||||
size_t W_CMemUsed = (1 << params.windowLog) + ZSTD_estimateCCtxSize_usingCParams(params);
|
||||
size_t O_CMemUsed = (1 << winners[cLevel].params.windowLog) + ZSTD_estimateCCtxSize_usingCParams(winners[cLevel].params);
|
||||
double W_CMemUsed_note = W_ratioNote * ( 50 + 13*cLevel) - log((double)W_CMemUsed);
|
||||
double O_CMemUsed_note = O_ratioNote * ( 50 + 13*cLevel) - log((double)O_CMemUsed);
|
||||
|
||||
|
||||
+58
-34
@@ -13,11 +13,16 @@ roundTripTest() {
|
||||
cLevel="$2"
|
||||
proba=""
|
||||
fi
|
||||
if [ -n "$4" ]; then
|
||||
dLevel="$4"
|
||||
else
|
||||
dLevel="$cLevel"
|
||||
fi
|
||||
|
||||
rm -f tmp1 tmp2
|
||||
$ECHO "roundTripTest: ./datagen $1 $proba | $ZSTD -v$cLevel | $ZSTD -d"
|
||||
$ECHO "roundTripTest: ./datagen $1 $proba | $ZSTD -v$cLevel | $ZSTD -d$dLevel"
|
||||
./datagen $1 $proba | $MD5SUM > tmp1
|
||||
./datagen $1 $proba | $ZSTD --ultra -v$cLevel | $ZSTD -d | $MD5SUM > tmp2
|
||||
./datagen $1 $proba | $ZSTD --ultra -v$cLevel | $ZSTD -d$dLevel | $MD5SUM > tmp2
|
||||
$DIFF -q tmp1 tmp2
|
||||
}
|
||||
|
||||
@@ -29,12 +34,17 @@ fileRoundTripTest() {
|
||||
local_c="$2"
|
||||
local_p=""
|
||||
fi
|
||||
if [ -n "$4" ]; then
|
||||
local_d="$4"
|
||||
else
|
||||
local_d="$local_c"
|
||||
fi
|
||||
|
||||
rm -f tmp.zstd tmp.md5.1 tmp.md5.2
|
||||
$ECHO "fileRoundTripTest: ./datagen $1 $local_p > tmp && $ZSTD -v$local_c -c tmp | $ZSTD -d"
|
||||
$ECHO "fileRoundTripTest: ./datagen $1 $local_p > tmp && $ZSTD -v$local_c -c tmp | $ZSTD -d$local_d"
|
||||
./datagen $1 $local_p > tmp
|
||||
cat tmp | $MD5SUM > tmp.md5.1
|
||||
$ZSTD --ultra -v$local_c -c tmp | $ZSTD -d | $MD5SUM > tmp.md5.2
|
||||
< tmp $MD5SUM > tmp.md5.1
|
||||
$ZSTD --ultra -v$local_c -c tmp | $ZSTD -d$local_d | $MD5SUM > tmp.md5.2
|
||||
$DIFF -q tmp.md5.1 tmp.md5.2
|
||||
}
|
||||
|
||||
@@ -45,7 +55,6 @@ then
|
||||
fi
|
||||
|
||||
isWindows=false
|
||||
ECHO="echo -e"
|
||||
INTOVOID="/dev/null"
|
||||
case "$OS" in
|
||||
Windows*)
|
||||
@@ -66,6 +75,11 @@ case "$UNAME" in
|
||||
SunOS) DIFF="gdiff" ;;
|
||||
esac
|
||||
|
||||
ECHO="echo -e"
|
||||
case "$UNAME" in
|
||||
Darwin) ECHO="echo" ;;
|
||||
esac
|
||||
|
||||
$ECHO "\nStarting playTests.sh isWindows=$isWindows ZSTD='$ZSTD'"
|
||||
|
||||
[ -n "$ZSTD" ] || die "ZSTD variable must be defined!"
|
||||
@@ -584,7 +598,6 @@ $ECHO "\n**** zstd --list/-l single frame tests ****"
|
||||
./datagen > tmp1
|
||||
./datagen > tmp2
|
||||
./datagen > tmp3
|
||||
./datagen > tmp4
|
||||
$ZSTD tmp*
|
||||
$ZSTD -l *.zst
|
||||
$ZSTD -lv *.zst
|
||||
@@ -593,9 +606,7 @@ $ZSTD --list -v *.zst
|
||||
|
||||
$ECHO "\n**** zstd --list/-l multiple frame tests ****"
|
||||
cat tmp1.zst tmp2.zst > tmp12.zst
|
||||
cat tmp3.zst tmp4.zst > tmp34.zst
|
||||
cat tmp12.zst tmp34.zst > tmp1234.zst
|
||||
cat tmp12.zst tmp4.zst > tmp124.zst
|
||||
cat tmp12.zst tmp3.zst > tmp123.zst
|
||||
$ZSTD -l *.zst
|
||||
$ZSTD -lv *.zst
|
||||
$ZSTD --list *.zst
|
||||
@@ -605,7 +616,7 @@ $ECHO "\n**** zstd --list/-l error detection tests ****"
|
||||
! $ZSTD -l tmp1 tmp1.zst
|
||||
! $ZSTD --list tmp*
|
||||
! $ZSTD -lv tmp1*
|
||||
! $ZSTD --list -v tmp2 tmp23.zst
|
||||
! $ZSTD --list -v tmp2 tmp12.zst
|
||||
|
||||
$ECHO "\n**** zstd --list/-l test with null files ****"
|
||||
./datagen -g0 > tmp5
|
||||
@@ -628,57 +639,70 @@ $ZSTD -lv tmp1.zst
|
||||
rm tmp*
|
||||
|
||||
|
||||
$ECHO "\n**** zstd long distance matching tests **** "
|
||||
roundTripTest -g0 " --long"
|
||||
roundTripTest -g9M "2 --long"
|
||||
# Test parameter parsing
|
||||
roundTripTest -g1M -P50 "1 --long=29" " --memory=512MB"
|
||||
roundTripTest -g1M -P50 "1 --long=29 --zstd=wlog=28" " --memory=256MB"
|
||||
roundTripTest -g1M -P50 "1 --long=29" " --long=28 --memory=512MB"
|
||||
roundTripTest -g1M -P50 "1 --long=29" " --zstd=wlog=28 --memory=512MB"
|
||||
|
||||
|
||||
if [ "$1" != "--test-large-data" ]; then
|
||||
$ECHO "Skipping large data tests"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
$ECHO "\n**** large files tests **** "
|
||||
|
||||
roundTripTest -g270000000 1
|
||||
roundTripTest -g270000000 2
|
||||
roundTripTest -g270000000 3
|
||||
roundTripTest -g250000000 2
|
||||
roundTripTest -g230000000 3
|
||||
|
||||
roundTripTest -g140000000 -P60 4
|
||||
roundTripTest -g140000000 -P60 5
|
||||
roundTripTest -g140000000 -P60 6
|
||||
roundTripTest -g130000000 -P62 5
|
||||
roundTripTest -g120000000 -P65 6
|
||||
|
||||
roundTripTest -g70000000 -P70 7
|
||||
roundTripTest -g70000000 -P70 8
|
||||
roundTripTest -g70000000 -P70 9
|
||||
roundTripTest -g60000000 -P71 8
|
||||
roundTripTest -g50000000 -P73 9
|
||||
|
||||
roundTripTest -g35000000 -P75 10
|
||||
roundTripTest -g35000000 -P75 11
|
||||
roundTripTest -g35000000 -P75 12
|
||||
roundTripTest -g30000000 -P76 11
|
||||
roundTripTest -g25000000 -P78 12
|
||||
|
||||
roundTripTest -g18000013 -P80 13
|
||||
roundTripTest -g18000014 -P80 14
|
||||
roundTripTest -g18000015 -P80 15
|
||||
roundTripTest -g18000016 -P80 16
|
||||
roundTripTest -g18000017 -P80 17
|
||||
roundTripTest -g18000015 -P81 15
|
||||
roundTripTest -g18000016 -P84 16
|
||||
roundTripTest -g18000017 -P88 17
|
||||
roundTripTest -g18000018 -P94 18
|
||||
roundTripTest -g18000019 -P94 19
|
||||
roundTripTest -g18000019 -P96 19
|
||||
|
||||
roundTripTest -g68000020 -P99 20
|
||||
roundTripTest -g6000000000 -P99 1
|
||||
roundTripTest -g5000000000 -P99 1
|
||||
|
||||
fileRoundTripTest -g4193M -P99 1
|
||||
|
||||
|
||||
$ECHO "\n**** zstd long, long distance matching round-trip tests **** "
|
||||
roundTripTest -g0 "2 --long"
|
||||
roundTripTest -g270000000 "1 --long"
|
||||
roundTripTest -g140000000 -P60 "5 --long"
|
||||
roundTripTest -g70000000 -P70 "8 --long"
|
||||
roundTripTest -g130000000 -P60 "5 --long"
|
||||
roundTripTest -g35000000 -P70 "8 --long"
|
||||
roundTripTest -g18000001 -P80 "18 --long"
|
||||
fileRoundTripTest -g4100M -P99 "1 --long"
|
||||
# Test large window logs
|
||||
roundTripTest -g700M -P50 "1 --long=29"
|
||||
roundTripTest -g600M -P50 "1 --long --zstd=wlog=29,clog=28"
|
||||
|
||||
|
||||
if [ -n "$hasMT" ]
|
||||
then
|
||||
$ECHO "\n**** zstdmt long round-trip tests **** "
|
||||
roundTripTest -g99000000 -P99 "20 -T2"
|
||||
roundTripTest -g6000000000 -P99 "1 -T2"
|
||||
roundTripTest -g1500000000 -P97 "1 -T999"
|
||||
fileRoundTripTest -g4195M -P98 " -T0"
|
||||
roundTripTest -g1500000000 -P97 "1 --long -T999"
|
||||
roundTripTest -g80000000 -P99 "19 -T2" " "
|
||||
roundTripTest -g5000000000 -P99 "1 -T2" " "
|
||||
roundTripTest -g500000000 -P97 "1 -T999" " "
|
||||
fileRoundTripTest -g4103M -P98 " -T0" " "
|
||||
roundTripTest -g400000000 -P97 "1 --long=24 -T2" " "
|
||||
else
|
||||
$ECHO "\n**** no multithreading, skipping zstdmt tests **** "
|
||||
fi
|
||||
|
||||
+106
-105
@@ -96,6 +96,15 @@ unsigned int FUZ_rand(unsigned int* seedPtr)
|
||||
return rand32 >> 5;
|
||||
}
|
||||
|
||||
#define CHECK_Z(f) { \
|
||||
size_t const err = f; \
|
||||
if (ZSTD_isError(err)) { \
|
||||
DISPLAY("Error => %s : %s ", \
|
||||
#f, ZSTD_getErrorName(err)); \
|
||||
DISPLAY(" (seed %u, test nb %u) \n", seed, testNb); \
|
||||
goto _output_error; \
|
||||
} }
|
||||
|
||||
|
||||
/*======================================================
|
||||
* Basic Unit tests
|
||||
@@ -166,8 +175,8 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo
|
||||
RDG_genBuffer(CNBuffer, CNBufferSize, compressibility, 0., seed);
|
||||
|
||||
/* Create dictionary */
|
||||
MEM_STATIC_ASSERT(COMPRESSIBLE_NOISE_LENGTH >= 4 MB);
|
||||
dictionary = FUZ_createDictionary(CNBuffer, 4 MB, 4 KB, 40 KB);
|
||||
DISPLAYLEVEL(3, "creating dictionary for unit tests \n");
|
||||
dictionary = FUZ_createDictionary(CNBuffer, CNBufferSize / 2, 8 KB, 40 KB);
|
||||
if (!dictionary.start) {
|
||||
DISPLAY("Error creating dictionary, aborting \n");
|
||||
goto _output_error;
|
||||
@@ -181,16 +190,14 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo
|
||||
|
||||
/* Basic compression test */
|
||||
DISPLAYLEVEL(3, "test%3i : compress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
|
||||
{ size_t const r = ZSTD_initCStream_usingDict(zc, CNBuffer, dictSize, 1);
|
||||
if (ZSTD_isError(r)) goto _output_error; }
|
||||
CHECK_Z( ZSTD_initCStream_usingDict(zc, CNBuffer, dictSize, 1) );
|
||||
outBuff.dst = (char*)(compressedBuffer)+cSize;
|
||||
outBuff.size = compressedBufferSize;
|
||||
outBuff.pos = 0;
|
||||
inBuff.src = CNBuffer;
|
||||
inBuff.size = CNBufferSize;
|
||||
inBuff.pos = 0;
|
||||
{ size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff);
|
||||
if (ZSTD_isError(r)) goto _output_error; }
|
||||
CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
|
||||
if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
|
||||
{ size_t const r = ZSTD_endStream(zc, &outBuff);
|
||||
if (r != 0) goto _output_error; } /* error, or some data not flushed */
|
||||
@@ -200,11 +207,11 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo
|
||||
/* context size functions */
|
||||
DISPLAYLEVEL(3, "test%3i : estimate CStream size : ", testNb++);
|
||||
{ ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBufferSize, dictSize);
|
||||
size_t const s = ZSTD_estimateCStreamSize_advanced_usingCParams(cParams)
|
||||
/* uses ZSTD_initCStream_usingDict() */
|
||||
+ ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy);
|
||||
if (ZSTD_isError(s)) goto _output_error;
|
||||
DISPLAYLEVEL(3, "OK (%u bytes) \n", (U32)s);
|
||||
size_t const cstreamSize = ZSTD_estimateCStreamSize_usingCParams(cParams);
|
||||
size_t const cdictSize = ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy); /* uses ZSTD_initCStream_usingDict() */
|
||||
if (ZSTD_isError(cstreamSize)) goto _output_error;
|
||||
if (ZSTD_isError(cdictSize)) goto _output_error;
|
||||
DISPLAYLEVEL(3, "OK (%u bytes) \n", (U32)(cstreamSize + cdictSize));
|
||||
}
|
||||
|
||||
DISPLAYLEVEL(3, "test%3i : check actual CStream size : ", testNb++);
|
||||
@@ -225,8 +232,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo
|
||||
|
||||
/* skippable frame test */
|
||||
DISPLAYLEVEL(3, "test%3i : decompress skippable frame : ", testNb++);
|
||||
if (ZSTD_isError( ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize) ))
|
||||
goto _output_error;
|
||||
CHECK_Z( ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize) );
|
||||
inBuff.src = compressedBuffer;
|
||||
inBuff.size = cSize;
|
||||
inBuff.pos = 0;
|
||||
@@ -244,8 +250,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo
|
||||
inBuff2 = inBuff;
|
||||
DISPLAYLEVEL(3, "test%3i : decompress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
|
||||
ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
|
||||
{ size_t const r = ZSTD_setDStreamParameter(zd, DStream_p_maxWindowSize, 1000000000); /* large limit */
|
||||
if (ZSTD_isError(r)) goto _output_error; }
|
||||
CHECK_Z( ZSTD_setDStreamParameter(zd, DStream_p_maxWindowSize, 1000000000) ); /* large limit */
|
||||
{ size_t const remaining = ZSTD_decompressStream(zd, &outBuff, &inBuff);
|
||||
if (remaining != 0) goto _output_error; } /* should reach end of frame == 0; otherwise, some data left, or an error */
|
||||
if (outBuff.pos != CNBufferSize) goto _output_error; /* should regenerate the same amount */
|
||||
@@ -335,8 +340,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo
|
||||
inBuff.src = CNBuffer;
|
||||
inBuff.size = CNBufferSize;
|
||||
inBuff.pos = 0;
|
||||
{ size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff);
|
||||
if (ZSTD_isError(r)) goto _output_error; }
|
||||
CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
|
||||
if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
|
||||
{ size_t const r = ZSTD_endStream(zc, &outBuff);
|
||||
if (r != 0) goto _output_error; } /* error, or some data not flushed */
|
||||
@@ -353,8 +357,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo
|
||||
inBuff.src = CNBuffer;
|
||||
inBuff.size = CNBufferSize;
|
||||
inBuff.pos = 0;
|
||||
{ size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff);
|
||||
if (ZSTD_isError(r)) goto _output_error; }
|
||||
CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
|
||||
if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
|
||||
{ size_t const r = ZSTD_endStream(zc, &outBuff);
|
||||
if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error; /* must fail : wrong srcSize */
|
||||
@@ -376,8 +379,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo
|
||||
outBuff.size = ZSTD_compressBound(inSize);
|
||||
outBuff.pos = 0;
|
||||
DISPLAYLEVEL(5, "compress1 ");
|
||||
{ size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff);
|
||||
if (ZSTD_isError(r)) goto _output_error; }
|
||||
CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
|
||||
if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
|
||||
DISPLAYLEVEL(5, "end1 ");
|
||||
{ size_t const r = ZSTD_endStream(zc, &outBuff);
|
||||
@@ -394,8 +396,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo
|
||||
outBuff.size = ZSTD_compressBound(inSize);
|
||||
outBuff.pos = 0;
|
||||
DISPLAYLEVEL(5, "compress2 ");
|
||||
{ size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff);
|
||||
if (ZSTD_isError(r)) goto _output_error; }
|
||||
CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
|
||||
if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
|
||||
DISPLAYLEVEL(5, "end2 ");
|
||||
{ size_t const r = ZSTD_endStream(zc, &outBuff);
|
||||
@@ -415,8 +416,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo
|
||||
inBuff.src = CNBuffer;
|
||||
inBuff.size = CNBufferSize;
|
||||
inBuff.pos = 0;
|
||||
{ size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff);
|
||||
if (ZSTD_isError(r)) goto _output_error; }
|
||||
CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
|
||||
if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
|
||||
{ size_t const r = ZSTD_endStream(zc, &outBuff);
|
||||
if (r != 0) goto _output_error; } /* error, or some data not flushed */
|
||||
@@ -465,8 +465,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo
|
||||
/* Memory restriction */
|
||||
DISPLAYLEVEL(3, "test%3i : maxWindowSize < frame requirement : ", testNb++);
|
||||
ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
|
||||
{ size_t const r = ZSTD_setDStreamParameter(zd, DStream_p_maxWindowSize, 1000); /* too small limit */
|
||||
if (ZSTD_isError(r)) goto _output_error; }
|
||||
CHECK_Z( ZSTD_setDStreamParameter(zd, DStream_p_maxWindowSize, 1000) ); /* too small limit */
|
||||
inBuff.src = compressedBuffer;
|
||||
inBuff.size = cSize;
|
||||
inBuff.pos = 0;
|
||||
@@ -490,8 +489,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo
|
||||
inBuff.src = CNBuffer;
|
||||
inBuff.size = CNBufferSize;
|
||||
inBuff.pos = 0;
|
||||
{ size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff);
|
||||
if (ZSTD_isError(r)) goto _output_error; }
|
||||
CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
|
||||
if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
|
||||
{ size_t const r = ZSTD_endStream(zc, &outBuff);
|
||||
if (r != 0) goto _output_error; } /* error, or some data not flushed */
|
||||
@@ -513,16 +511,14 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo
|
||||
}
|
||||
|
||||
DISPLAYLEVEL(3, "test%3i : compress with ZSTD_CCtx_refPrefix : ", testNb++);
|
||||
{ size_t const refErr = ZSTD_CCtx_refPrefix(zc, dictionary.start, dictionary.filled);
|
||||
if (ZSTD_isError(refErr)) goto _output_error; }
|
||||
CHECK_Z( ZSTD_CCtx_refPrefix(zc, dictionary.start, dictionary.filled) );
|
||||
outBuff.dst = compressedBuffer;
|
||||
outBuff.size = compressedBufferSize;
|
||||
outBuff.pos = 0;
|
||||
inBuff.src = CNBuffer;
|
||||
inBuff.size = CNBufferSize;
|
||||
inBuff.pos = 0;
|
||||
{ size_t const r = ZSTD_compress_generic(zc, &outBuff, &inBuff, ZSTD_e_end);
|
||||
if (ZSTD_isError(r)) goto _output_error; }
|
||||
CHECK_Z( ZSTD_compress_generic(zc, &outBuff, &inBuff, ZSTD_e_end) );
|
||||
if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
|
||||
cSize = outBuff.pos;
|
||||
DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/CNBufferSize*100);
|
||||
@@ -549,23 +545,20 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo
|
||||
inBuff.src = CNBuffer;
|
||||
inBuff.size = CNBufferSize;
|
||||
inBuff.pos = 0;
|
||||
{ size_t const r = ZSTD_compress_generic(zc, &outBuff, &inBuff, ZSTD_e_end);
|
||||
if (ZSTD_isError(r)) goto _output_error; }
|
||||
CHECK_Z( ZSTD_compress_generic(zc, &outBuff, &inBuff, ZSTD_e_end) );
|
||||
if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
|
||||
cSize = outBuff.pos;
|
||||
DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/CNBufferSize*100);
|
||||
|
||||
DISPLAYLEVEL(3, "test%3i : decompress without dictionary (should work): ", testNb++);
|
||||
{ size_t const r = ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize);
|
||||
if (ZSTD_isError(r)) goto _output_error; /* must fail : dictionary not used */
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
}
|
||||
CHECK_Z( ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize) );
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
/* Empty srcSize */
|
||||
DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_advanced with pledgedSrcSize=0 and dict : ", testNb++);
|
||||
{ ZSTD_parameters params = ZSTD_getParams(5, 0, 0);
|
||||
params.fParams.contentSizeFlag = 1;
|
||||
ZSTD_initCStream_advanced(zc, dictionary.start, dictionary.filled, params, 0);
|
||||
CHECK_Z( ZSTD_initCStream_advanced(zc, dictionary.start, dictionary.filled, params, 0) );
|
||||
} /* cstream advanced shall write content size = 0 */
|
||||
inBuff.src = CNBuffer;
|
||||
inBuff.size = 0;
|
||||
@@ -573,7 +566,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo
|
||||
outBuff.dst = compressedBuffer;
|
||||
outBuff.size = compressedBufferSize;
|
||||
outBuff.pos = 0;
|
||||
if (ZSTD_isError(ZSTD_compressStream(zc, &outBuff, &inBuff))) goto _output_error;
|
||||
CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
|
||||
if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error;
|
||||
cSize = outBuff.pos;
|
||||
if (ZSTD_findDecompressedSize(compressedBuffer, cSize) != 0) goto _output_error;
|
||||
@@ -582,7 +575,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo
|
||||
DISPLAYLEVEL(3, "test%3i : pledgedSrcSize == 0 behaves properly : ", testNb++);
|
||||
{ ZSTD_parameters params = ZSTD_getParams(5, 0, 0);
|
||||
params.fParams.contentSizeFlag = 1;
|
||||
ZSTD_initCStream_advanced(zc, NULL, 0, params, 0);
|
||||
CHECK_Z( ZSTD_initCStream_advanced(zc, NULL, 0, params, 0) );
|
||||
} /* cstream advanced shall write content size = 0 */
|
||||
inBuff.src = CNBuffer;
|
||||
inBuff.size = 0;
|
||||
@@ -590,7 +583,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo
|
||||
outBuff.dst = compressedBuffer;
|
||||
outBuff.size = compressedBufferSize;
|
||||
outBuff.pos = 0;
|
||||
if (ZSTD_isError(ZSTD_compressStream(zc, &outBuff, &inBuff))) goto _output_error;
|
||||
CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
|
||||
if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error;
|
||||
cSize = outBuff.pos;
|
||||
if (ZSTD_findDecompressedSize(compressedBuffer, cSize) != 0) goto _output_error;
|
||||
@@ -602,7 +595,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo
|
||||
outBuff.dst = compressedBuffer;
|
||||
outBuff.size = compressedBufferSize;
|
||||
outBuff.pos = 0;
|
||||
if (ZSTD_isError(ZSTD_compressStream(zc, &outBuff, &inBuff))) goto _output_error;
|
||||
CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
|
||||
if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error;
|
||||
cSize = outBuff.pos;
|
||||
if (ZSTD_findDecompressedSize(compressedBuffer, cSize) != ZSTD_CONTENTSIZE_UNKNOWN) goto _output_error;
|
||||
@@ -610,17 +603,16 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo
|
||||
|
||||
/* Basic multithreading compression test */
|
||||
DISPLAYLEVEL(3, "test%3i : compress %u bytes with multiple threads : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
|
||||
{ ZSTD_parameters const params = ZSTD_getParams(1, 0, 0);
|
||||
size_t const r = ZSTDMT_initCStream_advanced(mtctx, CNBuffer, dictSize, params, CNBufferSize);
|
||||
if (ZSTD_isError(r)) goto _output_error; }
|
||||
{ ZSTD_parameters const params = ZSTD_getParams(1, 0, 0);
|
||||
CHECK_Z( ZSTDMT_initCStream_advanced(mtctx, CNBuffer, dictSize, params, CNBufferSize) );
|
||||
}
|
||||
outBuff.dst = (char*)(compressedBuffer);
|
||||
outBuff.size = compressedBufferSize;
|
||||
outBuff.pos = 0;
|
||||
inBuff.src = CNBuffer;
|
||||
inBuff.size = CNBufferSize;
|
||||
inBuff.pos = 0;
|
||||
{ size_t const r = ZSTDMT_compressStream_generic(mtctx, &outBuff, &inBuff, ZSTD_e_end);
|
||||
if (ZSTD_isError(r)) goto _output_error; }
|
||||
CHECK_Z( ZSTDMT_compressStream_generic(mtctx, &outBuff, &inBuff, ZSTD_e_end) );
|
||||
if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
|
||||
{ size_t const r = ZSTDMT_endStream(mtctx, &outBuff);
|
||||
if (r != 0) goto _output_error; } /* error, or some data not flushed */
|
||||
@@ -641,9 +633,10 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo
|
||||
"\x28\xB5\x2F\xFD\x04\x00\x4C\x00\x00\x10\x61\x61\x01\x00\x00\x2A"
|
||||
"\x80\x05\x44\x00\x00\x08\x62\x01\x00\x00\x2A\x20\x04\x5D\x00\x00"
|
||||
"\x00\x03\x40\x00\x00\x64\x60\x27\xB0\xE0\x0C\x67\x62\xCE\xE0";
|
||||
ZSTD_DStream* zds = ZSTD_createDStream();
|
||||
ZSTD_DStream* const zds = ZSTD_createDStream();
|
||||
if (zds==NULL) goto _output_error;
|
||||
|
||||
ZSTD_initDStream(zds);
|
||||
CHECK_Z( ZSTD_initDStream(zds) );
|
||||
inBuff.src = testCase;
|
||||
inBuff.size = 47;
|
||||
inBuff.pos = 0;
|
||||
@@ -652,9 +645,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo
|
||||
outBuff.pos = 0;
|
||||
|
||||
while (inBuff.pos < inBuff.size) {
|
||||
size_t const r = ZSTD_decompressStream(zds, &outBuff, &inBuff);
|
||||
/* Bug will cause checksum to fail */
|
||||
if (ZSTD_isError(r)) goto _output_error;
|
||||
CHECK_Z( ZSTD_decompressStream(zds, &outBuff, &inBuff) );
|
||||
}
|
||||
|
||||
ZSTD_freeDStream(zds);
|
||||
@@ -725,35 +716,26 @@ static U32 FUZ_randomClampedLength(U32* seed, U32 minVal, U32 maxVal)
|
||||
goto _output_error; \
|
||||
} }
|
||||
|
||||
#define CHECK_Z(f) { \
|
||||
size_t const err = f; \
|
||||
if (ZSTD_isError(err)) { \
|
||||
DISPLAY("Error => %s : %s ", \
|
||||
#f, ZSTD_getErrorName(err)); \
|
||||
DISPLAY(" (seed %u, test nb %u) \n", seed, testNb); \
|
||||
goto _output_error; \
|
||||
} }
|
||||
|
||||
static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibility, int bigTests)
|
||||
{
|
||||
U32 const maxSrcLog = bigTests ? 24 : 22;
|
||||
static const U32 maxSampleLog = 19;
|
||||
size_t const srcBufferSize = (size_t)1<<maxSrcLog;
|
||||
BYTE* cNoiseBuffer[5];
|
||||
size_t const copyBufferSize= srcBufferSize + (1<<maxSampleLog);
|
||||
size_t const copyBufferSize = srcBufferSize + (1<<maxSampleLog);
|
||||
BYTE* const copyBuffer = (BYTE*)malloc (copyBufferSize);
|
||||
size_t const cBufferSize = ZSTD_compressBound(srcBufferSize);
|
||||
size_t const cBufferSize = ZSTD_compressBound(srcBufferSize);
|
||||
BYTE* const cBuffer = (BYTE*)malloc (cBufferSize);
|
||||
size_t const dstBufferSize = srcBufferSize;
|
||||
BYTE* const dstBuffer = (BYTE*)malloc (dstBufferSize);
|
||||
U32 result = 0;
|
||||
U32 testNb = 0;
|
||||
U32 coreSeed = seed;
|
||||
ZSTD_CStream* zc = ZSTD_createCStream(); /* will be reset sometimes */
|
||||
ZSTD_DStream* zd = ZSTD_createDStream(); /* will be reset sometimes */
|
||||
ZSTD_CStream* zc = ZSTD_createCStream(); /* will be re-created sometimes */
|
||||
ZSTD_DStream* zd = ZSTD_createDStream(); /* will be re-created sometimes */
|
||||
ZSTD_DStream* const zd_noise = ZSTD_createDStream();
|
||||
clock_t const startClock = clock();
|
||||
const BYTE* dict=NULL; /* can keep same dict on 2 consecutive tests */
|
||||
const BYTE* dict = NULL; /* can keep same dict on 2 consecutive tests */
|
||||
size_t dictSize = 0;
|
||||
U32 oldTestLog = 0;
|
||||
U32 const cLevelMax = bigTests ? (U32)ZSTD_maxCLevel() : g_cLevelMax_smallTests;
|
||||
@@ -831,8 +813,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compres
|
||||
if ((FUZ_rand(&lseed)&1) /* at beginning, to keep same nb of rand */
|
||||
&& oldTestLog /* at least one test happened */ && resetAllowed) {
|
||||
maxTestSize = FUZ_randomLength(&lseed, oldTestLog+2);
|
||||
if (maxTestSize >= srcBufferSize)
|
||||
maxTestSize = srcBufferSize-1;
|
||||
maxTestSize = MIN(maxTestSize, srcBufferSize-16);
|
||||
{ U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? 0 : maxTestSize;
|
||||
CHECK_Z( ZSTD_resetCStream(zc, pledgedSrcSize) );
|
||||
}
|
||||
@@ -914,7 +895,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compres
|
||||
size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
|
||||
size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize);
|
||||
inBuff.size = inBuff.pos + readCSrcSize;
|
||||
outBuff.size = inBuff.pos + dstBuffSize;
|
||||
outBuff.size = outBuff.pos + dstBuffSize;
|
||||
decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff);
|
||||
if (ZSTD_getErrorCode(decompressionResult) == ZSTD_error_checksum_wrong) {
|
||||
DISPLAY("checksum error : \n");
|
||||
@@ -998,15 +979,16 @@ static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double comp
|
||||
U32 result = 0;
|
||||
U32 testNb = 0;
|
||||
U32 coreSeed = seed;
|
||||
ZSTDMT_CCtx* zc = ZSTDMT_createCCtx(2); /* will be reset sometimes */
|
||||
U32 nbThreads = 2;
|
||||
ZSTDMT_CCtx* zc = ZSTDMT_createCCtx(nbThreads); /* will be reset sometimes */
|
||||
ZSTD_DStream* zd = ZSTD_createDStream(); /* will be reset sometimes */
|
||||
ZSTD_DStream* const zd_noise = ZSTD_createDStream();
|
||||
clock_t const startClock = clock();
|
||||
const BYTE* dict=NULL; /* can keep same dict on 2 consecutive tests */
|
||||
size_t dictSize = 0;
|
||||
U32 oldTestLog = 0;
|
||||
U32 const cLevelMax = bigTests ? (U32)ZSTD_maxCLevel() : g_cLevelMax_smallTests;
|
||||
U32 const nbThreadsMax = bigTests ? 5 : 2;
|
||||
int const cLevelMax = bigTests ? (U32)ZSTD_maxCLevel()-1 : g_cLevelMax_smallTests;
|
||||
U32 const nbThreadsMax = bigTests ? 4 : 2;
|
||||
|
||||
/* allocations */
|
||||
cNoiseBuffer[0] = (BYTE*)malloc (srcBufferSize);
|
||||
@@ -1042,16 +1024,16 @@ static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double comp
|
||||
size_t maxTestSize;
|
||||
|
||||
/* init */
|
||||
if (nbTests >= testNb) { DISPLAYUPDATE(2, "\r%6u/%6u ", testNb, nbTests); }
|
||||
else { DISPLAYUPDATE(2, "\r%6u ", testNb); }
|
||||
if (testNb < nbTests) {
|
||||
DISPLAYUPDATE(2, "\r%6u/%6u ", testNb, nbTests);
|
||||
} else { DISPLAYUPDATE(2, "\r%6u ", testNb); }
|
||||
FUZ_rand(&coreSeed);
|
||||
lseed = coreSeed ^ prime32;
|
||||
|
||||
/* states full reset (deliberately not synchronized) */
|
||||
/* some issues can only happen when reusing states */
|
||||
if ((FUZ_rand(&lseed) & 0xFF) == 131) {
|
||||
U32 const nbThreadsCandidate = (FUZ_rand(&lseed) % 6) + 1;
|
||||
U32 const nbThreads = MIN(nbThreadsCandidate, nbThreadsMax);
|
||||
nbThreads = (FUZ_rand(&lseed) % nbThreadsMax) + 1;
|
||||
DISPLAYLEVEL(5, "Creating new context with %u threads \n", nbThreads);
|
||||
ZSTDMT_freeCCtx(zc);
|
||||
zc = ZSTDMT_createCCtx(nbThreads);
|
||||
@@ -1091,11 +1073,12 @@ static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double comp
|
||||
} else {
|
||||
U32 const testLog = FUZ_rand(&lseed) % maxSrcLog;
|
||||
U32 const dictLog = FUZ_rand(&lseed) % maxSrcLog;
|
||||
U32 const cLevelCandidate = (FUZ_rand(&lseed) %
|
||||
(ZSTD_maxCLevel() -
|
||||
(MAX(testLog, dictLog) / 3))) +
|
||||
1;
|
||||
U32 const cLevel = MIN(cLevelCandidate, cLevelMax);
|
||||
int const cLevelCandidate = ( FUZ_rand(&lseed)
|
||||
% (ZSTD_maxCLevel() - (MAX(testLog, dictLog) / 2)) )
|
||||
+ 1;
|
||||
int const cLevelThreadAdjusted = cLevelCandidate - (nbThreads * 2) + 2; /* reduce cLevel when multiple threads to reduce memory consumption */
|
||||
int const cLevelMin = MAX(cLevelThreadAdjusted, 1); /* no negative cLevel yet */
|
||||
int const cLevel = MIN(cLevelMin, cLevelMax);
|
||||
maxTestSize = FUZ_rLogLength(&lseed, testLog);
|
||||
oldTestLog = testLog;
|
||||
/* random dictionary selection */
|
||||
@@ -1178,7 +1161,7 @@ static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double comp
|
||||
size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
|
||||
size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize);
|
||||
inBuff.size = inBuff.pos + readCSrcSize;
|
||||
outBuff.size = inBuff.pos + dstBuffSize;
|
||||
outBuff.size = outBuff.pos + dstBuffSize;
|
||||
DISPLAYLEVEL(5, "ZSTD_decompressStream input %u bytes \n", (U32)readCSrcSize);
|
||||
decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff);
|
||||
CHECK (ZSTD_isError(decompressionResult), "decompression error : %s", ZSTD_getErrorName(decompressionResult));
|
||||
@@ -1276,8 +1259,9 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
|
||||
const BYTE* dict = NULL; /* can keep same dict on 2 consecutive tests */
|
||||
size_t dictSize = 0;
|
||||
U32 oldTestLog = 0;
|
||||
U32 const cLevelMax = bigTests ? (U32)ZSTD_maxCLevel() : g_cLevelMax_smallTests;
|
||||
U32 const nbThreadsMax = bigTests ? 5 : 1;
|
||||
U32 windowLogMalus = 0; /* can survive between 2 loops */
|
||||
U32 const cLevelMax = bigTests ? (U32)ZSTD_maxCLevel()-1 : g_cLevelMax_smallTests;
|
||||
U32 const nbThreadsMax = bigTests ? 4 : 2;
|
||||
ZSTD_CCtx_params* cctxParams = ZSTD_createCCtxParams();
|
||||
|
||||
/* allocations */
|
||||
@@ -1318,6 +1302,7 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
|
||||
else { DISPLAYUPDATE(2, "\r%6u ", testNb); }
|
||||
FUZ_rand(&coreSeed);
|
||||
lseed = coreSeed ^ prime32;
|
||||
DISPLAYLEVEL(5, " *** Test %u *** \n", testNb);
|
||||
|
||||
/* states full reset (deliberately not synchronized) */
|
||||
/* some issues can only happen when reusing states */
|
||||
@@ -1364,10 +1349,12 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
|
||||
U32 const dictLog = FUZ_rand(&lseed) % maxSrcLog;
|
||||
U32 const cLevelCandidate = (FUZ_rand(&lseed) %
|
||||
(ZSTD_maxCLevel() -
|
||||
(MAX(testLog, dictLog) / 3))) +
|
||||
(MAX(testLog, dictLog) / 2))) +
|
||||
1;
|
||||
U32 const cLevel = MIN(cLevelCandidate, cLevelMax);
|
||||
DISPLAYLEVEL(5, "t%u: cLevel : %u \n", testNb, cLevel);
|
||||
maxTestSize = FUZ_rLogLength(&lseed, testLog);
|
||||
DISPLAYLEVEL(5, "t%u: maxTestSize : %u \n", testNb, (U32)maxTestSize);
|
||||
oldTestLog = testLog;
|
||||
/* random dictionary selection */
|
||||
dictSize = ((FUZ_rand(&lseed)&63)==1) ? FUZ_rLogLength(&lseed, dictLog) : 0;
|
||||
@@ -1377,19 +1364,32 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
|
||||
}
|
||||
{ U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? ZSTD_CONTENTSIZE_UNKNOWN : maxTestSize;
|
||||
ZSTD_compressionParameters cParams = ZSTD_getCParams(cLevel, pledgedSrcSize, dictSize);
|
||||
static const U32 windowLogMax = 24;
|
||||
|
||||
/* mess with compression parameters */
|
||||
cParams.windowLog += (FUZ_rand(&lseed) & 3) - 1;
|
||||
cParams.windowLog = MIN(windowLogMax, cParams.windowLog);
|
||||
cParams.hashLog += (FUZ_rand(&lseed) & 3) - 1;
|
||||
cParams.chainLog += (FUZ_rand(&lseed) & 3) - 1;
|
||||
cParams.searchLog += (FUZ_rand(&lseed) & 3) - 1;
|
||||
cParams.searchLength += (FUZ_rand(&lseed) & 3) - 1;
|
||||
cParams.targetLength = (U32)(cParams.targetLength * (0.5 + ((double)(FUZ_rand(&lseed) & 127) / 128)));
|
||||
cParams.targetLength = (U32)((cParams.targetLength + 1 ) * (0.5 + ((double)(FUZ_rand(&lseed) & 127) / 128)));
|
||||
cParams = ZSTD_adjustCParams(cParams, 0, 0);
|
||||
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_windowLog, cParams.windowLog, useOpaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_hashLog, cParams.hashLog, useOpaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_chainLog, cParams.chainLog, useOpaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 1) {
|
||||
CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_windowLog, cParams.windowLog, useOpaqueAPI) );
|
||||
assert(cParams.windowLog >= ZSTD_WINDOWLOG_MIN); /* guaranteed by ZSTD_adjustCParams() */
|
||||
windowLogMalus = (cParams.windowLog - ZSTD_WINDOWLOG_MIN) / 5;
|
||||
DISPLAYLEVEL(5, "t%u: windowLog : %u \n", testNb, cParams.windowLog);
|
||||
}
|
||||
if (FUZ_rand(&lseed) & 1) {
|
||||
CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_hashLog, cParams.hashLog, useOpaqueAPI) );
|
||||
DISPLAYLEVEL(5, "t%u: hashLog : %u \n", testNb, cParams.hashLog);
|
||||
}
|
||||
if (FUZ_rand(&lseed) & 1) {
|
||||
CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_chainLog, cParams.chainLog, useOpaqueAPI) );
|
||||
DISPLAYLEVEL(5, "t%u: chainLog : %u \n", testNb, cParams.chainLog);
|
||||
}
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_searchLog, cParams.searchLog, useOpaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_minMatch, cParams.searchLength, useOpaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_targetLength, cParams.targetLength, useOpaqueAPI) );
|
||||
@@ -1401,18 +1401,19 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
|
||||
if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmBucketSizeLog, FUZ_randomClampedLength(&lseed, 0, ZSTD_LDM_BUCKETSIZELOG_MAX), useOpaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmHashEveryLog, FUZ_randomClampedLength(&lseed, 0, ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN), useOpaqueAPI) );
|
||||
|
||||
/* unconditionally set, to be sync with decoder */
|
||||
/* mess with frame parameters */
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_checksumFlag, FUZ_rand(&lseed) & 1, useOpaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_dictIDFlag, FUZ_rand(&lseed) & 1, useOpaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_contentSizeFlag, FUZ_rand(&lseed) & 1, useOpaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, pledgedSrcSize) );
|
||||
DISPLAYLEVEL(5, "pledgedSrcSize : %u \n", (U32)pledgedSrcSize);
|
||||
DISPLAYLEVEL(5, "t%u: pledgedSrcSize : %u \n", testNb, (U32)pledgedSrcSize);
|
||||
|
||||
/* multi-threading parameters */
|
||||
{ U32 const nbThreadsCandidate = (FUZ_rand(&lseed) & 4) + 1;
|
||||
U32 const nbThreads = MIN(nbThreadsCandidate, nbThreadsMax);
|
||||
U32 const nbThreadsAdjusted = (windowLogMalus < nbThreadsCandidate) ? nbThreadsCandidate - windowLogMalus : 1;
|
||||
U32 const nbThreads = MIN(nbThreadsAdjusted, nbThreadsMax);
|
||||
CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_nbThreads, nbThreads, useOpaqueAPI) );
|
||||
DISPLAYLEVEL(5, "t%u: nbThreads : %u \n", testNb, nbThreads);
|
||||
if (nbThreads > 1) {
|
||||
U32 const jobLog = FUZ_rand(&lseed) % (testLog+1);
|
||||
CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_overlapSizeLog, FUZ_rand(&lseed) % 10, useOpaqueAPI) );
|
||||
@@ -1463,7 +1464,7 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
|
||||
outBuff.size = outBuff.pos + dstBuffSize;
|
||||
|
||||
CHECK_Z( ZSTD_compress_generic(zc, &outBuff, &inBuff, flush) );
|
||||
DISPLAYLEVEL(5, "compress consumed %u bytes (total : %u) \n",
|
||||
DISPLAYLEVEL(6, "compress consumed %u bytes (total : %u) \n",
|
||||
(U32)inBuff.pos, (U32)(totalTestSize + inBuff.pos));
|
||||
|
||||
XXH64_update(&xxhState, srcBuffer+srcStart, inBuff.pos);
|
||||
@@ -1478,11 +1479,11 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
|
||||
size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog+1);
|
||||
size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
|
||||
outBuff.size = outBuff.pos + adjustedDstSize;
|
||||
DISPLAYLEVEL(5, "End-flush into dst buffer of size %u \n", (U32)adjustedDstSize);
|
||||
DISPLAYLEVEL(6, "End-flush into dst buffer of size %u \n", (U32)adjustedDstSize);
|
||||
remainingToFlush = ZSTD_compress_generic(zc, &outBuff, &inBuff, ZSTD_e_end);
|
||||
CHECK(ZSTD_isError(remainingToFlush),
|
||||
"ZSTD_compress_generic w/ ZSTD_e_end error : %s",
|
||||
ZSTD_getErrorName(remainingToFlush) );
|
||||
CHECK( ZSTD_isError(remainingToFlush),
|
||||
"ZSTD_compress_generic w/ ZSTD_e_end error : %s",
|
||||
ZSTD_getErrorName(remainingToFlush) );
|
||||
} }
|
||||
crcOrig = XXH64_digest(&xxhState);
|
||||
cSize = outBuff.pos;
|
||||
@@ -1505,12 +1506,12 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
|
||||
size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
|
||||
size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize);
|
||||
inBuff.size = inBuff.pos + readCSrcSize;
|
||||
outBuff.size = inBuff.pos + dstBuffSize;
|
||||
DISPLAYLEVEL(5, "ZSTD_decompressStream input %u bytes (pos:%u/%u)\n",
|
||||
outBuff.size = outBuff.pos + dstBuffSize;
|
||||
DISPLAYLEVEL(6, "ZSTD_decompressStream input %u bytes (pos:%u/%u)\n",
|
||||
(U32)readCSrcSize, (U32)inBuff.pos, (U32)cSize);
|
||||
decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff);
|
||||
CHECK (ZSTD_isError(decompressionResult), "decompression error : %s", ZSTD_getErrorName(decompressionResult));
|
||||
DISPLAYLEVEL(5, "inBuff.pos = %u \n", (U32)readCSrcSize);
|
||||
DISPLAYLEVEL(6, "inBuff.pos = %u \n", (U32)readCSrcSize);
|
||||
}
|
||||
CHECK (outBuff.pos != totalTestSize, "decompressed data : wrong size (%u != %u)", (U32)outBuff.pos, (U32)totalTestSize);
|
||||
CHECK (inBuff.pos != cSize, "compressed data should be fully read (%u != %u)", (U32)inBuff.pos, (U32)cSize);
|
||||
@@ -1614,9 +1615,9 @@ int main(int argc, const char** argv)
|
||||
/* Parsing commands. Aggregated commands are allowed */
|
||||
if (argument[0]=='-') {
|
||||
|
||||
if (!strcmp(argument, "--mt")) { selected_api=mt_api; continue; }
|
||||
if (!strcmp(argument, "--newapi")) { selected_api=advanced_api; continue; }
|
||||
if (!strcmp(argument, "--opaqueapi")) { selected_api=advanced_api; useOpaqueAPI = 1; continue; }
|
||||
if (!strcmp(argument, "--mt")) { selected_api=mt_api; testNb += !testNb; continue; }
|
||||
if (!strcmp(argument, "--newapi")) { selected_api=advanced_api; testNb += !testNb; continue; }
|
||||
if (!strcmp(argument, "--opaqueapi")) { selected_api=advanced_api; testNb += !testNb; useOpaqueAPI = 1; continue; }
|
||||
if (!strcmp(argument, "--no-big-tests")) { bigTests=0; continue; }
|
||||
|
||||
argument++;
|
||||
|
||||
Reference in New Issue
Block a user